A modern Python library for the Crow Cloud API - Next Generation
Project description
Crow Security NG
A modern, async Python library for the Crow Cloud API — Next Generation.
Provides a clean, type-hinted interface for interacting with Crow Shepherd alarm panels
through the Crow Cloud API at api.crowcloud.xyz.
Features
- Fully async — built on
aiohttpfor efficient async I/O - Type hints — complete type annotations for better IDE support
- Modern Python — requires Python 3.10+, uses dataclasses and enums
- Proper error handling — dedicated exception classes for different error types
- MAC address normalization — accepts any MAC format (with/without separators)
- WebSocket support — real-time updates from your alarm panel
- Backwards compatible — provides a
Sessionclass compatible with the originalcrow_security - Token refresh — automatic OAuth2 token refresh with fallback to full re-login
- Context managers — proper resource cleanup with async context managers
Installation
pip install crow_security_ng
Authentication
The library uses OAuth2 Resource Owner Password Credentials (ROPC) against
https://api.crowcloud.xyz/o/token/. Application credentials (CLIENT_ID and
CLIENT_SECRET) are embedded in the library — you only need your Crow Cloud
email and password.
The access token is sent as Authorization: Bearer {token} on every request.
The library refreshes expired tokens automatically.
Quick Start
Basic Usage
import asyncio
from crow_security_ng import Session
async def main():
async with Session("your-email@example.com", "your-password") as session:
panel = await session.get_panel("AABBCCDDEEFF")
print(f"Panel: {panel.name} (id={panel.id})")
areas = await panel.get_areas()
for area in areas:
print(f" Area: {area.name}, State: {area.state.value}")
zones = await panel.get_zones()
for zone in zones:
print(f" Zone: {zone.name}, Open: {zone.is_open}")
asyncio.run(main())
Advanced Client Usage
import asyncio
from crow_security_ng import CrowClient
async def main():
async with CrowClient(email="email@example.com", password="password") as client:
panels = await client.get_panels()
panel = panels[0]
print(f"Panel: {panel.name}, id={panel.id}, mac={panel.mac}")
# Sub-resources use the numeric panel.id — not the MAC
areas = await client.get_areas(panel.id)
zones = await client.get_zones(panel.id)
outputs = await client.get_outputs(panel.id)
# Arm an area (sends X-Crow-CP-Remote header automatically via Panel.set_area_state)
area = await panel.set_area_state(areas[0].id, "arm")
print(f"Armed: {area.is_armed}")
# Control an output
await client.set_output_state(
panel.id, outputs[0].id, True,
remote_password=panel.remote_access_password,
)
asyncio.run(main())
WebSocket Real-time Updates
import asyncio
from crow_security_ng import Session
async def handle_message(msg: dict):
print(f"Event: {msg}")
async def main():
async with Session("email@example.com", "password") as session:
panel = await session.get_panel("AABBCCDDEEFF")
# Runs indefinitely, calling handle_message for every event
await session.ws_connect(panel.mac, handle_message)
asyncio.run(main())
API Reference
Session
Simple interface compatible with the original crow_security library.
session = Session(email, password)
panel = await session.get_panel(mac) # MAC in any format
panels = await session.get_panels()
await session.ws_connect(mac, callback)
await session.close()
CrowClient
Full access to all API features.
client = CrowClient(
email="...",
password="...",
timeout=30, # optional, default 30 s
)
All sub-resource methods take the numeric panel ID (not MAC):
await client.get_areas(panel_id)
await client.get_area(panel_id, area_id)
await client.set_area_state(panel_id, area_id, state, force=False,
remote_password=..., user_code=...)
await client.get_zones(panel_id)
await client.get_zone(panel_id, zone_id)
await client.set_zone_bypass(panel_id, zone_id, bypass,
remote_password=..., user_code=...)
await client.get_outputs(panel_id)
await client.get_output(panel_id, output_id)
await client.set_output_state(panel_id, output_id, state,
remote_password=..., user_code=...)
await client.get_measurements(panel_id)
await client.get_zone_pictures(panel_id, zone_id)
await client.capture_picture(panel_id, zone_id, remote_password=..., user_code=...)
await client.download_picture(picture, "/path/to/file.jpg")
Models
Panel
panel.mac # 12-char hex MAC (lookup + WebSocket subscribe)
panel.id # numeric database ID (sub-resource URLs)
panel.name
panel.remote_access_password # → X-Crow-CP-Remote header
panel.user_code # → X-Crow-CP-User header (may be None)
panel.firmware_version
Panel also exposes convenience delegation methods:
areas = await panel.get_areas()
await panel.set_area_state(area_id, "arm")
zones = await panel.get_zones()
await panel.set_zone_bypass(zone_id, True)
outputs = await panel.get_outputs()
await panel.set_output_state(output_id, True)
measurements = await panel.get_measurements()
pictures = await panel.get_zone_pictures(zone_id)
await panel.capture_picture(zone_id)
Area
area.id
area.name
area.state # AreaState enum
area.is_armed # True if ARMED or STAY_ARMED
area.is_arming # True if ARM_IN_PROGRESS or STAY_ARM_IN_PROGRESS
area.exit_delay
area.ready_to_arm
area.zone_alarm
Zone
zone.id
zone.name
zone.state # bool — True = open/triggered
zone.bypass # True if bypassed
zone.battery_low # True if low battery
zone.tamper_alarm
zone.zone_type # int (55 = smart cam)
zone.is_open # True if state or active
zone.has_low_battery
Output
output.id
output.name
output.state # bool — True = on
output.tamper_alarm
output.battery_low
Measurement
measurement.device_id
measurement.dect_interface # 32533=temp, 32532=humidity, 32535=pressure, 61=gas
measurement.temperature # °C (raw API value ÷ 1000)
measurement.humidity # %RH (raw API value ÷ 1000)
measurement.air_pressure # atm (raw API value ÷ 1000)
measurement.gas_level # 0-4 scale
Picture
picture.id
picture.zone # zone ID
picture.zone_name
picture.url # pre-signed download URL (no auth needed)
picture.picture_type # 0 = manual, 1 = alarm-triggered
picture.created # datetime
Exceptions
from crow_security_ng import (
CrowError, # Base exception
AuthenticationError, # OAuth2 login failed / credentials rejected
ConnectionError, # Network-level failure
ResponseError, # Unexpected HTTP error (status_code, response_text attrs)
PanelNotFoundError, # Panel MAC not found (mac attr)
RateLimitError, # HTTP 429 (retry_after attr)
TimeoutError, # Request timed out
InvalidMacError, # Malformed MAC address (mac attr)
WebSocketError, # WebSocket auth or subscribe failure
)
Migrating from crow_security
Change your import — everything else stays the same:
# Before
import crow_security as crow
session = crow.Session(email, password)
# After
from crow_security_ng import Session
session = Session(email, password)
Key differences
| crow_security 0.3.0 | crow_security_ng | |
|---|---|---|
| Return types | Raw dict |
Typed dataclass objects |
panel.id |
Present | Present — used for all sub-resource URLs |
Zone.state |
Mixed | bool (True = open) |
| Exceptions | CrowLoginError, ResponseError |
Richer hierarchy |
| Type hints | None | Full Python 3.10+ annotations |
| Token refresh | Manual | Automatic on 401 |
| Context manager | Partial (bug in __aexit__) |
Full async context manager |
| Python version | 3.2+ | 3.10+ |
Backward-compatibility aliases are provided so existing exception handlers continue to work:
CrowSecurityError→CrowErrorCrowSecurityAuthenticationError→AuthenticationErrorCrowSecurityConnectionError→ConnectionErrorCrowSecurityClient→CrowClient
Home Assistant Integration
This library is designed to work with the Crow Shepherd Home Assistant integration.
License
MIT License — see LICENSE for details.
Credits
- Inspired by the original crow_security library by Shprota
- Thanks to the Crow Group for the Shepherd alarm system
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file crow_security_ng-0.1.9.tar.gz.
File metadata
- Download URL: crow_security_ng-0.1.9.tar.gz
- Upload date:
- Size: 24.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ac7aa8129c5b8641f5f471e8844264a75c113c11efca0382c3da775ce550a82
|
|
| MD5 |
61565d055575042665f0395db2b0d429
|
|
| BLAKE2b-256 |
7ea1b8c9d7896695afcf61129cced028d6d4405ba104c7cfebb430d8ebc5f9f6
|
File details
Details for the file crow_security_ng-0.1.9-py3-none-any.whl.
File metadata
- Download URL: crow_security_ng-0.1.9-py3-none-any.whl
- Upload date:
- Size: 19.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
00f00b80eb1b1e529243ecf32c17691dc1b17589b7c60c492aaf7ea062e1398f
|
|
| MD5 |
6f5ccadbabba714b812b1958e195e9b6
|
|
| BLAKE2b-256 |
fe0f2ea64a1e2c9ed3c7e550da742d2f5a878b232cc34d94f9dc98afadcfbd03
|