Repository navigation
Technical Design Document: Crow AAP IP Module Integration
ARCHIVED - historical reference only. This page documents a superseded version of the integration and is no longer maintained. For current documentation see the Home page and the HA 2026.09 Development Branch page. Full index: Archived Documentation. Here is the comprehensive Technical Design & Function Documentation for the Crow/AAP IP Module Integration. This document serves as a reference for developers and advanced users to understand the internal architecture, design decisions, and function logic.
This integration follows the Local Push architecture. It establishes a persistent TCP socket connection to the alarm hardware using the pycrowipmodule library.
- Hardware: The Crow IP Module sends ASCII strings over TCP.
-
Library (
pycrowipmodule): Runs in a background thread, parses the ASCII strings into a state dictionary (system_state,zone_state,area_state). -
Callbacks: When state changes, the library triggers a callback function defined in
__init__.py. -
Thread Bridge: Since the library callback runs in a worker thread,
hass.loop.call_soon_threadsafeis used to marshall the data back to the main Home Assistant Event Loop. -
Dispatcher: The
async_dispatcher_sendsignal broadcasts the data. - Entities: Individual entities (Sensors, Alarm Panel) listen to these signals and update their state in Home Assistant.
Design Pattern: Multi-step Wizard with State Persistence.
Instead of a single large form, the setup is split into 4 steps to handle the complexity of configuring 16 zones and multiple partitions.
CrowConfigFlowClass:-
async_step_user: Entry point. Immediately redirects to the first configuration step. -
async_step_areas: Collects names and codes for Area A and Area B. Stores them inself.areas_config. -
async_step_outputs: Collects names for Output 3 and 4 (the switchable outputs). Stores inself.outputs_config. -
async_step_zones: A loop generates 16 fields for naming. Usesvol.In(ZONE_TYPES)to render a Dropdown menu for Zone Types. Stores inself.zones_config. -
async_step_connection: Collects IP, Port, and Timeout. This is the final step where:
- Data from all previous steps is merged.
-
CONF_AREAS,CONF_ZONES, andCONF_OUTPUTSare stored in theoptionsdictionary of the config entry (making them mutable). - Connection details (
CONF_HOST) are stored in thedatadictionary (immutable). - Uniqueness is verified (
_abort_if_unique_id_configured).
CrowOptionsFlowHandlerClass:- Allows re-configuration of names and types after installation.
-
Robustness Logic: Uses
.get(key) or {}extensively to prevent500 Internal Server Errorsif the existing configuration is incomplete or corrupted.
Design Pattern: Async Wrapper & Signal Dispatching.
This file bridges the synchronous/threaded nature of the external library with the asynchronous nature of Home Assistant.
-
async_setup_entry(hass, entry):
- Initializes the
CrowIPAlarmPanelcontroller. -
The Thread-Safe Wrapper (
_thread_safe_send):
-
Problem: The Crow library fires callbacks from a background thread. Calling HA functions directly causes
Fatal error: protocol.data_received(). - Solution: ```python def _thread_safe_send(signal, data): hass.loop.call_soon_threadsafe(async_dispatcher_send, hass, signal, data)
This forces the execution onto the main HA event loop.
- Non-Blocking Start:
-
Problem: Connecting to the alarm might take time or timeout (60s+), causing
Bootstrap stage 2 timeout. -
Solution:
hass.async_add_executor_job(controller.start)is called without await. This fires the connection process in the background, allowing HA to finish booting immediately.
Design Pattern: State Machine & Command Sequencing.
-
CrowAlarmPanelClass: -
Keypad Logic:
-
code_formatreturnsCodeFormat.NUMBERalways, ensuring the keypad is visible. -
code_arm_requiredreturnsFalseif a default code is configured. This creates a hybrid mode: The user can type a code, but doesn't have to. -
Arming Logic (
async_alarm_arm_...): -
Crow systems require a specific sequence: Send Command (
arm_stay) -> Send Code (keypress). -
The function splits this into two network calls.
-
State Mapping: Maps the raw boolean flags from the library (
armed,stay_armed,exit_delay) to HA enums (AlarmControlPanelState.ARMED_AWAY, etc.).
Design Pattern: Inheritance & Logic Inversion.
-
CrowBaseEntityClass: -
Base class for all binary sensors.
-
Handles
device_infoto link entities to the device registry. -
Stores
self._hostlocally to avoidAttributeErrorif the controller object doesn't expose the IP. -
CrowSystemStatusSensorClass (Diagnostic): -
Handles system flags like Mains, Battery, Tamper.
-
Logic Inversion:
-
Battery: Library sends
Truefor OK. HA expectsOnfor Problem. Logic:return not val. -
Tamper: Library sends
Truefor Closed. HA expectsOnfor Open. Logic:return not val. -
Mains: Library sends
Truefor OK. HA expectsOnfor Power Present. Logic:return val. -
Categorized as
EntityCategory.DIAGNOSTICso they appear in a separate section in the UI.
Design Pattern: Optimistic Updates.
-
CrowOutput: Represents the switchable outputs (3 & 4). -
Uses optimistic state updating (
self.async_write_ha_state()) immediately after sending a command to provide instant UI feedback, while waiting for the real confirmation callback from the panel. -
CrowRelay: Represents hardware relays (1 & 2). -
Modeled as momentary switches (State is always
False). Turning them "On" sends a pulse and immediately resets.
The configuration is stored in JSON format within Home Assistant's storage (.storage/core.config_entries).
{
"options": {
"areas": {
"1": { "name": "House", "code": "1234", "code_arm_required": true },
"2": { "name": "Garage", "code": "", "code_arm_required": true }
},
"zones": {
"1": { "name": "Front Door", "type": "door" },
"2": { "name": "Living Room", "type": "motion" }
// ... up to 16
},
"outputs": {
"3": { "name": "Gate" },
"4": { "name": "Light" }
}
}
}
These strings are used by the async_dispatcher_send to route data to the correct entities:
| Signal String | Payload Data | Listener |
|---|---|---|
crowipmodule.zones_updated |
Zone ID | Updates binary_sensor (Zones) |
crowipmodule.areas_updated |
Area ID | Updates alarm_control_panel
|
crowipmodule.system_updated |
Full State Dict | Updates sensor (Status) & binary_sensor (Diagnostic) |
crowipmodule.output_updated |
Output ID | Updates switch
|
-
Library:
pycrowipmodule >= 0.32 - Protocol: ASCII based Telnet-style communication.
-
Home Assistant APIs:
config_entries,core,helpers.dispatcher,helpers.entity,voluptuous.