Open-source project
custom-components/pyscript avatar
custom-components/pyscript

Pyscript: writing Home Assistant automations in Python

Pyscript adds rich Python scripting to HASS

1,191 stars69 forksPythonApache-2.0

At a glance

What is it?
Pyscript is a Home Assistant custom integration that lets you write Python functions instead of YAML automations, with state variables bound to Python variables and services callable as functions. It runs each function as its own program, and it can wait for states or events without blocking anything else.
Who is it for?
Adopt Pyscript if your Home Assistant logic has outgrown YAML automations, especially if it involves loops, waiting on several states, or reusable functions. Do not adopt it if your automations are simple triggers, since YAML is easier to audit and requires no custom component.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 42 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why Python in a YAML automation platform

Home Assistant's native automation model is YAML, and it works well for the case it was designed for: a trigger, a condition, and a sequence of actions. The pain shows up when an automation needs a loop, a helper function, a calculated value, or a wait on more than one condition. Expressing that in YAML means either template gymnastics or a pile of nested conditionals.

Pyscript is a HACS custom integration that answers this with Python. It lets you write Python functions and scripts that implement automation, logic, and triggers. Two bindings do most of the work. State variables are bound to Python variables, so reading sensor.state and writing it are the same operation you would expect in Python, and services are callable as Python functions, so calling an action reads as a function call rather than a service call with YAML payload.

The framing in the README is that it is easy and concise to implement logic this way, and the audience is a Home Assistant user whose automations have outgrown the built-in syntax. The project is Apache-2.0 licensed, copyright Craig Barratt, with the current release at 2.1.0 from 2026-08-11 and the last push on 2026-09-11.

The comparison with the built-in automation editor is the one that matters. YAML is declarative and diffable, and every action is visible in the UI. Python is imperative and compact, and nothing is visible unless you look at the file. That trade is favourable only once the logic is complex enough to make YAML painful.

Functions that run like small parallel programs

The concurrency model is the part that distinguishes Pyscript from an automation engine. A function you write can be configured to be called as a service, or to run on time, state-change, or event triggers. It can call any service, fire events, and set state variables.

What makes it more than that is the waiting. Functions can sleep or wait for additional changes in state variables or events, and the README is explicit that this happens without slowing or affecting other operations. The suggested mental model is small programs that run in parallel, independently of each other, and that could be active for extended periods of time.

That is a fundamentally different execution model from Home Assistant's native automation, where an automation runs to completion and waits inside an action block the whole flow. In Pyscript a function that waits for a door to open is a task suspended on a condition, and the automation engine carries on with everything else.

The practical consequence is that a long-running Pyscript function is a resource you are holding for as long as it waits, and the design assumes you write several of them rather than one enormous script. It also means debugging is different. A function suspended mid-wait has no obvious output, so the logging guidance in the README matters: watch the Home Assistant log for pyscript errors and for logger output from your scripts.

Installing as a custom component

There are two routes, and the HACS route is the shorter one. Under HACS, in the Integrations section, you select the plus button, search for pyscript, and install it.

The manual route is a download of the release zip, which is named hass-custom-pyscript.zip, and an unzip into your configuration directory:

bash
cd YOUR_HASS_CONFIG_DIRECTORY    # same place as configuration.yaml
mkdir -p custom_components/pyscript
cd custom_components/pyscript
unzip hass-custom-pyscript.zip

There is also a way to run the current master version rather than a release, by cloning the repository and copying the component directory across:

bash
mkdir SOME_LOCAL_WORKSPACE
cd SOME_LOCAL_WORKSPACE
git clone https://github.com/custom-components/pyscript.git
mkdir -p YOUR_HASS_CONFIG_DIRECTORY/custom_components
cp -pr pyscript/custom_components/pyscript YOUR_HASS_CONFIG_DIRECTORY/custom_components

That second form is the one to be careful with. It tracks master, so you get unreleased changes and you get them whether you asked for them or not, and there is no release zip to fall back to if a change breaks your setup. For a production instance the release zip is the safer default.

Either way, the result is a custom_components directory inside your Home Assistant configuration, which is the standard location for third-party integrations and which is why a copy-based install works at all.

The three configuration flags and the decorator switch

After installation you add the integration from the Integrations menu in the Home Assistant configuration UI, as Pyscript Python scripting, or by adding a pyscript block to configuration.yaml. There are three optional parameters and all three default to false:

yaml
pyscript:
  allow_all_imports: true
  hass_is_global: true
  legacy_decorators: true

allow_all_imports lets any Python package be imported. hass_is_global exposes hass as a variable rather than requiring it to be passed in, which is convenient inside functions that need to reach the Home Assistant API. legacy_decorators temporarily switches back to the legacy decorator subsystem.

That third one is the one with a story attached. Starting with version 2.0.0, Pyscript uses the new decorator subsystem by default, and if you hit a problem in the new implementation the escape hatch is legacy_decorators: true. The README asks that if you use it, you also file a bug report in GitHub Issues so the new subsystem can be fixed. That is a reasonable arrangement, because a silent fallback would let the bug persist unnoticed, and asking for the report makes the temporary workaround a contribution.

The rest of the workflow is short. Add files with a .py suffix in the config/pyscript folder, restart Home Assistant, and whenever you change a script file, make a reload service call to pyscript. The restart is a separate step from the reload, which is worth understanding: the initial restart picks up the integration and the .py files, while the reload service call picks up changes to those files without a full restart.

