forked from openhab/openhab-addons
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This will should be merged after I have created a separate package for the helper libraries, as discussed here... openhab#7208 (comment). For now, this was built to test using the helper libraries as a separate bundle. Signed-off-by: Scott Rushworth <openhab@5iver.com>
- Loading branch information
Scott Rushworth
committed
Mar 25, 2020
1 parent
602b0ab
commit 5b34677
Showing
38 changed files
with
3,948 additions
and
171 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
File renamed without changes.
3 changes: 3 additions & 0 deletions
3
bundles/org.openhab.automation.helperlibraries.jython/README.md
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Jython Helper Libraries | ||
|
||
This addon provides helper libraries for use with Jython and scripted automation. |
3 changes: 3 additions & 0 deletions
3
bundles/org.openhab.automation.helperlibraries.jython/bnd.bnd
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Bundle-SymbolicName: ${project.artifactId} | ||
DynamicImport-Package: * | ||
-includeresource.resources: -src/main/resources |
24 changes: 24 additions & 0 deletions
24
bundles/org.openhab.automation.helperlibraries.jython/pom.xml
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
|
||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>org.openhab.addons.bundles</groupId> | ||
<artifactId>org.openhab.addons.reactor.bundles</artifactId> | ||
<version>2.5.4-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>org.openhab.automation.helperlibraries.jython</artifactId> | ||
|
||
<name>openHAB Add-ons :: Automation :: Jython Helper Libraries</name> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.openhab.core.bundles</groupId> | ||
<artifactId>org.openhab.core.automation.module.script</artifactId> | ||
<version>2.5.0</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
</dependencies> | ||
</project> |
6 changes: 3 additions & 3 deletions
6
...ctory.jython/src/main/feature/feature.xml → ...aries.jython/src/main/feature/feature.xml
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<features name="org.openhab.automation.scriptenginefactory.jython-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0"> | ||
<features name="org.openhab.automation.helperlibraries.jython-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0"> | ||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/2.5.0/xml/features</repository> | ||
|
||
<feature name="openhab-scriptenginefactory-jython" description="Jython ScriptEngineFactory" version="${project.version}"> | ||
<feature name="openhab-helperlibraries-jython" description="Jython Helper Libraries" version="${project.version}"> | ||
<feature>openhab-runtime-base</feature> | ||
<feature>openhab-core-automation</feature> | ||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.automation.scriptenginefactory.jython/${project.version}</bundle> | ||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.automation.helperlibraries.jython/${project.version}</bundle> | ||
</feature> | ||
</features> |
81 changes: 81 additions & 0 deletions
81
...in/java/org/openhab/automation/helperlibraries/jython/internal/JythonHelperLibraries.java
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/** | ||
* Copyright (c) 2010-2019 Contributors to the openHAB project | ||
* | ||
* See the NOTICE file(s) distributed with this work for additional | ||
* information. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0 | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*/ | ||
package org.openhab.automation.helperlibraries.jython.internal; | ||
|
||
import java.io.File; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.TreeSet; | ||
|
||
import org.eclipse.jdt.annotation.NonNullByDefault; | ||
import org.osgi.service.component.annotations.Activate; | ||
import org.osgi.service.component.annotations.Component; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
/** | ||
* These helper libraries aid in the use of Jython within scripted automation. | ||
* | ||
* @author Scott Rushworth - Initial contribution | ||
*/ | ||
@Component(service = JythonHelperLibraries.class) | ||
@NonNullByDefault | ||
public class JythonHelperLibraries { | ||
|
||
protected final Logger logger = LoggerFactory.getLogger(getClass()); | ||
private static final String HELPER_LIBRARY_PYTHON_PATH = new StringBuilder(JythonHelperLibraries.class | ||
.getProtectionDomain().getCodeSource().getLocation().toString().replace("file:", "")).toString(); | ||
|
||
@Activate | ||
public JythonHelperLibraries() { | ||
logger.debug("Loading Jython helper libraries"); | ||
String existingPythonPath = System.getProperty("python.path"); | ||
// logger.warn("existingPythonPath: '{}'", existingPythonPath); | ||
if (existingPythonPath == null || existingPythonPath.isEmpty()) { | ||
System.setProperty("python.path", HELPER_LIBRARY_PYTHON_PATH); | ||
} else if (!existingPythonPath.contains(HELPER_LIBRARY_PYTHON_PATH)) { | ||
TreeSet<String> newPythonPathList = new TreeSet<>( | ||
new ArrayList<String>(Arrays.asList(existingPythonPath.split(File.pathSeparator)))); | ||
// logger.warn("Before addition: '{}'", newPythonPathList); | ||
newPythonPathList.add(HELPER_LIBRARY_PYTHON_PATH); | ||
// logger.warn("After addition: '{}'", newPythonPathList); | ||
String newPythonPath = String.join(File.pathSeparator, newPythonPathList); | ||
// logger.warn("String: '{}'", newPythonPath); | ||
System.setProperty("python.path", newPythonPath); | ||
} | ||
|
||
logger.trace("python.home [{}], python.path [{}]", System.getProperty("python.home"), | ||
System.getProperty("python.path")); | ||
} | ||
|
||
// This does not work properly, since Deactivate() is called immediately after Activate() due to there being no | ||
// dependencies on the service. | ||
// @Deactivate | ||
// public void deactivate() { | ||
// logger.debug("Unloading Jython helper libraries"); | ||
// String existingPythonPath = System.getProperty("python.path"); | ||
// //logger.warn("existingPythonPath: '{}'", existingPythonPath); | ||
// if (existingPythonPath.contains(HELPER_LIBRARY_PYTHON_PATH)) { | ||
// TreeSet<String> newPythonPathList = new TreeSet<>( | ||
// new ArrayList<String>(Arrays.asList(existingPythonPath.split(File.pathSeparator)))); | ||
// //logger.warn("Before removal: '{}'", newPythonPathList); | ||
// newPythonPathList.remove(HELPER_LIBRARY_PYTHON_PATH); | ||
// //logger.warn("After removal: '{}'", newPythonPathList); | ||
// String newPythonPath = String.join(File.pathSeparator, newPythonPathList); | ||
// //logger.warn("String: '{}'", newPythonPath); | ||
// System.setProperty("python.path", newPythonPath); | ||
// } | ||
// logger.trace("python.home [{}], python.path [{}], python.cachdir [{}]", System.getProperty("python.home"), | ||
// System.getProperty("python.path"), System.getProperty("python.cachedir")); | ||
// } | ||
} |
1 change: 1 addition & 0 deletions
1
...es/org.openhab.automation.helperlibraries.jython/src/main/resources/community/__init__.py
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
|
78 changes: 78 additions & 0 deletions
78
...helperlibraries.jython/src/main/resources/community/area_triggers_and_actions/__init__.py
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
""" | ||
The ``area_triggers_and_actions`` package provides a mechanism for using group | ||
logic to trigger rules and then perform a particular action. | ||
This package provides the following modules: | ||
* ``area_actions`` | ||
""" | ||
__all__ = ['start_action', 'stop_timer'] | ||
|
||
from threading import Timer | ||
|
||
from core.jsr223.scope import ON, OFF, OPEN, CLOSED | ||
from core.metadata import get_key_value | ||
from core.log import logging, LOG_PREFIX, log_traceback | ||
|
||
from community.area_triggers_and_actions.area_actions import * | ||
|
||
try: | ||
import sys | ||
import personal.area_triggers_and_actions.area_actions | ||
reload(sys.modules['personal.area_triggers_and_actions.area_actions']) | ||
from personal.area_triggers_and_actions.area_actions import * | ||
except: | ||
pass | ||
|
||
#from org.joda.time import DateTime | ||
|
||
log = logging.getLogger("{}.community.area_triggers_and_actions".format(LOG_PREFIX)) | ||
|
||
timer_dict = {} | ||
|
||
@log_traceback | ||
def _timer_function(item, active, function_name, timer_type, timer_delay, recurring, function): | ||
"""This is the function called by the timers.""" | ||
#log.warn("_timer_function: item.name [{}], active [{}], function_name [{}], timer_type [{}], timer_delay [{}], recurring [{}], function [{}]".format(item.name, active, function_name, timer_type, timer_delay, recurring, function)) | ||
function(item, active) | ||
log.debug("{}: [{}] second {} {} timer has completed".format(item.name, timer_delay, function_name, timer_type)) | ||
if recurring and item.state in [ON, OPEN] if active else item.state in [OFF, CLOSED]: | ||
timer_dict.update({item.name: {function_name: {timer_type: Timer(timer_delay, _timer_function, [item, active, function_name, timer_type, timer_delay, recurring, function])}}}) | ||
timer_dict[item.name][function_name][timer_type].start() | ||
log.debug("{}: [{}] second recurring {} {} timer has started".format(item.name, timer_delay, function_name, timer_type)) | ||
|
||
def start_action(item, active, function_name): | ||
""" | ||
This is the function called by the rule to begin the selected action, | ||
which may be first passed through a timer. | ||
Args: | ||
item Item: The Item to perform the action on | ||
active boolean: Area activity (True for active and False for inactive) | ||
function_name string: Name of the action function | ||
""" | ||
#start_time = DateTime.now().getMillis() | ||
timer_type = "ON" if active else "OFF" | ||
function = globals()[function_name] | ||
function_metadata = get_key_value(item.name, "area_triggers_and_actions", "actions", function_name) | ||
limited = function_metadata.get("limited") | ||
timer_metadata = function_metadata.get(timer_type, {}) | ||
if not limited or timer_metadata: | ||
timer_delay = timer_metadata.get("delay") | ||
recurring = timer_metadata.get("recurring") | ||
#log.warn("start_action: item.name [{}], active [{}], function_name [{}], timer_type [{}], timer_delay [{}], recurring [{}], function [{}]".format(item.name, active, function_name, timer_type, timer_delay, recurring, function)) | ||
if not timer_delay: | ||
function(item, active) | ||
elif timer_dict.get(item.name, {}).get(function_name, {}).get(timer_type) is None or not timer_dict[item.name][function_name][timer_type].isAlive():# if timer does not exist, create it | ||
timer_dict.update({item.name: {function_name: {timer_type: Timer(timer_delay, _timer_function, [item, active, function_name, timer_type, timer_delay, recurring, function])}}}) | ||
timer_dict[item.name][function_name][timer_type].start() | ||
log.debug("{}: [{}] second {}{} {} timer has started".format(item.name, timer_delay, "recurring " if recurring else "", function_name, timer_type)) | ||
stop_timer(item.name, function_name, "OFF" if active else "ON") | ||
#log.warn("Test: start_action: {}: [{}]: time=[{}]".format(item.name, timer_type, DateTime.now().getMillis() - start_time)) | ||
|
||
def stop_timer(item_name, function_name, timer_type): | ||
"""This function stops the timer.""" | ||
#log.warn("stop_timer: function_name [{}], timer_type [{}], item_name [{}]".format(function_name, timer_type, item_name)) | ||
if timer_dict.get(item_name, {}).get(function_name, {}).get(timer_type) is not None and timer_dict[item_name][function_name][timer_type].isAlive():# if timer exists, stop it | ||
timer_dict[item_name][function_name][timer_type].cancel() | ||
log.debug("{}: {} {} timer has been cancelled".format(item_name, function_name, timer_type)) |
105 changes: 105 additions & 0 deletions
105
...erlibraries.jython/src/main/resources/community/area_triggers_and_actions/area_actions.py
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
""" | ||
The ``area_actions`` module contains the ``light_action`` and | ||
``toggle_action`` functions that should be useable by everyone without | ||
customization. Custom actions should not be put into this file, as they could | ||
be overwritten during an upgrade. Instead, place them in the | ||
``personal.area_triggers_and_actions.area_actions`` module. | ||
""" | ||
__all__ = ['light_action', 'toggle_action'] | ||
|
||
from core.jsr223.scope import events, items, PercentType, DecimalType, HSBType, ON, OFF | ||
from core.metadata import get_key_value | ||
from core.log import logging, LOG_PREFIX | ||
|
||
import configuration | ||
reload(configuration) | ||
from configuration import area_triggers_and_actions_dict | ||
|
||
#from org.joda.time import DateTime | ||
|
||
log = logging.getLogger("{}.community.area_triggers_and_actions.area_actions".format(LOG_PREFIX)) | ||
|
||
def light_action(item, active): | ||
""" | ||
This function performs an action on a light Item. | ||
When called, this function pulls in the metadata for the supplied Item or | ||
uses the default values specified in | ||
``configuration.area_triggers_and_actions_dict"["default_levels"]``, if the | ||
metadata does not exist. This metadata is then compared to the current lux | ||
level to determine if a light should be turned OFF or set to the specified | ||
level. This function should work for everyone without modification. | ||
Args: | ||
Item item: The Item to perform the action on | ||
boolean active: Area activity (True for active and False for inactive) | ||
""" | ||
#start_time = DateTime.now().getMillis() | ||
item_metadata = get_key_value(item.name, "area_triggers_and_actions", "modes", str(items["Mode"])) | ||
low_lux_trigger = item_metadata.get("low_lux_trigger", area_triggers_and_actions_dict["default_levels"]["low_lux_trigger"]) | ||
hue = DecimalType(item_metadata.get("hue", area_triggers_and_actions_dict["default_levels"]["hue"])) | ||
saturation = PercentType(str(item_metadata.get("saturation", area_triggers_and_actions_dict["default_levels"]["saturation"]))) | ||
brightness = PercentType(str(item_metadata.get("brightness", area_triggers_and_actions_dict["default_levels"]["brightness"]))) | ||
#log.warn("light_action: item.name [{}], active [{}], brightness [{}], lux [{}], low_lux_trigger [{}]".format(item.name, active, brightness, items[area_triggers_and_actions_dict["lux_item_name"]], low_lux_trigger)) | ||
lux_item_name = get_key_value(item.name, "area_triggers_and_actions", "light_action", "lux_item_name") or area_triggers_and_actions_dict.get("lux_item_name") | ||
if active and brightness > PercentType(0) and (True if lux_item_name is None else items[lux_item_name].intValue() <= low_lux_trigger): | ||
if item.type == "Dimmer" or (item.type == "Group" and item.baseItem.type == "Dimmer"): | ||
if item.state != brightness: | ||
if item.state < PercentType(99): | ||
events.sendCommand(item, brightness) | ||
log.info(">>>>>>> {}: {}".format(item.name, brightness)) | ||
else: | ||
log.info("[{}]: dimmer was manually set > 98, so not adjusting".format(item.name)) | ||
else: | ||
log.debug("[{}]: dimmer is already set to [{}], so not sending command".format(item.name, brightness)) | ||
elif item.type == "Color" or (item.type == "Group" and item.baseType == "Color"): | ||
if item.state != HSBType(hue, saturation, brightness): | ||
if item.state.brightness < PercentType(99): | ||
events.sendCommand(item, HSBType(hue, saturation, brightness)) | ||
log.info(">>>>>>> {}: [{}]".format(item.name, HSBType(hue, saturation, brightness))) | ||
else: | ||
log.info("[{}]: brightness was manually set > 98, so not adjusting".format(item.name)) | ||
else: | ||
log.debug("[{}]: color is already set to [{}, {}, {}], so not sending command".format(item.name, hue, saturation, brightness)) | ||
elif item.type == "Switch" or (item.type == "Group" and item.baseItem.type == "Switch"): | ||
if item.state == OFF: | ||
events.sendCommand(item, ON) | ||
log.info(">>>>>>> {}: ON".format(item.name)) | ||
else: | ||
log.debug("[{}]: switch is already [ON], so not sending command".format(item.name)) | ||
else: | ||
if item.type == "Dimmer" or (item.type == "Group" and item.baseItem.type == "Dimmer"): | ||
if item.state != PercentType(0): | ||
if item.state < PercentType(99): | ||
events.sendCommand(item, PercentType(0)) | ||
log.info("<<<<<<<<<<<<<<<<<<<<< {}: 0".format(item.name)) | ||
else: | ||
log.info("{}: dimmer was manually set > 98, so not adjusting".format(item.name)) | ||
else: | ||
log.debug("[{}]: dimmer is already set to [0], so not sending command".format(item.name)) | ||
elif item.type == "Color" or (item.type == "Group" and item.baseType == "Color"): | ||
if item.state != HSBType(DecimalType(0), PercentType(0), PercentType(0)): | ||
if item.state.brightness < PercentType(99): | ||
events.sendCommand(item, "0, 0, 0") | ||
log.info("<<<<<<<<<<<<<<<<<<<<< {}: [0, 0, 0]".format(item.name)) | ||
else: | ||
log.info("{}: brightness was manually set > 98, so not adjusting".format(item.name)) | ||
else: | ||
log.debug("[{}]: color is already set to [0, 0, 0], so not sending command".format(item.name)) | ||
elif item.type == "Switch" or (item.type == "Group" and item.baseItem.type == "Switch"): | ||
if item.state == ON: | ||
events.sendCommand(item, OFF) | ||
log.info("<<<<<<<<<<<<<<<<<<<<< {}: OFF".format(item.name)) | ||
else: | ||
log.debug("[{}]: switch is already set to [OFF], so not sending command".format(item.name)) | ||
#log.warn("Test: light_action: {}: [{}]: time=[{}]".format(item.name, "ON" if active else "OFF", DateTime.now().getMillis() - start_time)) | ||
|
||
def toggle_action(item, active): | ||
""" | ||
This function sends the OFF command to the Item. | ||
Args: | ||
Item item: The Item to perform the action on | ||
boolean active: Area activity (True for active and False for inactive) | ||
""" | ||
events.sendCommand(item, ON if item.state == OFF else OFF) |
Oops, something went wrong.