Pyronix Cloud for Home Assistant
Monitor and control Pyronix intruder alarm panels (Euro 46, Enforcer) from Home Assistant. The integration connects through the Pyronix Cloud, the same end-to-end encrypted relay used by the official HomeControl2.0 app, so no additional hardware or panel changes are required.
Not affiliated with or endorsed by Pyronix or Hikvision.
Contents
- Highlights
- Compatibility
- How it works
- Features
- Installation
- Configuration
- Arming and force arming
- Automation examples
- Known limitations
- Troubleshooting
- Development
- Licence
Highlights
- Full alarm control. Arm (away, night and custom levels, or individual areas), disarm and force arm from dashboards, voice assistants and automations.
- Secure by default. Every arm and disarm passes an access check: a PIN (stored only as a salted scrypt hash), a list of permitted Home Assistant users, or no check at all, as you choose.
- Clear feedback. If the panel refuses to set, the action fails with the panel's own reason, for example "Full Set cannot be armed: Landing DT Open".
- Every input as a sensor. Door contacts, PIRs and other inputs become binary sensors that can drive notifications, lighting and heating.
- Two connection modes. Short on-demand sessions that keep the HomeControl2 app available (default), or a persistent session with sub-second updates.
- Safe failure behaviour. Commands are never retried automatically, sessions always close cleanly, and credentials are redacted from logs and diagnostics.
See Automation examples for ready-made YAML.
Compatibility
| Item | Supported |
|---|---|
| Home Assistant | 2026.2 or later |
| Panels | Pyronix Euro 46 (verified). Enforcer uses the same protocol but has not been verified yet. |
| Panel connectivity | Any module that connects the panel to the Pyronix Cloud (for example DIGI-WiFi or DIGI-LAN) |
| Subscription | An active Pyronix Cloud subscription for the panel |
| Panel modes | Level-set panels (levels A/B/C) and area-set panels |
Reports from other models and firmware versions are welcome; please open an issue.
How it works
The panel has no local API that the app uses. Everything goes through the Pyronix Cloud:
Home Assistant ──WSS──▶ wss://app.pyronixcloud.com ──(panel uplink)──▶ Panel
└────────── end-to-end session: ECDH P-256 + AES-128-CFB ──────────┘
- Cloud relay. An XML-like handshake identifies the panel and opens a relay.
- Encrypted panel session. Binary frames are protected with keys derived from an ECDH exchange and the panel's app password.
- Application layer. The client sends one-byte opcodes (arm, disarm, omit, outputs, log). The panel replies with JSON documents (panel, areas, inputs, outputs, user, faults, log).
The full specification is in PROTOCOL.md.
Features
| HA platform | What it shows |
|---|---|
alarm_control_panel |
One entity per panel on level-set panels: level A → away, B → night, C → custom bypass. State comes from the panel's area status codes. Arming stops with the reason if an input is open; the Force arm action omits open inputs, as the app does (see Arming and force arming). Area-set panels get one entity per area. |
binary_sensor |
One per input (zone): open/closed. |
sensor |
Diagnostic: connection state (disabled by default) and fault count. |
| Diagnostics | Download with all credentials and identifiers redacted. |
Planned: output switches, input omit, the event log and PIR-camera photos.
How data is updated
There are two connection modes. You choose one in the options (see Configuration options).
- On demand (default). Every few minutes (default 2) and for each arm or disarm, Home Assistant opens a short session, reads the panel state, says goodbye and disconnects. The panel allows one remote session at a time, so the HomeControl2 app is blocked only for those few seconds. Changes show up at the next poll.
- Persistent ("live updates"). Keeps one session open for instant input and area changes, and reconnects with back-off (5 seconds, doubling up to 5 minutes). If nothing at all arrives from the cloud for a little over two minutes, the session is treated as dead and reconnects. While it is connected, the HomeControl2 app cannot log in.
Straight after a session ends, the Pyronix Cloud sometimes reports the panel as "not polling" for about 35 seconds. Home Assistant then waits and opens the connection again, up to 4 more times, 10 seconds apart. Only the connection is repeated, never a command.
Installation
You need Home Assistant 2026.2 or later.
HACS (recommended)
- Click the button above, or search for Pyronix Cloud in HACS and install it. If it does
not appear yet, add
https://github.com/fregster/ha-pyronix-integrationas a custom repository (category Integration) first. HACS installs thepyronix-cloudlibrary from PyPI. - Restart Home Assistant.
- Add the Pyronix Cloud integration and enter the details below.
Manual installation
- Download this repository (a release
or a ZIP of
main) and copycustom_components/pyronix_cloudinto thecustom_componentsfolder of your Home Assistant configuration directory. - Restart Home Assistant. It installs the
pyronix-cloudlibrary from PyPI on first start. - Add the Pyronix Cloud integration and enter the details below.
HACS tells you about new releases. With a manual install you have to check for them yourself.
What you need
The same details HomeControl2 uses. Each one is listed with its label in the app:
- Device name (
AppUser). This is a free-text name for the client, shown in the app under Settings > User Name. It defaults to the phone model and is not your e-mail. - System ID (
PanelId, 8 characters). You entered it when you added the panel, and the app shows it as "Panel ID:". - App password (
PanelPwd). The login screen asks for this. Your installer set it, and it is not your keypad code. - User code (
UserCode). The login screen asks for this too. It is your keypad code. - An active Pyronix Cloud subscription for the panel
Setup also offers a Live updates tick box, which starts the entry in persistent mode, and an Advanced options section with the cloud relay URL. Leave the URL alone; it is only for testing against a fake relay. Home Assistant checks the details with one short, read-only session before it saves them. The last setup step asks who may arm and disarm (see below).
Configuration options
Change these under Settings → Devices & services → Pyronix Cloud → Configure. Saving reloads the integration.
| Option | What it does | Values |
|---|---|---|
| Connection mode | How Home Assistant talks to the panel (see How data is updated). | On-demand (default, recommended) or Persistent. Persistent locks out the HomeControl2 app. |
| Poll interval | Minutes between polls in on-demand mode. Persistent mode ignores it. | 1 to 60 minutes, default 2. |
| Who can arm and disarm | Which check Home Assistant makes before it arms or disarms (see below). | PIN (default for new entries), Selected users or Anyone. |
| PIN | The PIN asked for in PIN mode. | 4 to 8 digits. Leave empty to keep the current PIN. |
| Users | In users mode, the Home Assistant users who may arm and disarm. | One or more active users. |
| Allow automations and scripts | In users mode, also allow automations and scripts, which act without a user. | Off by default. |
| Always force arm | Make the normal arm actions omit open inputs and arm anyway, as the app does. | Off by default. |
To change the device name, app password or user code, choose Reconfigure from the entry's menu. The System ID cannot change; add a new entry for another panel.
Who can arm and disarm
Home Assistant arms and disarms with the keypad user code you entered during setup, so the integration adds its own check on top. An admin chooses it in the last setup step and can change it later under Settings → Devices & services → Pyronix Cloud → Configure:
- PIN (default). Every arm, disarm and force arm asks for a PIN of 4 to 8 digits. You choose
it in Home Assistant; it may be the same number as your keypad code, but it is a separate
setting. Home Assistant stores only a salted hash of it (scrypt), never the PIN itself, and
diagnostics redact the hash. Automations and scripts must send the PIN as
code. To change the PIN, enter a new one in the options; leave the field empty to keep the current one. - Selected users. Only the Home Assistant users you pick may arm and disarm; no PIN is asked for. Automations and scripts act without a user, so they are refused unless you also tick Allow automations and scripts.
- Anyone. No check: every Home Assistant user, automation and script can disarm the alarm.
A refused call fails with a message saying why (wrong PIN, user not allowed, automations not allowed) and nothing is sent to the panel.
Entries created before this option existed keep working as Anyone, so an upgrade breaks no automations. Home Assistant shows a repair issue for them until an admin saves the options with a choice.
Arming and force arming
The normal arm actions (Arm away, and on level-set panels Arm night and Arm custom bypass) arm without force: if an input is open the panel will not set, and the action fails with the panel's reason, for example "Full Set cannot be armed: Landing DT Open". Home Assistant checks the area before sending anything, and also stops at once if the panel refuses after the command. While the exit timer runs the entity shows arming.
To arm anyway, use the Force arm action (pyronix_cloud.force_arm). It omits open inputs
until the next unset, as the HomeControl2 app always does. It takes an optional code (the PIN)
and, on level-set panels, a mode (away, night or custom_bypass, default away); area
entities ignore mode.
action: pyronix_cloud.force_arm
target:
entity_id: alarm_control_panel.pyronix_alarm
data:
mode: night
code: "4711"
To make the normal arm actions behave like the app, turn on Always force arm in the options.
A forced set can still be refused: if the panel cancels it or reports that the area cannot be set, the action fails at once with the panel's reason. Arming an area that is already set (or setting, or in alarm) sends nothing to the panel.
The integration never repeats an arm or disarm on its own. If a command fails, it reports the error and leaves the next step to you.
Automation examples
Entity IDs follow your panel's site name and input names. The examples assume a level-set panel
named "Pyronix alarm" (the name used when the panel has no site name). Check your own IDs under
Settings → Devices & services → Pyronix Cloud. In PIN mode, automations must send the PIN as
code; in users mode they need Allow automations and scripts.
Tell me when the alarm goes off.
alias: Alarm going off
triggers:
- trigger: state
entity_id: alarm_control_panel.pyronix_alarm
to: triggered
actions:
- action: notify.notify
data:
title: Alarm
message: The house alarm is going off.
Remind me when everyone has left and the alarm is not set.
alias: Alarm not set
triggers:
- trigger: numeric_state
entity_id: zone.home
below: 1
for: "00:10:00"
conditions:
- condition: state
entity_id: alarm_control_panel.pyronix_alarm
state: disarmed
actions:
- action: notify.notify
data:
message: Everyone has left and the alarm is not set.
Set the night level at bedtime. It fails with the reason if a door or window is open; use
pyronix_cloud.force_arm instead to omit open inputs. Keep the PIN in secrets.yaml.
alias: Night set at bedtime
triggers:
- trigger: time
at: "23:30:00"
conditions:
- condition: state
entity_id: alarm_control_panel.pyronix_alarm
state: disarmed
actions:
- action: alarm_control_panel.alarm_arm_night
target:
entity_id: alarm_control_panel.pyronix_alarm
data:
code: !secret pyronix_pin
Tell me about panel faults (for example mains failure or a low battery).
alias: Alarm panel fault
triggers:
- trigger: numeric_state
entity_id: sensor.pyronix_alarm_faults
above: 0
actions:
- action: notify.notify
data:
message: >
The alarm panel reports {{ states('sensor.pyronix_alarm_faults') }} fault(s).
Check the keypad or the HomeControl2 app.
Turn on the hall light when the hall PIR sees movement (only useful with live updates on).
alias: Hall light on movement
triggers:
- trigger: state
entity_id: binary_sensor.pyronix_alarm_hall_pir
to: "on"
actions:
- action: light.turn_on
target:
entity_id: light.hall
Known limitations
- One remote session at a time. The panel lets only one remote client in. In persistent mode Home Assistant holds that session, so the HomeControl2 app (yours and everyone else's) cannot log in. In on-demand mode the app is blocked for a few seconds at each poll. If the app is in use when Home Assistant polls, that poll fails with "panel busy", and the reverse.
- Cloud only. Everything goes through the Pyronix Cloud, as the app does. It needs internet access at home and at the panel, a working Pyronix Cloud and an active subscription for the panel. There is no local connection.
- On-demand mode is not real time. A change shows up at the next poll, up to the poll interval later. Use persistent mode if you need instant updates, and accept that it locks out the app.
- Not a monitored alarm. Do not rely on Home Assistant to tell you about a break-in. Keep your alarm's own signalling or monitoring.
- Verified hardware. All features are verified on a Euro 46. Other models (Enforcer) and other firmware versions are expected to work but have not been verified.
- One command at a time. A second arm or disarm while the first is still running fails with an error saying the panel is already busy with another command.
- No automatic retries of commands. If the panel does not confirm a command, the integration does not know whether it worked, and leaves the next step to you.
- Commands may wait. Straight after a session, the cloud can refuse a new one for about 35 seconds (see How data is updated), so an arm or disarm can take that much longer.
- Not every feature yet. Outputs, input omit, the event log and PIR-camera photos are not supported.
- Guessed sensor types. An input's device class (motion, door, smoke) is guessed from its type and name. Change it in the entity settings if it is wrong.
- Removed inputs stay. Inputs that the panel no longer reports are not removed automatically. Delete their entities yourself.
- The cloud sees your app password. Like the app, the integration sends the panel's app password to the Pyronix Cloud inside TLS (see PROTOCOL.md §12).
- Unofficial. The protocol was worked out from the app. A Pyronix change to the cloud or the app could break the integration without notice.
Troubleshooting
Many errors appear in two places: as a message when setup or an action fails, and, for a poll, as "Failed to read the panel state (ErrorName)" in the log while the entities are unavailable. Both are listed below.
The panel rejected the System ID, app password or user code
Shown during setup (invalid_auth), or as a request to re-authenticate the integration
(auth_failed, AuthenticationError or AccessDeniedError).
- Check the details against the HomeControl2 app. The app password is set by your installer and is not your keypad code. The System ID is 8 characters.
- For an existing entry, Home Assistant shows a re-authentication prompt under Settings → Devices & services. Enter the correct app password and user code there.
- Do not try again and again. Repeated failed logins may lock the panel or raise a tamper alert.
The panel is busy with another remote session
panel_busy, or PanelBusyError in the log. Another client holds the panel's single remote
session, usually the HomeControl2 app, or another Home Assistant using persistent mode.
- Close the app (or log out of it) and wait a minute.
- Try again, or wait for the next poll.
- If this happens often, use on-demand mode everywhere, or a longer poll interval.
The panel is not connected to the Pyronix Cloud
panel_offline, or PanelOfflineError in the log. The cloud says the panel is not polling it.
- Straight after a session this can be the cloud's ~35-second pause. Home Assistant waits and tries again on its own; check whether the next poll works.
- If it persists, check that the app can reach the panel. If it cannot, check the panel's internet module (for example DIGI-WiFi or DIGI-LAN): power, network cable or Wi-Fi, and the router.
The panel's Pyronix Cloud subscription has expired
subscription_expired, or SubscriptionExpiredError in the log. Renew the subscription through
the app or your installer, then reload the integration.
Failed to connect to the Pyronix Cloud
cannot_connect, or CommunicationError, PyronixTimeoutError, ConnectionClosedError or
ProtocolError in the log. Home Assistant could not reach the cloud, or the session broke off.
Check Home Assistant's internet access and DNS, and that outgoing HTTPS (port 443) to
app.pyronixcloud.com is allowed. A single failure is usually temporary; the next poll or
reconnect tries again.
Arming fails: "area cannot be armed: reason"
arm_refused. The panel will not set the area: it is not ready, or it cancelled the set. The
reason is what the panel reports, for example "Landing DT Open".
- Close the door or window, or fix the fault, and arm again.
- Or use Force arm (or Always force arm) to omit open inputs. The panel can still cancel a forced set, for example because of a fault that cannot be omitted; the message then gives the panel's reason.
The panel did not confirm the command
command_not_confirmed. Home Assistant sent the arm or disarm, but the panel did not report the
change in time, or the connection dropped after the command went out. The command may still
have reached the panel.
- Check the panel's state first: wait for the next poll, or look at the keypad or the app.
- Only then decide whether to send the command again. Never repeat it blindly, and do not build automations that retry it in a loop.
The panel is already busy with another command
Another arm or disarm is still running. Wait for it to finish, then check the state before you send another.
The user code is not allowed to set or unset these areas
not_permitted. The keypad user code in the entry does not have rights to those areas. Ask your
installer or master user to give that user the areas, or reconfigure the entry with a user code
that has them. This arm mode is not available (mode_not_supported) means the level is not
in use, or the user code may not set it.
The PIN is missing or wrong / user or automations not allowed
invalid_code, user_not_allowed or automation_not_allowed. Home Assistant's own check refused
the call and sent nothing to the panel. Enter the PIN, send it as code from automations, or
change Who can arm and disarm in the options.
The panel session is not connected
not_connected. Persistent mode is reconnecting. Wait for it; the Connection state
diagnostic sensor (enable it first) shows when it is back.
Repair notice "Choose who can arm and disarm"
The entry was created before the access option existed, so anyone can arm and disarm. Open the options, choose an access rule and save.
The HomeControl2 app cannot log in
Persistent mode holds the panel's only remote session. Switch to on-demand mode, or accept that the app cannot be used while Home Assistant is connected.
Debug logs and diagnostics
To capture a debug log, open Settings → Devices & services → Pyronix Cloud, choose Enable debug
logging, reproduce the problem, then choose Disable debug logging to download the log. Or
add this to configuration.yaml and restart:
logger:
default: warning
logs:
custom_components.pyronix_cloud: debug
pyronix_cloud: debug
The integration never logs the app password, the user code or the PIN. Logs can still contain area and input names, so read them before you share them.
To download diagnostics, open the panel's device page and choose Download diagnostics. Credentials, the System ID, the site name, the PIN hash and the names of people in the panel state are redacted. Attach the diagnostics and the log to an issue.
Removing the integration
- Go to Settings → Devices & services → Pyronix Cloud, open the entry's menu (⋮) and choose Delete. Home Assistant says goodbye to the panel and closes the session. The stored credentials, the PIN hash and the entities go with the entry.
- If you installed with HACS, open HACS, find Pyronix Cloud, choose Remove from its menu,
and restart Home Assistant. For a manual install, delete
custom_components/pyronix_cloudfrom your configuration directory and restart. - Edit or delete automations and scripts that use its entities or
pyronix_cloud.force_arm.
Nothing is left on the panel: the integration changes no panel settings and installs nothing on it, so the HomeControl2 app works as before. Past sessions stay in the panel's event log under the device name you chose.
Development
Repository layout
PROTOCOL.md Reverse-engineered protocol specification
probe/ Stand-alone read-only protocol test script (step 1)
src/pyronix_cloud/ Async client library, no HA dependency (published as pyronix-cloud)
src/pyronix_cloud/testing/ Fake cloud relay + panel for offline tests and dev instances
custom_components/pyronix_cloud/ Home Assistant integration
tests/ Library tests; tests/integration/ holds the HA tests
apk/, decompiled/, reference/ Local-only reverse-engineering inputs (gitignored, never committed)
Roadmap
Probe: done; read-only live sessions answered most of PROTOCOL.md §13.Libraryandintegration: done; arming and disarming verified on a live Euro 46.- Outputs, input omit, the event log and PIR-camera photos.
Publishand list in the HACS default repository; later, HA core.pyronix-cloudto PyPI
Developing against the fake panel
uv run python -m pyronix_cloud.testing --port 8765
This serves a fake cloud relay and panel on ws://127.0.0.1:8765 and prints its test
credentials. In the config flow, open Advanced and set the cloud relay URL to it.
Trying the probe
cp .env.example .env # then fill in your panel details
# see probe/README.md for install and run instructions
.env is gitignored. Never commit credentials, captures or logs that contain them.
Contributing
See AGENTS.md for conventions, safety rules and the development workflow. These apply to human and AI contributors alike.
Licence
- The
pyronix_cloudlibrary, the probe and the documentation are licensed under the GNU LGPL v3.0 or later, which builds on the GNU GPL v3.0. - The Home Assistant integration (
custom_components/) is licensed under the Apache License 2.0.
Per-file licensing follows the REUSE specification (see REUSE.toml).
Legal
This project is for interoperability with hardware you own. The APK and decompiled sources are used locally for analysis and are never redistributed.
Metadata
Release files for pyronix-cloud 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pyronix_cloud-0.2.1.tar.gz | 168.4 kB | With provenance | Details for pyronix_cloud-0.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pyronix_cloud-0.2.1-py3-none-any.whl | Python 3 | none | any | Details for pyronix_cloud-0.2.1-py3-none-any.whl |
Total release size: 266.7 kB
Release files / pyronix_cloud-0.2.1.tar.gz
| Download URL | pyronix_cloud-0.2.1.tar.gz |
|---|---|
| Size | 168.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dca4306ab4598fe8744206f7d89267fe15b0f4b866565be78634ee906b0763b0
|
|
BLAKE2b-256 checksum How to use checksums |
6691037adcf9cabe69c1f60575a40d2a9908e467219d502d5af118b4daa62665
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.
Transparency logRelease files / pyronix_cloud-0.2.1-py3-none-any.whl
| Download URL | pyronix_cloud-0.2.1-py3-none-any.whl |
|---|---|
| Size | 98.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7258ebbeb1f5002364cf5deae6a35b5a9ff177a37979ef4d59f56e4c5523ddc1
|
|
BLAKE2b-256 checksum How to use checksums |
32a15bfd1bc77e7de72c1e508eb87822ad43904dd22bfbf6ba2372f819511110
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.
Transparency logSecurity for pyronix-cloud 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for pyronix_cloud-0.2.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.