Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Active Host Daemon

Overview

Active Host Daemon is a macOS utility that detects whether local or remote input is active and reports host changes to Home Assistant. It runs in the background as a per-user LaunchAgent and uses a Quartz event tap to observe local input.

The transfer gesture is Ctrl plus a deliberate movement to the active display's left edge. After the configured movement and dwell requirements are satisfied, the daemon selects the remote host. An active Screen Sharing connection also selects the remote host and takes priority over Quartz input events. Genuine local input returns control to the local host once Screen Sharing has disconnected; disconnecting alone leaves the remote host selected until fresh local input is observed.

Features

  • Native macOS Quartz input monitoring
  • Explicit local and remote host states
  • Multi-display left-edge detection
  • Standard and High Performance Screen Sharing detection with priority over local Quartz input
  • Home Assistant webhook notifications on host changes
  • Optional display wake when control returns from a Logitech Flow peer
  • Automatic startup and restart through launchd
  • Event-tap health watchdog and operational diagnostics
  • Install, start, stop, restart, status, and uninstall commands

Installation

Requirements:

  • macOS
  • Python 3.10 or newer
  • A Home Assistant webhook URL

Clone the repository, create its virtual environment, install dependencies, and run the installer:

cd /path/to/active-host-daemon
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
./install.sh

The installer renders the LaunchAgent with the repository's absolute path, writes it to ~/Library/LaunchAgents, creates ~/Library/Logs, and starts the daemon.

Configuration

Edit config.yaml before installation:

hosts:
  local: "macmini"
  remote: "laptop"

poll_interval: 1
screen_sharing_port: 5900

home_assistant:
  webhook: "http://home-assistant.local:8123/api/webhook/active_host"
  request_timeout: 10

logging:
  level: INFO
  • hosts.local is sent when local input is active.
  • hosts.remote is sent after a successful edge-transfer gesture.
  • poll_interval controls how frequently the daemon loop observes detector state.
  • screen_sharing_port is the base Screen Sharing port. Standard sessions use an established TCP connection; High Performance sessions use connected UDP sockets on this port and the next two ports.
  • home_assistant.webhook must be an absolute HTTP or HTTPS URL.
  • request_timeout is the webhook timeout in seconds.
  • display.wake_on_local enables display wake on a remote-to-local transition.
  • display.wake_duration controls how long caffeinate registers user activity.
  • logging.level accepts standard Python logging levels such as INFO or DEBUG.

Display wake is optional and disabled when the display section is omitted. To enable it, add:

display:
  wake_on_local: true
  wake_duration: 5

This is intended for Logitech Flow users whose destination Mac remains awake while its display has gone to sleep. When control returns from the remote host to the local Mac, the daemon runs /usr/bin/caffeinate -u -t 5 asynchronously to register user activity and wake the display. It never runs during a local-to-remote transfer.

Validate configuration without starting the detector:

.venv/bin/python active_host.py --check

Display the installed software version:

.venv/bin/python active_host.py --version

First Run

After ./install.sh, inspect the service:

./status.sh

The initial Home Assistant event is sent when the daemon first observes its host state. Subsequent events are sent only when the detected host changes. Payloads use this format:

{
  "host": "macmini",
  "source": "active-host-daemon",
  "timestamp": 1783856401
}

Permissions

The virtual-environment Python interpreter may require permission under:

System Settings
→ Privacy & Security
→ Accessibility

and, if requested:

System Settings
→ Privacy & Security
→ Input Monitoring

Grant access to .venv/bin/python from this repository. If permissions are granted after launch, restart the daemon:

./restart.sh

or:

launchctl kickstart -k gui/$(id -u)/uk.co.lailey.active-host-daemon

Updating

After updating the repository, refresh dependencies and reinstall the LaunchAgent so its rendered definition matches the current project:

git pull
.venv/bin/python -m pip install -r requirements.txt
./install.sh

The installer safely unloads an existing copy before loading the replacement.

Troubleshooting

Start with the formatted status report:

./status.sh

The primary logs are:

~/Library/Logs/active-host-daemon.log
~/Library/Logs/active-host-daemon-error.log

Follow them live with:

tail -f ~/Library/Logs/active-host-daemon.log
tail -f ~/Library/Logs/active-host-daemon-error.log

Common checks:

  • If the service is not installed, run ./install.sh.
  • If permission guidance appears, grant Accessibility and Input Monitoring access, then run ./restart.sh.
  • If configuration validation fails, correct config.yaml and restart.
  • If the webhook fails, verify its URL and confirm Home Assistant is reachable.
  • For detailed Quartz callback and health diagnostics, temporarily set the logging level to DEBUG, then restart the daemon.

LaunchAgent Commands

Inspect the launchd service directly:

launchctl print gui/$(id -u)/uk.co.lailey.active-host-daemon

Restart it directly:

launchctl kickstart -k gui/$(id -u)/uk.co.lailey.active-host-daemon

The installed plist is located at:

~/Library/LaunchAgents/uk.co.lailey.active-host-daemon.plist

Examples

Install or replace the LaunchAgent:

./install.sh

Start a stopped LaunchAgent:

./start.sh

Restart the daemon and immediately display its status:

./restart.sh

Stop the daemon without uninstalling it:

./stop.sh

Display service, process, path, permission, and recent-log information:

./status.sh

Unload the service and remove its installed plist while preserving logs:

./uninstall.sh

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages