Skip to content

Repository files navigation

Aegis for Ajax — Home Assistant Integration

HACS Custom GitHub Release Tests Validate with hassfest HACS Validation License: MIT Code style: ruff

Disclaimer: This is an unofficial third-party integration and is not affiliated with, endorsed by, or supported by Ajax Systems. Use at your own risk. This integration communicates with Ajax Systems servers using the same protocol as the official mobile app. Ajax Systems may change their API at any time, which could break this integration without notice.

Aegis is a Home Assistant custom integration for Ajax Security Systems — works with any co-branded Ajax app (Protegim, ADT, G4S, and many more).

Communicates via gRPC (the same protocol the official mobile app uses). No Enterprise API key required — just your regular account credentials.

How It Works

Ajax Systems provides co-branded versions of their mobile app to security companies worldwide. Each co-branded app connects to the same Ajax cloud backend but uses a unique application label to identify itself. This integration emulates the mobile app's gRPC protocol, so it works with any co-branded variant.

You need to know the application label of your Ajax provider. This is an internal identifier that the app sends to the Ajax cloud (see the Known App Labels table below). If you use the main Ajax app, the label is Ajax.

Features

  • Alarm Control Panel: Arm away, disarm, night mode, group arming with PIN code support. When the space is in group / zone mode, per-group panels are created and react to FCM push events instantly — arming or disarming a single group from the Ajax mobile app reflects in HA within seconds (whole-space transitions already worked this way; group-level transitions joined in 1.5.0). Each group panel also lists which devices belong to that group, in its member_device_ids and member_device_names attributes — Ajax group membership is otherwise only visible in the mobile app, and it is a separate taxonomy from rooms (a device has both, independently). Works with Alexa via Home Assistant Cloud (see Arm modes & voice assistants). Optionally shows the hub's exit / entry delays as arming / pending, driven by the hub's own signals (1.18.0, off by default — see Exit and entry delays)
  • Force Arm Services: aegis_ajax.force_arm and aegis_ajax.force_arm_night to arm ignoring open sensors
  • Binary Sensors: Door open/close, motion detection, smoke, steam (FireProtect 2 chamber discriminator), leak, tamper, CO, heat, glass break, vibration, tilt (DoorProtect Plus accelerometer), CRA monitoring status, cellular connection, lid tamper, external contact alert (wired reed switches on DoorProtect/Hub Hybrid inputs), external contact fault, MultiTransmitter wired-input alert with alarm category, ethernet link, Wi-Fi link, mains power
  • Hub Network: Real-time hub network data — ethernet/wifi/gsm connection status, Wi-Fi SSID and signal strength, IP addressing, cellular signal strength and network type, power supply status
  • Sensors: Battery level, temperature, humidity, CO2, signal strength, GSM type (2G/3G/4G), Wi-Fi signal level, Wi-Fi SSID, Wi-Fi IP, IMEI, Ethernet IP/gateway/DNS, cellular signal/network, connection type
  • Electrical readings for WallSwitch / Socket family devices: live current draw (A), measured line voltage (V) when the firmware reports it, cumulative electric energy consumed (kWh, wired into HA's Energy dashboard via state_class=total_increasing), and instantaneous power (W). Power is a direct firmware reading on the Outlet Type E / F family and a derived current × measured voltage reading (opt-in, with a 230 V nominal fallback) on the WallSwitch family. Updates arrive on the hub's push channel; a per-hub 60 s STATUS refresh fills the gap on device families whose firmware emits live deltas sparsely (Outlet Type E / F). The sensors also persist across HA restarts so a constant load like a fixed-speed pump doesn't render as unknown after a reboot until the next state change.
  • Manual hub refresh button: one button.<hub>_refresh_hub per configured hub. Pressing it (or calling button.press from an automation) forces an immediate STATUS refresh from the hub — useful after toggling an appliance, when waiting for the next 60 s periodic tick would feel sluggish. Rate-limited to one press per 60 s per hub so a stuck automation can't generate unusual traffic against Ajax's servers.
  • Switches: Relays, wall switches, sockets (multi-channel support) — turn on/off via DeviceCommandDeviceOn / DeviceCommandDeviceOff gRPC services
  • Lights: Dimmers with absolute brightness control via DeviceCommandBrightness
  • Locks: Ajax SmartLock and LockBridge (Yale) — lock and unlock. Hub-attached Jeweller locks (e.g. installer-added Yale modules) are commanded over the generic device on/off path. Unlatch (lock.open) isn't exposed: it requires Ajax's cloud SmartLock service, which the hub-attached locks seen so far aren't registered with — the Ajax app can't unlatch them either
  • Hub Chime switch: a per-hub Chime switch toggles the hub-wide chime — the tone the hub plays when a monitored door/window opens while disarmed (the Ajax app's bottom-left toggle). Only created for hubs that expose the feature, and requires the account's chime-edit permission. Changes made from the Ajax app are reflected in Home Assistant immediately.
  • Valves: Ajax WaterStop and WaterStop Fibra surface as native valve.* entities reflecting WaterStopChannel.state (open / closed), is_transitioning, and a stuck attribute pulled from the channel-level MALFUNCTION_IS_STUCK. Open and close are supported — the valve can be controlled from Home Assistant and automations
  • Siren settings: HomeSiren / StreetSiren devices expose two config entities — a Siren volume select (Very loud / Loud / Quiet / Disabled) and an Alarm duration number (seconds) — read from and written back to the same settings the Ajax app shows. Writing requires an account with device-edit permission; a successful write triggers a targeted re-read so the entity confirms the hub's actual value within seconds
  • Hub firmware update (read-only): each hub exposes an update.<hub>_firmware entity that reports the firmware version the hub is actually running as its installed version — also shown under Firmware on the hub's device page — and whether Ajax has queued an update against it, with download progress when the cloud is pushing bytes. No install button is exposed on purpose — firmware updates remain Ajax-scheduled and the entity is informational. Hubs whose firmware doesn't report the running version behave as before (queued-update info only).
  • Per-device firmware update (read-only): each non-hub device gets an update.<device>_firmware counterpart sourced from the same read-only snapshot, surfacing the queued target version, download progress and a security-critical flag. Disabled by default (a typical install has 10-30 devices) — enable the ones you want to watch
  • Persistent notifications (optional): an option that surfaces selected security events as Home Assistant persistent notifications that stay visible until dismissed, as a built-in alternative to wiring your own persistent_notification.create automation. The event set is configurable and defaults to real incidents (alarm, panic, tamper, fire, CO, flood, glass break). Off by default; requires FCM push
  • Cameras: MotionCam alarm-photo sequences in HA, plus on-demand captures on PhOD models
  • Photo Storage: Captured photos saved to /media/ajax_photos/ with timestamp overlay, configurable retention
  • Media Browser: Browse captured photos per device via HA Media Browser
  • Event Platform: Security events from FCM push notifications (alarm, arm/disarm, tamper, panic, fire, flood, motion, and more)
  • Device automation triggers: every Ajax security event is a named device trigger on the hub device, selectable directly in the HA automation editor (no manual event-type strings)
  • Doorbell events: video-edge doorbells get a per-device event entity emitting HA's canonical ring event, and a doorbell motion push turns the doorbell's motion sensor on (30 s auto-off)
  • Button presses: an Ajax Button in control mode gets a per-device event entity that fires pressed — no push (FCM) needed, and it works while the system is armed or disarmed
  • Per-device bypass switches: each non-hub device can get a bypass switch to deactivate / reactivate it; gated by the bypass_switches option (auto / always / never). The switch reads on for a device deactivated anywhere — from Home Assistant, the Ajax app, or by an installer — and its deactivation_kinds attribute names the mode in force. Mind Ajax's own wording: temporary_deactivation_* is the permanent deactivation (until you re-enable it), one_time_deactivation_* lasts a single arming cycle, and a *_tamper variant means only the device's tamper protection is off. Both directions work from Home Assistant: switch on applies the same permanent deactivation the Ajax app does, switch off puts the device back under protection — and the integration re-reads the device after every write, so the switch never shows a state the hardware isn't in (#338)
  • Device removal follows the panel: deleting a device in the Ajax app removes it from Home Assistant within seconds — entities, device card and cache. Deletions that happen while Home Assistant is offline are picked up on the next reconnect: the device stops claiming state and its leftover card can be removed from its device page (Delete device — offered for any device the hub no longer reports; live devices are refused and a mistaken deletion re-creates itself from the next snapshot) (#422)
  • Logbook: Human-readable security event descriptions with icons
  • Real-time updates: Persistent gRPC stream for instant sensor state changes (< 1 second latency)
  • Push notifications: FCM integration for immediate event delivery
  • 2FA support (TOTP)
  • Reauth flow: when the Ajax session is rejected (password rotated, 2FA newly enabled, server-side logout), HA shows the orange "Reconfigure" banner with a guided password prompt — entity ids, areas, automations and history survive untouched
  • HA Repairs: diagnosable conditions surface as cards under Settings → Repairs instead of being buried in home-assistant.log — hub offline > 24h, sustained HTS reconnect failure, FCM credentials rejected (with one-click fix flow), a push connection repeatedly killed by an unreadable message (the integration renews its own push registration to recover), a push registration that Ajax accepted and that has never delivered anything, or grpcio version below the floor on Home Assistant OS
  • System Health card: one-line snapshot under Settings → System → Repairs → System Information with gRPC reachability, HTS / FCM connection ratios, last push / last poll ages — replaces log archaeology as the first triage step
  • DHCP discovery: Ajax hubs on the same LAN appear as a "Discovered" card in Settings → Devices & Services, no need to search by name
  • MDI icons for all entity types
  • Automation Blueprints: Ready-to-use automation templates (see below)

Requirements

  • Home Assistant 2025.11.0 or later — older cores pin grpcio below the version this integration needs, so installing on them fails outright (see Supported versions)
  • An Ajax Security account (email + password)
  • At least one Ajax hub online
  • The application label of your co-branded Ajax app

Installation

HACS (Recommended)

Open HACS Repository

Click the button above, or manually:

  1. Open HACS in Home Assistant
  2. Click the three dots menu (top right) and select Custom repositories
  3. Add https://github.com/bvis/aegis-hass with category Integration
  4. Search for "Aegis for Ajax" in HACS and click Install
  5. Restart Home Assistant
  6. Add the integration:

Add Integration

Manual

  1. Download this repository
  2. Copy custom_components/aegis_ajax/ to your Home Assistant config/custom_components/ directory
  3. Restart Home Assistant
  4. Go to Settings > Devices & Services > Add Integration and search for "Aegis for Ajax"

Configuration

  1. Enter your Ajax account email and password
  2. Enter the App Label of your co-branded app (see table below, or type your own)
  3. If 2FA is enabled, enter your TOTP code
  4. Select which spaces (hubs) to add
  5. Done

Recommended: use a dedicated Ajax account, separate from the one on your phone. Instead of your primary admin login, create a separate Ajax account, invite it to your space (Ajax app → space → Users → Invite) and grant it only what the integration needs. A non-admin User role is enough to read device state and arm / disarm — but to also receive push events, the role's notifications toggle is not enough: Ajax filters event delivery server-side by permission level, and a User role with notifications turned on still receives zero events (#234, #319); in practice the account needs admin / full access (see the FCM troubleshooting note below). You can also revoke its photo / video access if you don't use Photo on Demand or alarm photos, so Home Assistant never has access to camera images. This keeps your main credentials out of HA and limits what a compromised HA host could reach in your Ajax installation.

This also matters for real-time updates. Running the same Ajax account in both your phone app and Home Assistant can prevent instant push notifications from reaching HA — real-time event notifications (alarm, doorbell, motion and other sensor events) would then not reach HA reliably. Giving HA its own account avoids this contention. (Arm / disarm panel state still follows within ~1 s via the hub's status channel, with or without push.)

Trade-offs to know: without photo / video permission the MotionCam Photo-on-Demand button won't work, and per-device bypass switches need the account to hold the device-deactivation (DEVICE_EDIT) permission — the default bypass_switches: auto simply won't create them for an account that lacks it. As a safety net, the integration re-reads the device a few seconds after every bypass write and logs a warning when the panel disagrees, so the switch never shows a state the hardware isn't in.

Options

After setup, configure these in Settings > Devices & Services > Aegis for Ajax > Configure:

Option Default Description
Poll interval 300s Fallback polling interval, allowed range 60-300 seconds (real-time stream handles most updates)
Force arm disabled Arm ignoring open sensors and malfunctions (bypasses hub safety checks)
Show "Arm Home" button enabled Whether the alarm panel advertises Arm Home. It duplicates Ajax's single partial (Night) mode and exists mainly so the Nabu Casa / Alexa skill discovers the panel. Disable to hide the redundant button if you don't use Alexa / Home Assistant Cloud — Arm Away and Arm Night are unaffected.
Show exit / entry delays as panel states disabled Shows the hub's per-detector Delay when leaving as the panel's arming state and Delay when entering as pending, driven by the hub's own signals. Opt-in because automations waiting for armed_away then fire once the exit delay completes. See Exit and entry delays.
PIN code disabled Require PIN for arm/disarm from HA UI
FCM credentials Firebase credentials for push notifications (optional)
I don't use push notifications disabled Enable if you intentionally run without push. Hides the recurring "FCM not configured" reminder and Repair card (and the WARNING log). Real-time events (doorbell, arm/disarm, alarm) still won't reach Home Assistant until you configure FCM — this only silences the reminder.
Photo retention (days) 30 How many days to keep captured photos (1-365)
Max photos per device 100 Maximum photos stored per camera (0 = unlimited)
Auto-create labels enabled Create and assign aegis_* labels (camera, hub, door, motion, …) to your entities for easy grouping in dashboards/automations. Disable if you prefer to manage labels manually — with the option enabled the integration re-creates the labels on every restart.
Bypass switches auto Whether to create a bypass switch per device. auto only creates them if your Ajax account has the DEVICE_EDIT permission (required to deactivate devices); always creates them unconditionally; never skips them. Switching to auto or never removes the bypass switches the integration had created; no manual clean-up is needed.
Show security events as persistent notifications disabled Surfaces selected security events as Home Assistant persistent notifications that stay in the notification drawer until dismissed. See the next row for which events.
Events that create persistent notifications alarm, panic, tamper, fire, CO alarm, flood, glass break Multi-select over every event type the integration emits. Arm/disarm and motion are left out by default so the drawer only carries real incidents.
Clear FCM credentials disabled One-shot: tick it and save to drop the stored push credentials. It resets itself after saving.

Known App Labels

Each co-branded Ajax app uses an internal label name to identify itself to the Ajax cloud. This label is not always the same as the app's display name. The integration includes all known labels in a dropdown during setup.

App Label App Name Region
Ajax Ajax Security System Worldwide
ajax_pro Ajax PRO Worldwide
AIKO AIKO Estonia
3dAlarma 3D Alarma Spain
E-Pro E-Pro
G4S_SHIELDalarm G4S SHIELDalarm Europe
GSS_Home GSSecurity
HomeSecure HomeSecure
Hus_Smart Hus Smart Scandinavia
Novus_alarm Novus
Protegim_alarma Protegim Spain
Protecta Protecta
SecureAjax SecureAjax
Smart_Secure Smart & Secure
Verux Verux
Videotech_alarm Videotech
kale_alarm_x Kale Alarm X Turkey
ADT_Alarm ADT Alarm
ADT_Secure ADT Secure
Yoigo_ADT_Alarma Yoigo ADT Alarma Spain
Masmovil_ADT_Alarma Másmóvil ADT Alarma Spain
Euskaltel_ADT_Alarma Euskaltel ADT Alarma Spain
Elotec Elotec Ajax Norway
Yavir Yavir Ukraine
Oryggi Oryggi Iceland
acacio acacio
esahome esahome

How to find your app label

If your provider is not in the list above, you can find the correct label by:

  1. Check the app's Google Play URL — search for the package name (e.g. com.ajaxsystems.yourapp) and cross-reference with the table
  2. Check the app's resources — the label is stored as ajax_app_name in strings.xml

You can type any custom label during setup if yours is not listed.

Supported Devices

Type Devices Entities
Hub Hub, Hub Plus, Hub 4G, Hub Lite, Hub 2, Hub 2 Plus, Hub 2 4G, Hub 2 LTE (RTK), Hub 3, Hub Hybrid (2 / 4G), Hub Mega, Hub Void 4G, Hub Fibra, Hub Yavir / Yavir Plus, Hub Fire, Hub Superior Alarm panel, battery, GSM type/connected, CRA monitoring status, CRA company (diagnostic), lid tamper, IMEI, hub network sensors (Ethernet/Wi-Fi/GSM, IP data, cellular signal/network, mains power)
Door Sensors DoorProtect, DoorProtect Plus, DoorProtect Fibra, DoorProtect S, DoorProtect S Plus, DoorProtect Plus Fibra, DoorProtect Plus G3 Fibra, DoorProtect G3 Door open/close, tamper, vibration (Plus), tilt (Plus, accelerometer), battery, temperature, signal, external contact alert (wired contact triggered), external contact fault (wiring broken)
Motion Sensors MotionProtect, MotionProtect Plus, MotionProtect Outdoor, MotionProtect Curtain (and outdoor / mini / plus base variants), MotionProtect S / S Plus, MotionProtect G3 family (incl. Fibra), MotionProtect Plus Fibra / G3 Motion detected (real-time), tamper, battery, temperature, signal
Cameras MotionCam, MotionCam Outdoor, MotionCam Fibra (& base), MotionCam G3, MotionCam HD, MotionCam PhOD, MotionCam PhOD Fibra, MotionCam Outdoor PhOD, MotionCam Outdoor 2/4 PhOD, MotionCam S PhOD (& AM), MotionCam Superior PhOD, MotionCam Video (& Indoor) Motion detected, tamper, battery on all. Camera entity, photo-on-demand capture and alarm albums on MotionCam PhOD, MotionCam PhOD Fibra, MotionCam Outdoor PhOD, MotionCam Outdoor 2/4 PhOD and MotionCam Fibra base — the families confirmed on real hardware. MotionCam G3, HD, S PhOD (& AM), Superior PhOD and Video have no camera or capture entity yet: each needs one owner to confirm the Ajax app offers Photo on demand for it, see #472. Internal temperature on MotionCam Outdoor PhOD (confirmed on hardware)
Glass Break GlassProtect, GlassProtect S, GlassProtect Fibra Glass break detection, tamper, battery
Combi CombiProtect, CombiProtect S, CombiProtect Fibra Motion, glass break, tamper, battery
Fire/Smoke FireProtect, FireProtect Plus, FireProtect 2 (all sub-models — heat-only *hrb/*hsb, CO-only *crb/*csb, multi-sensor *hcrb/*hcsb, AC-powered *_ac, UL-listed *_ul) Smoke, steam (FireProtect 2 only — chamber discriminator), CO, high temperature, tamper, battery — sub-models without a given sensor expose only the relevant entity
Water Leak LeaksProtect Leak detected, tamper, battery
Air Quality LifeQuality Temperature (°C), humidity (%), CO₂ (ppm), battery, signal
Relays/Switches Relay, WallSwitch, Socket (and outlet variants) On/off per channel; electrical readings (current, voltage, energy) across the WallSwitch / Socket family. Power is exposed as a direct reading on the Outlet Type E / F family (the firmware reports it natively) and as a derived current × voltage reading on the WallSwitch family. The dry-contact Relay switches a potential-free contact and has no load metering — its Voltage sensor reports the module's own supply voltage (~12 V on a 12 V PSU), and Current / Energy read 0 by design.
Light switches LightSwitch (Jeweller / Fibra) On/off per channel
Lights LightSwitch Dimmer Brightness control
Locks SmartLock, LockBridge (Yale) Lock and unlock; state surfaces locked / unlocked. Hub-attached Jeweller locks (e.g. installer-added Yale modules on a third-party backend) are commanded over the generic device on/off path (#206 / #219). Note: unlatch (lock.open) isn't exposed on these — it's only available through Ajax's cloud SmartLock service, which they aren't registered with (the Ajax app can't unlatch them either)
Hub Chime Hubs that expose the chime setting switch.<hub>_chime toggles the hub-wide chime tone (door-open alert while disarmed); reflects app-side changes instantly. Requires the account's chime-edit permission
Doorbells MotionCam Video Doorbell, NVR-bridged video doorbell doorbell_pressed on the hub's security event entity, plus a per-device event entity (device_class: doorbell) that emits Home Assistant's canonical ring event; a doorbell motion push also flips the doorbell's motion_detected on (30 s auto-off). Requires FCM credentials configured. Note: the video doorbell has no photo capture in Home Assistant. For live view, if the doorbell is bridged through an Ajax NVR you can reach its stream over ONVIF — see Video cameras (ONVIF / RTSP).
Keypads Keypad, KeypadPlus, KeypadCombi, KeypadTouchscreen, KeypadOutdoor Battery, tamper, temperature, signal
Buttons Button (Jeweller) In panic mode, panic on the hub's security event entity (requires FCM). In control mode, a per-device event entity (device_class: button) that fires pressed on every press — this one rides the hub's status channel, so it works without FCM. Short and long click are indistinguishable in everything the hub reports, so there is one event rather than two. The DoubleButton is panic-only and reports nothing in control mode
Keyfobs (experimental) SpaceControl, SpaceControl S Grouped under a single Keyfobs device, with one Active binary sensor per keyfob (diagnostic). The active/inactive value is experimental and not yet confirmed — see Keyfobs (experimental). Who armed/disarmed via a keyfob already appears in the logbook regardless
Sirens HomeSiren, HomeSiren S, HomeSiren Fibra, HomeSiren G3, StreetSiren, StreetSiren S, StreetSiren Plus, StreetSiren Plus Fibra/G3, StreetSiren Fibra, StreetSiren Double Deck (& S / Fibra) Battery, tamper, signal; siren volume (select) and alarm duration (number) on every model except StreetSiren Plus, whose settings the hub does not report; internal temperature on the HomeSiren family and on StreetSiren, StreetSiren Plus G3 and the Double Deck variants — not on StreetSiren S, StreetSiren Plus, StreetSiren Fibra or StreetSiren Plus Fibra
Range extenders ReX, ReX 2, ReX 2 Fire Battery, signal; ReX 2 Fire adds smoke, high temperature and tamper
Wired-Input Modules MultiTransmitter, MultiTransmitter Fibra, Hub Hybrid wired inputs Tamper of the module itself; each registered wired sensor appears as its own device with an alert binary sensor and an alarm_type attribute (intrusion / fire / glass_break / vibration / …)

Siren temperature matches the value shown in the Ajax app and updates live over the hub's push channel (it moves in ~1 °C steps, as in the app). Earlier versions sourced it from the siren's internal board sensor, which read a few degrees high on a sun-exposed StreetSiren and refreshed only every 15 minutes; since 1.12.1 it reads the same internal-temperature value the app shows (#312).

Photo on Demand

MotionCam PhOD (Photo on Demand) models support capturing photos remotely:

  1. Press the "Capture photo" button entity in HA
  2. The hub triggers the camera, and the photo URL is retrieved via the Ajax notification system
  3. The photo is downloaded, a timestamp overlay is burned into the image, and it's saved to /media/ajax_photos/{device_name}/
  4. View photos in the camera entity or browse all captures via Media Browser → Ajax Security Photos

Note: Regular MotionCam models (without PhOD) do not support on-demand photo capture. The button entity is only created for PhOD models.

Photos are automatically cleaned up based on your retention settings (configurable in integration options).

Alarm photos in Media Source

MotionCam models, including PhOD, can display photos attached to real alarms. This does not trigger a new capture: regular MotionCam models still have no on-demand capture button. The camera entity shows the latest alarm's contact sheet (one, two or three frames, depending on the camera configuration); a newer PhOD capture can also update that entity. Historical imports never replace a newer preview.

Open Media Browser → Ajax Security Photos → device → alarm album to browse each sequence. Albums are saved under /media/ajax_photos/{device_name}/YYYY-MM-DD_HH-MM-SS-ffffff/, using the alarm's timestamp in Home Assistant's timezone, with numbered frames (01.jpg, 02.jpg, 03.jpg) and preview.jpg. The device's last.jpg is the latest preview. PhOD captures remain separate files named YYYY-MM-DD_HH-MM-SS-ffffff.jpg; microseconds avoid same-second collisions. Retention removes whole expired albums as well as old captures.

New camera-alarm pushes add one Ajax gRPC streamNotificationMedia call using the notification and hub IDs from the push. That same stream waits for pending frames to finish; it never queries history or reopens the stream. Completed local albums are skipped, including after restart. Existing PhOD capture behavior is unchanged.

For missed events, call aegis_ajax.refresh_alarm_images manually. Per space, each invocation adds one findNotifications query against the Alarm folder (up to 50 events) and at most 10 media streams, skipping completed local albums before opening a stream. A five-minute per-space cooldown rejects repeated calls before any network request. Both paths also download available frames using their signed image URLs. There is no periodic history polling; unavailable or incomplete sequences can be recovered with a later manual backfill.

Video cameras (ONVIF / RTSP)

Ajax video hardware (the NVR and the IP cameras / doorbell channels bridged through it) exposes a local ONVIF/RTSP service. This integration does not stream or proxy that video itself — instead it reads the connection details so you can point Home Assistant's built-in ONVIF integration at each camera and get a real camera entity with live view.

Local network only. The stream goes straight from Home Assistant to the camera/NVR on your LAN — it never travels through the Ajax cloud. Home Assistant must be on the same network (or reachable to it over a VPN). There is no cloud/remote live view.

Steps:

  1. Enable ONVIF in the Ajax app for the NVR (and/or each camera). It's off by default. Create an ONVIF username and password there — Home Assistant will need them, and the integration never sees them.

  2. Add the ONVIF integration in Home Assistant (Settings → Devices & services → Add Integration → ONVIF). Home Assistant usually auto-discovers the Ajax cameras on your LAN, so you can just pick the discovered device and enter the ONVIF user/password from step 1 — no need to type the IP. Home Assistant then creates the camera entity with live view.

  3. If a camera isn't auto-discovered (or to verify the connection details), get its IP and ports from the integration diagnostics: Settings → Devices & services → Aegis for Ajax → ⋮ → Download diagnostics, under the video_edge_onvif_rtsp section. Each VideoEdge lists:

    • network → the camera's LAN ip (and mac)
    • onvif.http_port → the ONVIF port (typically 8080)
    • rtsp.http_port → the RTSP port (typically 8554)
    • onvif.user_auth_enabledtrue once you've created an ONVIF user (if false, finish step 1 first)

    Then add the ONVIF integration manually with that IP, the ONVIF port (8080), and the ONVIF user/password.

That's it — from there the camera behaves like any other ONVIF camera in Home Assistant (live view, snapshots, recording, use in automations), while Aegis keeps providing the device's motion/tamper sensors and the doorbell ring event.

If your Home Assistant can't reach the camera on its LAN IP, ONVIF discovery will fail — this is a network reachability issue, not an integration one. As a fallback you can also point the Generic Camera integration at the RTSP stream directly (port 8554).

Person / vehicle / pet detection

Ajax cameras that classify what they see publish those detections as ONVIF events, and Home Assistant's ONVIF integration turns them into binary_sensor entities of their own — separate from the plain motion sensor this integration provides. If your camera offers object detection in the Ajax app, enable it there and the matching sensors appear alongside the camera entity.

That combination is worth knowing about, because it answers something the Ajax app cannot: those sensors fire regardless of whether the system is armed, so an automation can notify you about someone in the garden while you are at home and disarmed — using this integration's alarm panel and space entities as the condition, and the ONVIF detection as the trigger.

If you would rather not depend on the camera's own classifier, Frigate and similar NVR software can consume the same RTSP stream (port 8554) and do the detection themselves, with the same result in Home Assistant.

Custom Services

Service Description
aegis_ajax.force_arm Arm the system ignoring open sensors and active alarms. Supports entity target to arm a specific panel.
aegis_ajax.force_arm_night Arm night mode ignoring open sensors and active alarms. Supports entity target to arm a specific panel.
aegis_ajax.disarm_night_mode Exit night mode while leaving any independently armed (away) groups armed — the native Ajax "disarm night mode" operation. Unlike a panel-level disarm (which stands the whole space down), this only disarms the night-mode groups. Supports entity target; if omitted, applies to all panels.
aegis_ajax.set_photo_on_demand_mode Enable/disable Photo on Demand mode on a hub: user (hub users may request photos from the app) and/or scenario (scenarios/automations may trigger captures). Target a space via entity_id; leave a field unset to keep its current value.
aegis_ajax.refresh_alarm_images Import recent alarm-photo albums without triggering a capture. Target an alarm panel with entity_id, or omit it for all spaces. One history query + at most 10 media streams per space, once per five minutes; completed albums are skipped.
aegis_ajax.press_panic_button ⚠️ SOS / panic button. See dedicated section below before using.
aegis_ajax.list_client_sessions Return the sessions Ajax holds for the account (device model, OS, client version, app label, created / expires), with the integration's own session marked is_current. On-demand only — the endpoint rate-limits repeated calls.
aegis_ajax.terminate_client_session Log one selected device out of the Ajax account. Requires an explicit confirmation flag and refuses to touch the integration's own session.
aegis_ajax.terminate_other_client_sessions Log every other device out of the Ajax account, keeping this integration's session. Same confirmation flag; reports how many sessions it terminated if the endpoint stops it part way.

Both force_arm services accept an optional entity_id target (alarm control panel entity). If no target is specified, all panels across all configured accounts are armed.

Arm modes & voice assistants (Alexa via Home Assistant Cloud)

Ajax has a single partial-arm mode (the app calls it Night mode) plus full arm. The panel exposes Arm Away (full arm) and both Arm Home and Arm Night for that one partial mode — so "Arm Home" and "Arm Night" do the same thing and both settle the panel to armed_night. "Arm Home" is advertised mainly so the Nabu Casa / Alexa skill discovers the panel (it won't discover a panel that exposes Night without Home).

If you don't use Alexa / Home Assistant Cloud, the Arm Home button on the Lovelace alarm card is a redundant duplicate of Arm Night. Turn off the Show "Arm Home" button option (Configure) to hide it; Arm Away and Arm Night stay available.

Notes for Alexa:

  • The skill only exposes a panel that does not require a code to arm. If you enable the PIN option (use_pin_code), the panel won't be discovered by Alexa.
  • Alexa requests a PIN only on disarm, and only supports a 4-digit numeric code — Ajax PINs longer than 4 digits won't work for voice disarm.
  • When a PIN is configured, the panel reports code_format: number, which also makes the Home Assistant Lovelace alarm card render a numeric keypad.
  • A bare "Alexa, arm <name>" arms Home, not Away. This is Alexa's own default for an unqualified "arm" (it requests Armed Stay / Home), and since Arm Home maps to Ajax's partial mode the panel ends up partially armed. Home Assistant only forwards the mode Alexa asks for — the integration can't change Alexa's default. To arm fully: say "Alexa, arm <name> in away mode", or create an Alexa Routine that maps your phrase (e.g. "arm the house") to the action set panel → Armed Away.

Exit and entry delays (arming / pending)

Ajax runs the Delay when leaving and Delay when entering you configure per detector inside the hub: the moment you arm, the hub reports armed, and the delay only decides when the delayed detectors start raising alarms. So by default the panel goes straight from disarmed to armed_away — the one-second arming you may see is the Ajax app's own arm confirmation, not the detector delay (#443).

The hub does report both ends of the delay on the always-on status channel the integration already keeps open, so with the Show exit / entry delays as panel states option (Configure, off by default) the panel adds two states driven by those signals, never by a timer of ours:

Panel state Starts Ends
arming The space is seen arming (app, keypad, keyfob or Home Assistant) and at least one of its detectors has a "Delay when leaving" The hub reports the exit delay complete; disarm; alarm. As a safety net the longest configured delay bounds it, so a missed hub frame can't leave the panel stuck
pending The hub reports an entry delay started (a delayed detector triggered while armed) The expiry the hub announced with it; disarm; alarm (triggered always wins)

What the states mean, plainly: during arming only the detectors with a delay are still quiet — detectors in Instant Alarm mode are already live, so the state describes the exit route, not the whole system. pending means someone is inside the entry delay: disarm before it runs out or the hub raises the alarm.

With the option on, the panel also carries three attributes: hub_state (the state as the hub reports it, without the overlay), exit_delay_seconds (the longest "Delay when leaving" among the space's detectors) and delay_ends_at (the expected end of the running delay, or null). Nothing is persisted: after a restart the panel shows the hub's plain state until the next arm. Night mode shows arming only for detectors whose delays are set to apply in night mode; per-group panels are not covered yet.

Panic button (SOS)

The integration exposes the same panic button that the official Ajax mobile app does. It calls the underlying SpaceService/pressPanicButton endpoint.

⚠️ READ THIS BEFORE USING IT — FALSE PANIC ALARMS HAVE LEGAL AND FINANCIAL CONSEQUENCES.

Pressing the panic button forwards a Panic / Hold-up alarm to your monitoring station (CRA). On most professional monitoring contracts this means immediate police dispatch with no verification window — the operator is not allowed to call you back to confirm. False activations may result in fines, breach of your monitoring contract, and in some jurisdictions criminal liability.

Use this service only for genuine emergencies. Do not wire it to noisy automations such as "trigger when my NVR detects motion" — for that case, route the trigger through a hardware path (e.g. an Ajax Transmitter Fibra connected to a relay controlled from HA), so the hub's normal alarm engine and verification rules apply.

What it does (controlled by hub configuration):

  • Always fires regardless of whether the system is armed or disarmed.
  • Triggers a panic_button_pressed event on the hub (mapped to event type panic on the integration's security event entity).
  • Forwards the panic to the monitoring station.
  • Optionally activates sirens depending on the hub setting panic_siren_on_panic_button.

Whether sirens sound is decided entirely by the hub — the panic request carries no siren field, so the integration cannot influence it. To see what your hub will do, enable the diagnostic binary sensors Siren on panic button and Siren on tamper on the hub device (disabled by default). They are read-only mirrors of the hub configuration; changing the behaviour is done in the Ajax app, and a change made there becomes visible after the integration reloads.

Service: aegis_ajax.press_panic_button

Field Required Description
confirm Yes (must be true) Safety lock. The service refuses to run unless explicitly set to true to prevent accidental triggers from automations.
entity_id No Alarm panel entity for the space whose panic button to press. If omitted, the panic is sent to every configured space.
latitude No Optional caller latitude forwarded to Ajax. Use together with longitude.
longitude No Optional caller longitude forwarded to Ajax. Use together with latitude.

Example:

service: aegis_ajax.press_panic_button
target:
  entity_id: alarm_control_panel.aegis_home
data:
  confirm: true

Example Dashboard

An example Lovelace dashboard is included in docs/dashboard.yaml with sections for:

  • Alarm control panel + system status, with the exit / entry delay card (hub state, exit delay, countdown to the end of a running delay — needs the option described in Exit and entry delays)
  • Hub network (Ethernet, Wi-Fi, cellular, power)
  • Door & window sensors with batteries
  • Cameras & motion detectors with photo capture buttons
  • Temperature overview with 24h history
  • Tamper, connectivity, and problem diagnostics
  • Alarm, door, window, motion, and hub connectivity history

To use it, copy the YAML into a new dashboard view in Settings → Dashboards → Edit → Add View → YAML mode, and replace the example entity IDs with your own.

An example automations file is also available with 24 automation examples covering common security scenarios.

Entity Details

Hub sensors

  • CRA connection — binary sensor showing whether the space has at least one approved monitoring company (CRA)
  • CRA company — disabled-by-default diagnostic sensor showing the approved monitoring company name; returns multiple if more than one approved CRA is attached
  • Cellular connected — binary sensor for GSM/4G connection status
  • GSM type — sensor showing connection type (2G/3G/4G)
  • Hub network sensors — Ethernet/Wi-Fi connectivity, Wi-Fi SSID/signal, Ethernet/Wi-Fi IP addressing, cellular signal/network, and mains power status
  • Siren on panic button / Siren on tamper — disabled-by-default diagnostic binary sensors mirroring the hub's siren behaviour settings (read-only; configured in the Ajax app, refreshed on integration reload)
  • Delay when leaving — disabled-by-default diagnostic binary sensor on door, motion and combi detectors and MotionCams, mirroring whether the detector has an exit delay configured in the Ajax app (read-only). The delay itself can surface as the panel's arming / pending state with the Show exit / entry delays option
  • Lid opened — tamper detection for the hub enclosure
  • Battery — hub battery level
  • IMEI — hub cellular modem identifier

Note on hub network sensors: These entities are backed by the HTS connection. If HTS is unavailable or reconnecting, they may temporarily become unavailable instead of showing stale data.

Real-time event sensors

Door open/close and motion detection are transient events — they appear when the event occurs and clear automatically. The integration uses a persistent gRPC stream for instant delivery (typically < 1 second latency).

Note on motion detection: Ajax motion sensors only report motion events when the system is armed. This is a firmware-level behavior — when disarmed, motion detectors are inactive for battery conservation.

Security event entity

Each hub has a Security event entity that fires events from FCM push notifications: alarm, arm/disarm, tamper, panic, fire, flood, motion, glass break, CO, and more. Use these in automations to trigger actions on security events.

Each event includes enriched data attributes:

Attribute Description Example
raw_tag Original protobuf event tag intrusion_alarm, door_opened
transition Event transition state triggered, restored
device_name Name of the device that triggered the event Front Door, Hallway Cam
device_id Hex ID of the source device A1B2C3D4
device_type Type enum of the event's source. For arm/disarm this names what performed the action: a person (SPACE_MEMBER), a keyfob (SPACE_CONTROL), a keypad (KEYBOARD) or a scenario DOOR_PROTECT, SPACE_MEMBER
room_name Room the device is assigned to (when available) Kitchen, Entrance

Use these in automation templates, e.g. {{ trigger.event.data.device_name }}.

Security sensors

  • Case tamper — physical manipulation of device enclosure
  • Device problem — device malfunction or communication issue
  • Glass break — glass break detection (GlassProtect, CombiProtect)
  • Vibration — vibration/shock detection (DoorProtect Plus)
  • Tilt — accelerometer tilt / device removed from wall (DoorProtect Plus family)
  • Steam — chamber-level steam vs. smoke discriminator (FireProtect 2 with smoke chamber). Lets automations distinguish a real fire from cooking/shower steam false positives
  • External contact alert — triggered state of an externally wired contact (e.g. reed switch on a window) connected to a DoorProtect's input terminals; toggles open/closed
  • External contact fault — circuit-fault indicator for the same external wiring (cable disconnect or short)
  • Wire input alert — triggered state of a third-party sensor wired into a MultiTransmitter or a Hub Hybrid wire input. Exposes an alarm_type attribute reflecting the category Ajax assigned to that input (intrusion, fire, glass_break, vibration, etc.). Available on the wire_input, wire_input_mt, wire_input_rs and transmitter device types

Keyfobs (experimental)

SpaceControl keyfobs are grouped under a single Keyfobs device (one per hub), with one Active binary sensor per keyfob, named after it (using the keyfob name set in the Ajax app).

Not every hub produces these sensors, and that is expected. Some hubs report the keyfob as an ordinary device instead, in which case it gets its own device page — with the usual bypass switch, which already shows whether it is deactivated — and no Active sensor. The Keyfobs device only appears on hubs that report their keyfobs solely over the status channel.

The active/inactive state is experimental and not yet confirmed. On every install that produces the sensor each keyfob reports as active, and a keyfob can only be deactivated server-side by an installer or monitoring company, so there has been no inactive example to validate against — the sensor may not yet reflect a genuinely deactivated keyfob. The Ajax app's forced deactivation on a keyfob is a different mechanism (it is the same temporary exclusion as the bypass switch) and does not produce that example.

You can help finalize it: if you have a keyfob that your installer/CRA has deactivated, a Download diagnostics (Settings → Devices & Services → Aegis for Ajax → ⋮ → Download diagnostics) plus a debug log (custom_components.aegis_ajax: debug) attached to a GitHub issue would let us confirm the indicator and get it right. See Help Wanted.

Who armed or disarmed the system with a keyfob already appears in the logbook ("Disarmed (via …)") and on the hub's security event entity — that's independent of these sensors.

Automation Blueprints

Aegis includes 8 ready-to-use automation blueprints. Import them via URL in Settings → Automations → Blueprints → Import Blueprint:

Blueprint Description Import URL
Security Event Notification Push notification with emoji-labeled event type, device name and room. Optional inputs for a tap-through dashboard URL and for translating/customising the per-event-type labels. Ignores stale events on reload. Import
Intrusion Alarm + Capture Capture all cameras and send critical notification when intrusion alarm fires Import
Tamper Alert Critical notification when device tampering is detected Import
Door Opened While Armed Preventive alert when a door opens with the alarm armed, with optional warning script Import
Nobody Home Remind Arm Notification when nobody is home and the alarm is disarmed, with optional TTS Import
Remind Arm with TTS Push + voice announcement when someone is home and alarm is disarmed Import
Low Battery Weekly Weekly summary of devices with battery below threshold Import
Connectivity Loss Escalation Progressive alerts on hub connectivity loss (warning → critical → restored) Import

You can also manually copy the blueprint files from custom_components/aegis_ajax/blueprints/automation/ to your config/blueprints/automation/aegis_ajax/ directory.

Note: Blueprints are templates — existing automations created from them are not updated automatically. After updating the integration, delete and re-import the blueprint in Settings → Automations → Blueprints to get the latest version, then recreate the automation.

Troubleshooting

Problem Solution
"Invalid credentials" Verify email/password work in your Ajax app
"Cannot connect" Check internet connection; Ajax servers may be down
Hub shows offline Verify hub has internet in your Ajax app
2FA code rejected Ensure your device clock is synchronized
Unexpected errors Verify your app label matches your co-branded app exactly
Motion/door not updating Check that the gRPC stream is connected (look for "Device stream started" in logs)
Sensors unavailable after reload Use full HA restart instead of integration reload (gRPC streams require restart)
Photo capture button missing Only MotionCam PhOD models support on-demand capture
Arm fails with "malfunctions detected" Open sensors or low batteries prevent arming. Enable Force arm in Options, or use the aegis_ajax.force_arm service. The error message lists the blocking devices.
Disarm not working Check HA logs for specific error; ensure the system is armed before disarming

Data Sources by Protocol

This integration uses three communication channels. Each entity type depends on a specific protocol:

Protocol Entities Transport Notes
gRPC stream Door open/close, motion, tamper, connectivity, problem, battery, temperature, signal, alarm panel state, switches, lights mobile-gw.prod.ajax.systems:443 Persistent stream, < 1s latency. Case tampering is dual-sourced: some hubs report it here, others only over HTS (see below)
gRPC space snapshot CRA connection, CRA company, room metadata Same server One-shot SpaceService/stream snapshot read at startup / refresh time, then cached between polls
gRPC request Arm/disarm, force arm, photo capture trigger Same server On-demand commands
HTS Ethernet (IP, gateway, DNS), Wi-Fi (SSID, signal, IP), cellular (signal, network), mains power, connection type, per-device internal temperature (sirens, MotionProtect Curtain / Outdoor, MotionCam Outdoor PhoD), case tampering (families confirmed on hardware only — #406), keyfob activity, exit / entry delay events and per-detector delay settings (the opt-in arming / pending panel states, #454) hts.prod.ajax.systems:443 Proprietary binary protocol over TCP+TLS
FCM push Security events (alarm, arm/disarm, tamper, panic, fire, flood, motion, door_open, etc.), photo URL retrieval Firebase Cloud Messaging Requires FCM credentials (configured in Options)

If a specific group of sensors stops working:

  • Door/motion/battery unavailable → gRPC stream disconnected (check logs for "Device stream started")
  • Hub network sensors unavailable → HTS connection lost (auto-reconnects on next poll cycle)
  • Security events not firing → FCM not configured or push client not started (check logs for "FCM push client started")
  • Arm/disarm fails → gRPC request issue (check logs for specific error)

Roadmap

  • Video stream support (VideoEdge / NVR) — cameras bridged through an Ajax NVR expose a local ONVIF/RTSP service; the integration surfaces their IP + ports so you can use Home Assistant's native ONVIF integration for live view. See Video cameras (ONVIF / RTSP). Native/proxied streaming and the radio MotionCam Video family (not behind an NVR) are still open
  • Valve platform — bidirectional control. Read-only valve entity shipped in 1.3.0; open / close added in 1.12.0 over the generic device on/off command path
  • Number/Select platforms for device settings — siren volume and alarm duration shipped in 1.15.0 (#310), read and written over the hub's per-device update path. Other settings (detector sensitivity, LED brightness, alert thresholds) are still open and need captures from people running that hardware
  • SpaceControl (keyfob) detection — keyfobs surface as a Keyfobs device with an experimental per-keyfob active sensor (1.10.0); the active/inactive value still awaits confirmation from a deactivated-keyfob log (#311). (Who armed/disarmed via a keyfob was already attributed in the logbook.)

Help Wanted

This integration covers the hardware I personally own and can validate against a live hub. Anything beyond that — the video stream from cameras, less common device families, or features I don't have on my own install — depends on input from people who do own that hardware. There's no realistic way for me to extend coverage to devices I can't try myself.

Areas where the integration could grow with community input:

  • Video streaming — cameras behind an Ajax NVR already have a live-view path via Home Assistant's native ONVIF integration (guide). Still open: the radio MotionCam Video family that isn't bridged through an NVR, and any in-integration (proxied) streaming.
  • A deactivated SpaceControl keyfob — keyfobs now appear as a Keyfobs device with an experimental per-keyfob Active sensor (1.10.0), but the active/inactive value is unconfirmed because every keyfob seen so far is active. It has to be one your installer or monitoring company deactivated: the app's own forced deactivation is a different, temporary mechanism and doesn't produce the example. A diagnostics dump + debug log would let us finalize the indicator — see #311.
  • Device settings beyond sirens — siren volume and alarm duration are covered since 1.15.0 (#310); detector sensitivity, LED brightness and alert thresholds still need captures from owners of that hardware.
  • Co-branded apps the integration doesn't yet recognise in the App Label dropdown.
  • Any new device family that shows up in the snapshot without entities.

If you own any of these and would like it covered, open an issue on the tracker describing what you have and what's missing. Diagnostics dumps and debug logs from your install (Settings → Devices & Services → Aegis for Ajax → ⋮ → Download diagnostics, plus custom_components.aegis_ajax: debug in the logger config when relevant) are usually the most useful starting point — we can iterate over beta releases against your hardware until it works. Without that kind of involvement from people running the affected hardware, the integration can only cover what I personally use.

Push Notifications (Optional, but strongly recommended)

The integration can run with or without Firebase Cloud Messaging (FCM) push, but the two configurations behave very differently:

Behaviour With FCM Without FCM
Arm / disarm / night-mode state in the alarm panel Real-time (push) Near-real-time (~1 s) — the hub emits a status event over its always-on channel that the integration uses to re-read the state, for both the space and per-group panels; the poll is the backstop
Exit / entry delay panel states (arming / pending, opt-in) From the hub's always-on status channel Same — the delay events don't ride push at all
Event entity firings (alarm, tamper, panic, doorbell ring, fire / smoke, CO, flood, glass break, motion, door open, battery low, connection lost, malfunction) Real-time Never — these only ride the FCM channel
Photo-on-Demand URL retrieval (snapshot pulls) Available Not available
Device sensor state (temperature, signal strength, open / closed contacts, …) Real-time (gRPC stream) Real-time (gRPC stream)
Hub network info, SIM info, room / space topology Polled Polled

If you cannot configure FCM, the integration still works as a polled view of your Ajax installation, but automations that rely on alarm-panel events will not fire. You can dismiss the FCM not configured Repair card and it stays dismissed across restarts — the integration will not break and won't keep re-raising the card on every reboot. The WARNING line under Settings → System → Logs is the only remaining reminder.

You can enter the four FCM values later from either place — no need to remove and re-add the integration:

  • Settings → Devices & Services → Aegis for Ajax → Configure (the Options flow), or
  • the FCM not configured Repair card under Settings → Repairs (it opens the same four-field form).

Once entered, the values are stored on the config entry and persist across restarts; you should only ever need to enter them once. See The four values for where to obtain each one.

FCM shows connected but app → HA updates still don't arrive? Two common causes:

  • Same account in the app and in HA. Ajax doesn't reliably deliver one account's push to two sessions at once, so an actively-used phone app can leave HA's push channel starved even though FCM reports connected. Give HA its own account (see Configuration).
  • The HA account's role is below the level Ajax delivers events to. Ajax gates event delivery server-side by the account's permission level, not by the notifications toggle — an invited User role with notifications turned on still registers for push fine yet receives zero events (#234, #319). In practice, switching the HA account to admin / full access is what unlocks delivery. The exact minimum permission is unknown; if you find a narrower combination that still receives events, please report it on the tracker so this can document a least-privilege setup.

Either way you'd still get changes on the next poll, just not instantly.

Alternative to FCM: Ajax's SIA stream. If you'd rather not extract Firebase credentials at all, many Ajax hubs can stream events to Home Assistant's built-in SIA integration (set up a monitoring-station / SIA receiver on the hub pointing at HA's SIA server). SIA is read-only and instant, so a clean setup is to use SIA for live status (arm / disarm / alarm) and Aegis for sending commands (arm, disarm, bypass, panic, switches, locks) — in which case you can skip the FCM setup entirely and dismiss its Repair card. Aegis still streams device sensor state over gRPC either way; SIA just covers the alarm-panel events that would otherwise rely on FCM.

The four values

Configured in the integration's Options flow (Settings → Devices & Services → Aegis for Ajax → Configure) and stored securely in config entry data:

  • FCM Project ID
  • FCM App ID
  • FCM API Key
  • FCM Sender ID

All four belong to the same Firebase project — the one your Ajax mobile app uses for its own push notifications. The integration registers with that project as an additional FCM client, so it needs the same four values the app already carries.

These four values are app-wide identifiers, not per-user secrets — every installation of the same Ajax build (or co-branded variant) uses the same four values, and they identify the Firebase project the app talks to rather than any individual account. The project still doesn't ship them for you because (a) the values differ per co-branded variant — Ajax, Protegim, AIKO, etc. each have their own — and (b) project policy keeps third-party identifiers out of our repository regardless.

Where the values live

Three of the four are stored in the Android APK's resource file at res/values/strings.xml. Note that Android compiles resource XML to a binary format before packaging, so simply renaming the APK to .zip and extracting it will give you unreadable bytes for that file — you'll want a standard Android resource viewer like apktool to read it back into plain text.

Use apktool ≥ 2.9. Recent Ajax builds set the resource package id to 128 instead of the usual 127. Older apktool versions (e.g. the 2.7 shipped by some Linux distributions) can't decode that and produce a near-empty strings.xml (just a handful of unrelated entries). If your extracted strings.xml looks empty, grab a current apktool from apktool.org/docs/install and re-extract.

Once readable, three of the four values appear as named entries:

  • project_id — short slug, e.g. my-firebase-project-id (kebab-case, no spaces)
  • gcm_defaultSenderId — pure digit string (~12 digits, no prefix); the same digits that appear between the first two colons of google_app_id
  • google_app_id1:<sender_id>:android:<hex tail> (starts with 1:, followed by the sender digits, the literal :android:, and a hex string whose length varies by Firebase project — current Ajax builds ship a 16-char tail; Firebase's own canonical example is also 16)

The fourth, google_api_key, is not in strings.xml (the entry there is a placeholder string); it ships inside the native library bundled with the APK at lib/<arch>/libnative-lib.so. The value starts with AIza and is exactly 39 characters long, so it's easy to spot when scanning printable strings out of the binary.

If you downloaded the APK as a .xapk split bundle, the native library does NOT live inside the base com.ajaxsystems.apk — it ships in one of the architecture-specific config splits (config.armeabi_v7a.apk / config.arm64_v8a.apk). Unpack the XAPK first, then unpack the matching architecture split, then read lib/<arch>/libnative-lib.so from there.

Watch out — the native library typically contains more than one AIza… string. Google Cloud SDKs share the same key format across services, and an Ajax APK can ship a separate key for FCM, another for ML Kit, and so on; only the FCM-scoped one is what Firebase Installations accepts. There is no label next to the keys to tell them apart. The pragmatic recipe is to list every match (strings libnative-lib.so | grep -oE 'AIza[A-Za-z0-9_-]+' | sort -u) and try each one through the integration's Repair flow until registration succeeds. If you get Push notifications disabled — FCM credentials rejected by Google with the warning text mentioning API_KEY_ANDROID_APP_BLOCKED, that's the signal you've picked a non-FCM key — pull the next candidate from the list and retry.

Using the Ajax app on iPhone? The iOS build ships these values in GoogleService-Info.plist inside the signed .ipa bundle, which is encrypted and unreadable without a jailbroken device. The Firebase project is identical on both platforms, so extract the four values from the Android APK regardless of which OS you use day-to-day — pulled from the Android build, they work for FCM push delivery on a Home Assistant install on any phone OS.

Sanity-check before submitting

Two quick consistency checks that catch the most common "credentials rejected" reports:

  1. fcm_sender_id must equal the digit chunk between the first two colons of fcm_app_id. Example: if fcm_app_id = 1:608123456502:android:…, then fcm_sender_id is 608123456502. If they don't match, those two values came from different Firebase projects.
  2. All four values must come as a coherent set from one Firebase project — not picked individually from different sources.

If submission still fails

Since 1.6.0 the integration also runs the same shape checks above as a pre-flight before contacting Google. When something is structurally off (e.g. fcm_sender_id doesn't match the digit chunk in fcm_app_id), a Push notifications disabled — FCM credentials malformed Repair card appears with the specific problem named, and the values aren't sent to Firebase at all. That's faster and clearer than Google's opaque 403.

When everything is accepted and push still never arrives

FCM credentials can pass every checkpoint — the offline shape checks, Firebase minting a token, Ajax's own UpsertPushToken, and an MCS session that connects and heartbeats indefinitely — and still never carry a single message. Nothing looks broken, because the alarm panel never depends on push; the only symptom is that real-time events (doorbell rings, intrusion alarms) silently never happen, which is hard to notice without a baseline.

Since 1.20.0 the integration detects this. The hub's own status stream carries the same space events push does, about a second apart on a healthy install, so Aegis counts arm/disarm-class events seen while the push client was up. Once 20 of those have gone by with no push ever delivered for the credentials in force, a Push notifications are not arriving Repair card appears under Settings → Repairs. The count is persisted against a fingerprint of the four values, so it survives restarts and resets by construction when you re-enter them; the card clears itself the moment one push arrives. A quiet installation never trips it, since a house that generates no events generates no evidence either.

The card names the three causes and deliberately does not pick one, because they are indistinguishable from inside Home Assistant: values belonging to a Firebase project your co-branded app's push provider does not route through, another registration holding your Ajax account's push destination, or a push connection that never actually completed. The diagnostics dump carries the same numbers under push if you would rather read them directly, including the event count that makes a zero delivery count meaningful.

If the shape checks pass and Google still rejects, the WARNING line under Settings → System → Logs names the specific cause (project consistency, app-id format, or network reach to Google's FCM hosts). Re-enter the four values together via the Repair card under Settings → Repairs once you have a coherent set.

If you cannot obtain a coherent set, leaving FCM unconfigured is a fully supported (degraded) configuration — device sensors and a polled view of the alarm panel still work.

Translations

The integration is available in 15 languages: English, Spanish, Catalan, German, French, Italian, Dutch, Polish, Portuguese, Brazilian Portuguese, Romanian, Turkish, Ukrainian, Czech, and Danish.

Not all of them were written by native speakers. Some locales, or parts of them, were produced with non-human translation systems and then checked against the vocabulary already in the file, not against a native ear. Contributors have since reviewed or rewritten several languages (Italian, Dutch, Ukrainian, Danish and Spanish among them), but the rest may still read stiffly or use a term the Ajax app itself renders differently. If something in your language is wrong, awkward, or not what the Ajax app says, please tell us: open an issue quoting the string and the wording you would expect, or send a pull request that touches only custom_components/aegis_ajax/translations/<lang>.json. Values only, keys unchanged; a test pins key parity with strings.json, so a stray key edit fails CI rather than breaking the UI. Corrections to a single string are as welcome as a full review.

Support

This integration is free and open source, and stays that way — every feature is available to everyone. If it's useful to you and you'd like to support the time that goes into maintaining it, you can buy me a coffee ☕. Entirely optional and always appreciated.

The most valuable contribution, though, is a good bug report or a wire capture from hardware I can't test against — that's what moves the integration forward.

Legal Notice

This integration is provided for personal, non-commercial use and for interoperability purposes as permitted under applicable law (including EU Directive 2009/24/EC on the legal protection of computer programs).

  • This project is not affiliated with Ajax Systems in any way
  • Ajax Systems trademarks and product names belong to their respective owners
  • The protobuf definitions included in this integration were derived from publicly available mobile applications for interoperability purposes
  • No warranty is provided — this software is provided "as is"
  • The authors are not responsible for any damage, data loss, or security issues arising from the use of this integration
  • By using this integration, you accept full responsibility for its use with your Ajax security system

License

MIT

About

Aegis — Unofficial Home Assistant integration for Ajax Security Systems and co-branded apps

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

116 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages