Skip to content

Commit 0c1e929

Browse files
authored
Merge pull request #51 from craigbarratt/master
added hass_is_global config parameter
2 parents 5f4f269 + da11bfb commit 0c1e929

File tree

9 files changed

+163
-41
lines changed

9 files changed

+163
-41
lines changed

custom_components/pyscript/__init__.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@
1919
import homeassistant.helpers.config_validation as cv
2020
from homeassistant.loader import bind_hass
2121

22-
from .const import CONF_ALLOW_ALL_IMPORTS, DOMAIN, FOLDER, LOGGER_PATH, SERVICE_JUPYTER_KERNEL_START
22+
from .const import (
23+
CONF_ALLOW_ALL_IMPORTS,
24+
CONF_HASS_IS_GLOBAL,
25+
DOMAIN,
26+
FOLDER,
27+
LOGGER_PATH,
28+
SERVICE_JUPYTER_KERNEL_START,
29+
)
2330
from .eval import AstEval
2431
from .event import Event
2532
from .function import Function
@@ -31,7 +38,11 @@
3138
_LOGGER = logging.getLogger(LOGGER_PATH)
3239

3340
PYSCRIPT_SCHEMA = vol.Schema(
34-
{vol.Optional(CONF_ALLOW_ALL_IMPORTS, default=False): cv.boolean}, extra=vol.ALLOW_EXTRA,
41+
{
42+
vol.Optional(CONF_ALLOW_ALL_IMPORTS, default=False): cv.boolean,
43+
vol.Optional(CONF_HASS_IS_GLOBAL, default=False): cv.boolean,
44+
},
45+
extra=vol.ALLOW_EXTRA,
3546
)
3647

3748
CONFIG_SCHEMA = vol.Schema({DOMAIN: PYSCRIPT_SCHEMA}, extra=vol.ALLOW_EXTRA)

custom_components/pyscript/config_flow.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@
88
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
99
from homeassistant.core import callback
1010

11-
from .const import CONF_ALLOW_ALL_IMPORTS, DOMAIN
11+
from .const import CONF_ALLOW_ALL_IMPORTS, CONF_HASS_IS_GLOBAL, DOMAIN
12+
13+
CONF_BOOL_ALL = {CONF_ALLOW_ALL_IMPORTS, CONF_HASS_IS_GLOBAL}
1214

1315
PYSCRIPT_SCHEMA = vol.Schema(
14-
{vol.Optional(CONF_ALLOW_ALL_IMPORTS, default=False): bool}, extra=vol.ALLOW_EXTRA,
16+
{
17+
vol.Optional(CONF_ALLOW_ALL_IMPORTS, default=False): bool,
18+
vol.Optional(CONF_HASS_IS_GLOBAL, default=False): bool,
19+
},
20+
extra=vol.ALLOW_EXTRA,
1521
)
1622

1723

@@ -34,15 +40,17 @@ async def async_step_init(self, user_input: Dict[str, Any] = None) -> Dict[str,
3440
step_id="init",
3541
data_schema=vol.Schema(
3642
{
37-
vol.Optional(
38-
CONF_ALLOW_ALL_IMPORTS, default=self.config_entry.data[CONF_ALLOW_ALL_IMPORTS],
39-
): bool
43+
vol.Optional(name, default=self.config_entry.data.get(name, False)): bool
44+
for name in CONF_BOOL_ALL
4045
},
4146
extra=vol.ALLOW_EXTRA,
4247
),
4348
)
4449

