Pyscript for Home Assistant

repository·master·Indexed 22 days ago

https://github.com/custom-components/pyscript

A custom integration for Home Assistant that enables advanced automation and logic using Python. Pyscript allows users to write scripts that interact with Home Assistant states and services as native Python objects, featuring state binding, non-blocking execution, and parallel function processing. It supports state, time (including cron), and event triggers via Python decorators. Additional tools include an optional Jupyter kernel for interactive development and a service to generate IDE stubs for autocompletion and type checking.

Tokens
18.2K
Snippets
51
Records
77
Agent score
75%

What's inside Pyscript

  1. What is Pyscript?

    master

    Pyscript is a Home Assistant custom integration that allows you to write Python functions and scripts to implement automation, logic, and triggers. It provides a seamless, Pythonic way to interact with Home Assistant by binding state variables to Python variables and making Home Assistant services callable as standard Python functions.

    Key features include:

    • Parallel Execution: Functions run as small, independent programs that can run in parallel for extended periods.
    • Non-blocking Operations: Functions can sleep or wait for state changes or events without affecting other operations.
    • Triggering Mechanisms: Use Python decorators to trigger functions based on state changes, time (including cron syntax), or events.
    • Jupyter Integration: Includes a kernel that allows interactive development and testing via Jupyter notebooks, Lab, or VS Code.
  2. Access Pyscript documentation and community support

    master

    For the most up-to-date information on using Pyscript, refer to the following resources:

    • Stable Documentation: The latest official release documentation.
    • Latest Documentation: The current master branch documentation from GitHub.
    • Community Support: Use the GitHub Discussions page for help and community interaction.
    • Release Notes: View changes, updates, and new features in the GitHub releases section.
    • Bug Reports: Use GitHub Issues to report bugs or propose new features.
    • Wiki: Explore the project Wiki to find shared Pyscript apps and scripts.
  3. How to access and manipulate state variables

    master

    State variables (Home Assistant entities) are accessible in Python by their name in the format DOMAIN.name.

    Key behaviors:

    • Values: State values are always strings. Use helper methods like .as_int() or .as_float() to convert them.
    • Attributes: Access attributes using dot notation: DOMAIN.name.attr.
    • Dynamic Access: Use built-in functions for dynamic names:
      • state.get(name)
      • state.getattr(name, attr)
      • state.set(name, value)
      • state.setattr(name, attr, value)
      • state.exist(name)
      • state.names(domain=None)
    • Collisions: Service names take priority over state variables. If a name collision occurs, use state.get(name) to access the state variable.
    • Errors: Accessing a non-existent state variable raises NameError; a non-existent attribute raises AttributeError. (Note: @state_trigger expressions evaluate undefined variables to None instead of raising errors).
    # Direct access
    val = binary_sensor.test1
    
    # Accessing attributes
    attr = binary_sensor.test1.some_attribute
    
    # Dynamic access
    val = state.get("sensor.temperature")
    
    # Getting all names in a domain
    names = state.names(domain="light")
  4. Handle undefined variables in str_expr

    master

    When using string expressions (str_expr) in decorators like @event_trigger or within state triggers, Pyscript handles undefined variables gracefully.

    If you reference an undefined state variable, an undefined state attribute, or an undefined .old variable, the expression will evaluate to None rather than throwing an exception.

  5. How Pyscript works: Core Concepts

    master

    Pyscript allows you to write Python functions that act as small, independent programs running in parallel within Home Assistant.

    Key Features:

    • State Binding: Home Assistant state variables are bound to Python variables, making them easy to access and manipulate.
    • Service Integration: Home Assistant services are callable directly as Python functions.
    • Triggers: Functions can be configured to run based on time, state changes, or specific events.
    • Non-blocking Execution: Functions can use sleep or wait for state/event changes without blocking other Pyscript operations or the main Home Assistant loop.
    • Parallelism: Each function runs independently, allowing for complex, long-running logic.
  6. Language features and limitations in Pyscript

    master

    Pyscript implements a fully async Python interpreter using AST parsing. While it supports almost all Python language features, there are specific constraints and capabilities to be aware of:

    Supported Features:

    • Standard Python imports (restricted by default for security).
    • Async-based execution.
    • Built-in functions for logging, state management, task management, and waiting for triggers.

    Limitations:

    • No Generators: The yield keyword is not supported.
    • No Special Class Methods: You cannot define special class methods.

    Security Note: By default, the list of allowed imports is restricted. You can enable all imports by setting the allow_all_imports configuration option.

  7. How triggers work in Pyscript

    master

    Pyscript uses Python decorators (the @ syntax) to define when a function should execute. There are three primary types of triggers:

    1. State Triggers: Triggered by Python expressions using state variables. The trigger is evaluated only when a referenced state variable changes, and it fires when the expression evaluates to true or a non-zero value.
    2. Time Triggers: Can be configured for:
      • Single events (specific date and time).
      • Repetitive events (specific time of day, weekdays, or relative to sunrise/sunset).
      • Cron syntax: Periodic execution based on minutes, hours, days of week, days of month, and months.
    3. Event Triggers: Triggered by a specific event type. You can optionally include a Python trigger test that evaluates the event data to determine if the function should run.
  8. Understand Pyscript language limitations

    master

    Pyscript is an asynchronous implementation of Python and has several key differences:

    • No async/await required: Pyscript detects if a function is async and calls it correctly. However, declaring async def in pyscript does not return a coroutine like standard Python; use @pyscript_compile if you need true async behavior.
    • No Generators/Yield: The yield statement and generators are not supported.
    • No match-case: The Python match statement is not supported.
    • No Built-in I/O: open(), read(), and write() are not supported to prevent blocking the event loop.
    • Special Methods: Methods like __eq__ in pyscript-defined classes will not work because they are treated as async. Use @pyscript_compile or define the class in a native Python module.
  9. Trigger functions using @state_trigger, @time_trigger, and @event_trigger

    master

    Pyscript allows you to execute functions automatically based on specific conditions using decorators:

    • @state_trigger(condition): Executes the function when the specified state condition evaluates to True or non-zero. The condition is evaluated whenever the variables it references change.
    • @time_trigger(condition): (Mentioned as a trigger type).
    • @event_trigger(condition): (Mentioned as a trigger type).

    Note: Triggers are evaluated independently of the function execution; the trigger logic does not wait for the function to finish before checking for the next condition.

    @state_trigger("security.rear_motion == '1' or security.side_motion == '1'")
    def motion_light_rear():
        # Function logic here
        pass
  10. Understand Pyscript Global Contexts

    master

    Each pyscript file and Jupyter session runs in its own Global Context. Variables and functions defined in one context are isolated from others unless explicitly imported.

    Context Naming Convention

    Context names are derived from the file path:

    • pyscript/FILE.py $\rightarrow$ file.FILE
    • pyscript/modules/MODULE.py $\rightarrow$ modules.MODULE
    • pyscript/apps/APP/FILE.py $\rightarrow$ apps.APP.FILE
    • pyscript/scripts/DIR1/FILE.py $\rightarrow$ scripts.DIR1.FILE
    • Jupyter sessions $\rightarrow$ jupyter_NNN (where NNN is an integer)

    Interacting with Contexts

    Use these functions to navigate contexts (primarily for Jupyter/interactive use):

    • pyscript.get_global_ctx(): Returns the current context name.
    • pyscript.list_global_ctx(): Lists all available contexts.
    • pyscript.set_global_ctx(new_ctx_name): Switches to a different context.

    Note: When a script file is reloaded, its global context is destroyed and recreated. Any interactive changes made in Jupyter to a script's context will be lost upon reload.

  11. Use Pyscript Modules and Packages

    master

    You can store reusable code in the <config>/pyscript/modules directory. This directory can contain individual .py files (modules) or directories with an __init__.py (packages).

    • Importing: Modules/packages in this folder can be imported by any script or application.
    • Import Restrictions: Importing from modules/ is permitted even if allow_all_imports is set to false.
    • Reloading: Modifying a module in this directory will trigger an unload of the module and a reload of all dependent scripts or applications.
    • IDE Helpers: Files placed under modules/stubs/ are ignored at runtime, making this the ideal place for IDE type-hinting stubs.
  12. How Pyscript works as a scripting engine

    master

    Pyscript provides a rich Python environment for Home Assistant automation. It allows you to write small, parallel programs that run independently.

    Key Capabilities:

    • State Binding: Home Assistant state variables are bound directly to Python variables.
    • Service Integration: Home Assistant services can be called directly as Python functions.
    • Triggers: Functions can be configured to run based on time, state changes, or events.
    • Service Exposure: Functions can be configured to be callable as Home Assistant services.
    • Non-blocking Operations: Functions can use sleep or wait for state/event changes without blocking other operations or affecting the performance of Home Assistant.