A Jupyter kernel for developing against a live instance

Pyscript ships a kernel that interfaces with the Jupyter front-ends, which means notebook, console, lab, and VSCode. The point is to develop and test Pyscript code interactively, and to interact with much of Home Assistant by looking at state variables and calling services.

That is a significant addition for a Home Assistant integration. The alternative workflow for a script author is to write the file, reload the service, trigger the automation, and read the log. Each iteration costs a restart-free reload and a manual trigger, and the feedback arrives as log lines. In a notebook you can call a function, inspect the return value, look at a state variable, and try again, all against the running instance.

The kernel installation is optional and documented separately, in the hass-pyscript-jupyter README, and there is a Jupyter notebook tutorial published on nbviewer that can be downloaded and run interactively in a notebook connected to a live Home Assistant with Pyscript. The kernel is a separate repository from the integration, which means it can be versioned and updated independently of the component itself.

The other development aid is stub generation. Pyscript can generate IDE stub modules by calling the pyscript.generate_stubs service, which is what lets an editor know about the names Home Assistant exposes, including the generated services and state variables. The setup details are in the IDE Helpers section of the documentation.

Against YAML automations, and against AppDaemon

The honest comparison is with the built-in YAML automation, and the two are not interchangeable. A YAML automation is visible in the Home Assistant UI, editable without touching files, and it is the format that most of the community documentation and support assume. A Pyscript function is a Python file that most people cannot read at a glance, and it is only as good as the tests or logs around it.

That said, the YAML approach has a hard ceiling. A wait for one of several conditions, a loop over a list of devices, a reusable piece of business logic, a computation that needs more than one template expression: each of these pushes YAML further from readable. Pyscript is the answer at that point, and the value is proportional to how much of your configuration is complex logic rather than triggers.

Pyscript is a custom component, so it shares the Home Assistant process, the state machine, and the service calls, and it installs by copying a directory into custom_components. If you want Python but want to stay inside the Home Assistant configuration, Pyscript is the narrower and simpler choice.

The counter-argument for staying with YAML is auditability. A custom component also has a wider privilege surface, because allow_all_imports and hass_is_global are exactly the switches that make a script powerful, and both default to false for that reason.

The 2.0 rewrite and what a custom component costs you

The release history shows a significant change recently. Version 2.0.0 was published on 2026-05-02, followed by 2.0.1 in May and 2.1.0 on 2026-08-11. The 2.0 line replaced the decorator subsystem with a new one, and the legacy_decorators option exists only for that transition. A major version bump inside a Home Assistant custom component is worth taking seriously, because a custom component does not go through the normal review that core integrations get.

What that means practically is that the upgrade path is yours to verify. The README does not describe a migration guide for 2.0, only the fallback switch, so the sensible procedure is to read the release notes on the releases page, test the upgrade on a copy of your configuration, and keep legacy_decorators ready to set if something in your scripts behaves differently.

The other cost of a custom component is that it is a dependency outside the normal update path. Home Assistant will not upgrade it for you, and the HACS badge marks it as a default integration, meaning it is one of the ones HACS offers prominently, but the update is still a manual action. A script that depends on a Pyscript behaviour that changes in a later release will fail at runtime rather than at install time.

The project keeps a stable documentation build and a latest documentation build that tracks master, and the distinction matters when you are reading about a behaviour that may not be in your installed version. For a component with a 2.x rewrite behind it, the version you read about should match the version you run.

Editorial conclusion

Adopt Pyscript if your Home Assistant logic has outgrown YAML automations, especially if it involves loops, waiting on several states, or reusable functions. Do not adopt it if your automations are simple triggers, since YAML is easier to audit and requires no custom component. Verify first that the three configuration flags match the environment you run, because allow_all_imports widens what your scripts can import and legacy_decorators changes which decorator implementation is active.

Frequently asked questions

How do I install Pyscript in Home Assistant?

The shortest route is HACS: under HACS Integrations, select the plus button, search for pyscript, and install it. Manually, download hass-custom-pyscript.zip from the latest release, create custom_components/pyscript inside your configuration directory, and unzip the file there.

What configuration options does Pyscript accept?

There are three optional parameters, all defaulting to false: allow_all_imports, which lets any Python package be imported, hass_is_global, which exposes hass as a variable, and legacy_decorators, which switches back to the legacy decorator subsystem. You set them under a pyscript key in configuration.yaml or through the Integrations menu.

How do I reload Pyscript after editing a script file?

Add files with a .py suffix in the config/pyscript folder, restart Home Assistant the first time, and then make a reload service call to pyscript whenever you change a file. The README also tells you to watch the Home Assistant log for pyscript errors and for logger output from your scripts.

Can I develop Pyscript code in Jupyter?

Yes. Pyscript provides a kernel that interfaces with the Jupyter front-ends, including notebook, console, lab and VSCode, so you can test code interactively against a live instance. The kernel install is optional and documented in the separate hass-pyscript-jupyter repository, which also hosts a notebook tutorial.

What is the legacy_decorators option for?

Starting with version 2.0.0, Pyscript uses a new decorator subsystem by default. If you find a problem in the new implementation, setting legacy_decorators to true switches back to the legacy one temporarily. The README asks that you file a bug report in GitHub Issues if you use the fallback.

Official sources

  1. custom-components/pyscript on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/custom-components-pyscript.svg)](https://hysenlabs.com/projects/custom-components-pyscript)

Was this useful?