45-
if user_input[CONF_ALLOW_ALL_IMPORTS] != self.config_entry.data[CONF_ALLOW_ALL_IMPORTS]:
50+
if any(
51+
name not in self.config_entry.data or user_input[name] != self.config_entry.data[name]
52+
for name in CONF_BOOL_ALL
53+
):
4654
updated_data = self.config_entry.data.copy()
4755
updated_data.update(user_input)
4856
self.hass.config_entries.async_update_entry(entry=self.config_entry, data=updated_data)
@@ -108,15 +116,13 @@ async def async_step_import(self, import_config: Dict[str, Any] = None) -> Dict[
108116
# Update values for all keys, excluding `allow_all_imports` for entries
109117
# set up through the UI.
110118
for key, val in import_config.items():
111-
if entry.source == SOURCE_IMPORT or key != CONF_ALLOW_ALL_IMPORTS:
119+
if entry.source == SOURCE_IMPORT or key not in CONF_BOOL_ALL:
112120
updated_data[key] = val
113121

114122
# Remove values for all keys in entry.data that are not in the imported config,
115123
# excluding `allow_all_imports` for entries set up through the UI.
116124
for key in entry.data:
117-
if (
118-
entry.source == SOURCE_IMPORT or key != CONF_ALLOW_ALL_IMPORTS
119-
) and key not in import_config:
125+
if (entry.source == SOURCE_IMPORT or key not in CONF_BOOL_ALL) and key not in import_config:
120126
updated_data.pop(key)
121127

122128
# Update and reload entry if data needs to be updated

custom_components/pyscript/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
FOLDER = "pyscript"
66

77
CONF_ALLOW_ALL_IMPORTS = "allow_all_imports"
8+
CONF_HASS_IS_GLOBAL = "hass_is_global"
89

910
SERVICE_JUPYTER_KERNEL_START = "jupyter_kernel_start"
1011

custom_components/pyscript/global_ctx.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import os
55
from types import ModuleType
66

7-
from .const import FOLDER, LOGGER_PATH
7+
from .const import CONF_HASS_IS_GLOBAL, DOMAIN, FOLDER, LOGGER_PATH
88
from .eval import AstEval
99
from .function import Function
1010
from .trigger import TrigInfo
@@ -26,6 +26,12 @@ def __init__(self, name, global_sym_table=None, manager=None, rel_import_path=No
2626
self.auto_start = False
2727
self.module = None
2828
self.rel_import_path = rel_import_path
29+
config_entry = Function.hass.data.get(DOMAIN, {})
30+
if config_entry.data.get(CONF_HASS_IS_GLOBAL, False):
31+
#
32+
# expose hass as a global variable if configured
33+
#
34+
self.global_sym_table["hass"] = Function.hass
2935

3036
def trigger_register(self, func):
3137
"""Register a trigger function; return True if start now."""

custom_components/pyscript/strings.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"title": "pyscript",
66
"description": "Once you have created an entry, refer to the [docs](https://hacs-pyscript.readthedocs.io/en/latest/) to learn how to create scripts and functions.",
77
"data": {
8-
"allow_all_imports": "Allow All Imports?"
8+
"allow_all_imports": "Allow All Imports?",
9+
"hass_is_global": "Access hass as a global variable?"
910
}
1011
}
1112
},
@@ -20,7 +21,8 @@
2021
"init": {
2122
"title": "Update pyscript configuration",
2223
"data": {
23-
"allow_all_imports": "Allow All Imports?"
24+
"allow_all_imports": "Allow All Imports?",
25+
"hass_is_global": "Access hass as a global variable?"
2426
}
2527
},
2628
"no_ui_configuration_allowed": {

custom_components/pyscript/translations/en.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"title": "pyscript",
66
"description": "Once you have created an entry, refer to the [docs](https://hacs-pyscript.readthedocs.io/en/latest/) to learn how to create scripts and functions.",
77
"data": {
8-
"allow_all_imports": "Allow All Imports?"
8+
"allow_all_imports": "Allow All Imports?",
9+
"hass_is_global": "Access hass as a global variable?"
910
}
1011
}
1112
},
@@ -20,7 +21,8 @@
2021
"init": {
2122
"title": "Update pyscript configuration",
2223
"data": {
23-
"allow_all_imports": "Allow All Imports?"
24+
"allow_all_imports": "Allow All Imports?",
25+
"hass_is_global": "Access hass as a global variable?"
2426
}
2527
},
2628
"no_ui_configuration_allowed": {

docs/configuration.rst

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
Configuration
22
=============
33

4-
- Go to the Integrations menu in the Home Assistant Configuration UI and add
5-
``Pyscript Python scripting`` from there, or add ``pyscript:`` to
6-
``<config>/configuration.yaml``; pyscript has one optional configuration
7-
parameter that allows any python package to be imported if set, eg:
4+
- Pyscript can be configured using the UI, or via yaml. To use the UI, go to the
5+
Configuration -> Integrations page and selection "+" to add ``Pyscript Python scripting``.
6+
After that, you can change the settings anytime by selecting Options under Pyscript
7+
in the Configuration page.
8+
9+
Alternatively, for yaml configuration, add ``pyscript:`` to ``<config>/configuration.yaml``.
10+
Pyscript has two optional configuration parameters that allow any python package to be
11+
imported and exposes the ``hass`` variable as a global (both options default to ``false``):
812

913
.. code:: yaml
1014
1115
pyscript:
1216
allow_all_imports: true
17+
hass_is_global: true
1318
1419
- Add files with a suffix of ``.py`` in the folder ``<config>/pyscript``.
15-
- Restart HASS.
16-
- Whenever you change a script file, make a ``reload`` service call to ``pyscript``.
20+
- Restart HASS after installing pyscript.
21+
- Whenever you change a script file or configuration, make a ``reload`` service call to ``pyscript``.
1722
- Watch the HASS log for ``pyscript`` errors and logger output from your scripts.

docs/reference.rst

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,34 @@ Reference
44
Configuration
55
-------------
66

7-
Pyscript has one optional configuration setting that allows any Python package to be imported
8-
if set, eg:
7+
Pyscript can be configured using the UI, or via yaml. To use the UI, go to the
8+
Configuration -> Integrations page and selection "+" to add ``Pyscript Python scripting``.
9+
After that, you can change the settings anytime by selecting Options under Pyscript
10+
in the Configuration page.
11+
12+
Alternatively, for yaml configuration, add ``pyscript:`` to ``<config>/configuration.yaml``.
13+
You can't mix these two methods - your initial choice determines how you should update
14+
these settings later. If you want to switch configuration methods you will need to
15+
uninstall and reinstall pyscript.
16+
17+
Pyscript has two optional configuration parameters that allow any python package to be
18+
imported and exposes the ``hass`` variable as a global (both options default to ``false``).
19+
In `<config>/configuration.yaml``:
920

1021
.. code:: yaml
1122
1223
pyscript:
1324
allow_all_imports: true
25+
hass_is_global: true
26+
27+
The settings and behavior of your code can be controlled by additional user-defined yaml
28+
configuration settings. If you configured pyscript using the UI flow, you can still
29+
add additional configuration settings via yaml. Since they are free-form (no fixed
30+
schema) there is no UI configuration available for these additional settings.
1431

15-
The settings and behavior of your code can be controlled by additional user-defined configuration
16-
settings. All the pyscript configuration settings are available via the variable
17-
``pyscript.config`` (see `this section <#accessing-yaml-configuration>`__). The recommended
18-
structure is to have entries for each application you write stored under an ``apps`` entry.
32+
All the pyscript configuration settings are available via the variable ``pyscript.config``
33+
(see `this section <#accessing-yaml-configuration>`__). The recommended structure is
34+
to have entries for each application you write stored under an ``apps`` entry.
1935
For example, applications ``my_app1`` and ``my_app2`` would be configured as:
2036

2137
.. code:: yaml
@@ -1078,6 +1094,58 @@ triggers and application logic, eg:
10781094
10791095
Validating the configuration can be done either manually or with the ``voluptuous`` package.
10801096

1097+
Access to Hass
1098+
^^^^^^^^^^^^^^
1099+
1100+
If the ``hass_is_global`` configuration setting is set (default is off), then the variable ``hass``
1101+
is available as a global variable in all pyscript contexts. That provides significant flexiblity
1102+
in accessing HASS internals for cases where pyscript doesn't provide some binding or access.
1103+
1104+
Ideally you should only use ``hass`` for read-only access. However, you do need a good understanding
1105+
of ``hass`` internals and objects if you try to call functions or update anything. With great power
1106+
comes great responsibility!
1107+
1108+
For example, you can access configuration settings like ``hass.config.latitude`` or ``hass.config.time_zone``.
1109+
1110+
You can use ``hass`` to compute sunrise and sunset times using the same method HASS does, eg:
1111+
1112+
.. code:: python
1113+
1114+
import homeassistant.helpers.sun as sun
1115+
import datetime
1116+
1117+
location = sun.get_astral_location(hass)
1118+
sunrise = location.sunrise(datetime.datetime.today()).replace(tzinfo=None)
1119+
sunset = location.sunset(datetime.datetime.today()).replace(tzinfo=None)
1120+
print(f"today sunrise = {sunrise}, sunset = {sunset}")
1121+
1122+
Here's another method that uses the installed version of ``astral`` directly, rather than the HASS
1123+
helper function. It's a bit more crytpic since it's a very old version of ``astral``, but you can
1124+
see how the HASS configuration values are used:
1125+
1126+
.. code:: python
1127+
1128+
import astral
1129+
import datetime
1130+
1131+
here = astral.Location(
1132+
(
1133+
"",
1134+
"",
1135+
hass.config.latitude,
1136+
hass.config.longitude,
1137+
str(hass.config.time_zone),
1138+
hass.config.elevation,
1139+
)
1140+
)
1141+
sunrise = here.sunrise(datetime.datetime.today()).replace(tzinfo=None)
1142+
sunset = here.sunset(datetime.datetime.today()).replace(tzinfo=None)
1143+
print(f"today sunrise = {sunrise}, sunset = {sunset}")
1144+
1145+
If there are particular HASS internals that you think many pyscript users would find useful,
1146+
consider making a feature request or PR so it becomes a built-in feature in pyscript, rather
1147+
than requiring users to always have to delve into ``hass``.
1148+
10811149
Avoiding Event Loop I/O
10821150
^^^^^^^^^^^^^^^^^^^^^^^
10831151

0 commit comments

Comments
 (0)