Skip to main content

aw-watcher-lid

ActivityWatch watcher for laptop lid events and system suspend/resume tracking.

Disclaimer

This project was made using the Claude AI service heavily. This time no code reviews utilizing "Natural Human Stupidity" has been made. NHS has been applied to some of the documentation and some testing efforts.

Overview

aw-watcher-lid monitors your laptop's lid state and system suspend/resume events, reporting them to ActivityWatch as AFK (away from keyboard) events.

Motivation

I'm using aw-watcher-window-wayland and it does a fairly good job at tracking my afk status. I decided to create this watcher while having some bugs with the afk-handling in my aw-export-timewarrior script. The bugs have been found and dealt with now - but I still think watching the lid status may be useful. At least for me, this method should give no false postives. If the lid is closed, I'm by definition away from its keyboard and most likely not doing useful work on it. (Your situation may of course be different, with external keyboard or other means of working with the laptop). (False negatives is another thing - the lid may very well be open even if I'm afk - but I may probably train myself to always close the lid before leaving the computer).

Status

Version 0.1.0 is considered to be pretty feature-complete, but hasn't been tested much. Your help is needed for testing it on different laptops and different OS distributions!

Checklist prior to the 1.0.0-release:

  • I've personally used the watcher for some few days and verified that it works correctly.
  • ... including suspend detection and boot detection.
  • At least one other person has tested and approved this watcher. (Please give me feedback on this!)

Features

  • Lid event tracking: Detects when laptop lid is opened/closed
  • Suspend/resume detection: Tracks system suspend and resume events
  • Boot gap detection: Identifies system downtime between boots
  • Short cycle filtering: Ignores lid events shorter than 10 seconds (configurable)
  • D-Bus integration: Real-time event monitoring via systemd-logind
  • Journal fallback: Polls journalctl when D-Bus unavailable

Event Format

Events are posted to ActivityWatch with type systemafkstatus:

{
  "timestamp": "2025-01-15T14:30:00Z",
  "duration": 300.0,
  "data": {
    "status": "system-afk",
    "lid_state": "closed",
    "suspend_state": null,
    "boot_gap": false,
    "event_source": "lid"
  }
}

Installation

# Clone the repository
git clone https://github.com/tobixen/aw-watcher-lid.git
cd aw-watcher-lid

# Install the watcher
make install

# The Makefile provides helpful commands for managing the installation:
make help  # See all available commands

This method is recommended because it provides clear commands for systemd service management and gives you full control over the installation.

From PyPI (Alternative)

For Python developers who prefer pip:

# Install with pip
pip install aw-watcher-lid

# Or with pipx (isolated environment, recommended)
pipx install aw-watcher-lid

Note: When installing from PyPI, you'll need to manually set up the systemd service if needed (see instructions below).

Usage

The recommended way to run aw-watcher-lid is through the ActivityWatch GUI (aw-qt), which will manage starting and stopping the watcher automatically.

To configure aw-qt to start the watcher:

  1. Find your aw-qt config file (usually ~/.config/activitywatch/aw-qt/aw-qt.toml)
  2. Add aw-watcher-lid to the watchers list:
[aw-qt]
autostart_modules = ["aw-server", "aw-watcher-afk", "aw-watcher-window", "aw-watcher-lid"]
  1. Restart aw-qt

The watcher will now start automatically when you launch ActivityWatch.

Method 2: Systemd Service

If you prefer to run the watcher independently as a systemd user service:

For PyPI installations:

# Download and install the service file
curl -o ~/.config/systemd/user/aw-watcher-lid.service \
  https://raw.githubusercontent.com/tobixen/aw-watcher-lid/main/misc/aw-watcher-lid.service

# Enable and start the service
systemctl --user daemon-reload
systemctl --user enable --now aw-watcher-lid

# Check status
systemctl --user status aw-watcher-lid

# View logs
journalctl --user -u aw-watcher-lid -f

For source installations:

# Install and enable the service using the Makefile
make enable-service

# Check status
systemctl --user status aw-watcher-lid

# View logs
journalctl --user -u aw-watcher-lid -f

Method 3: Manual Execution

For testing or development:

# Run directly
poetry run aw-watcher-lid

# Or after install
aw-watcher-lid

Configuration

Configuration file: ~/.config/aw-watcher-lid/config.toml

# Enable boot gap detection
enable_boot_detection = true

# Boot gap threshold (seconds)
# Gaps longer than this are recorded as system downtime
boot_gap_threshold = 300.0

# Polling interval when using journal fallback (seconds)
journal_poll_interval = 60.0

Note: The watcher reports ALL lid events and suspend/resume actions. Event filtering (e.g., ignoring short cycles) should be configured in aw-export-timewarrior, not in the watcher itself.

Systemd Service

The systemd service runs aw-watcher-lid automatically on login.

Service Management

# Check status
systemctl --user status aw-watcher-lid

# View logs
journalctl --user -u aw-watcher-lid -f

# Stop/start manually
systemctl --user stop aw-watcher-lid
systemctl --user start aw-watcher-lid

# Disable auto-start
make disable-service

# Uninstall service completely
make uninstall-service

Integration with aw-export-timewarrior

This watcher is designed to work with aw-export-timewarrior, which merges lid events with regular AFK events to provide accurate time tracking.

The watcher reports ALL lid closures and suspend actions. Event filtering (e.g., ignoring cycles shorter than 10 seconds) is handled in aw-export-timewarrior, not in the watcher itself.

Technical Details

D-Bus Requirement

aw-watcher-lid requires D-Bus to monitor lid and suspend events via systemd-logind. D-Bus is included as a standard dependency and does not require root permissions.

The watcher uses:

  • org.freedesktop.login1.Manager interface for suspend/resume events
  • org.freedesktop.UPower device properties for lid state changes

TODO: The journal polling fallback should probably be removed completely from the codebase. It adds complexity and is not the correct approach for this functionality.

A journal polling fallback is included in the code but is not recommended and not properly tested.

The journal fallback:

  • Polls journalctl for systemd-logind messages every 60 seconds
  • Requires the service to run with root privileges OR user to be in the systemd-journal group
  • Has higher latency than D-Bus (up to 60s delay)
  • May miss rapid lid open/close cycles

If D-Bus is not available on your system, it's better to fix the D-Bus installation than to use the journal fallback.

Development

The project includes a Makefile with common development tasks:

make help            # Show all available commands
make install-dev     # Install with dev dependencies
make test            # Run tests
make lint            # Run linting
make format          # Format code
make clean           # Remove build artifacts

License

MPL-2.0 (following ActivityWatch)

Metadata

Release files for aw-watcher-lid 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aw-watcher-lid 0.1.2
File Size Uploaded
aw_watcher_lid-0.1.2.tar.gz 13.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aw-watcher-lid 0.1.2
File Interpreter ABI Platform
aw_watcher_lid-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 27.1 kB

Release files / aw_watcher_lid-0.1.2.tar.gz

Download URL aw_watcher_lid-0.1.2.tar.gz
Size 13.1 kB
Tags Source
SHA-256 checksum
How to use checksums
60f11aa3ede07c0d665a8253eaced5a2d384007f510383fa056c82e286a0409b
BLAKE2b-256 checksum
How to use checksums
eff97b027055664b56c58bced89e250559b5a1b4ad3c88acb600fb1fecc1ec51
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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 Dec 15, 2025.

Transparency log

Release files / aw_watcher_lid-0.1.2-py3-none-any.whl

Download URL aw_watcher_lid-0.1.2-py3-none-any.whl
Size 14.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7a36dad24d5123197122551b94cb60920a578c678e3a58ef327fab44144671ec
BLAKE2b-256 checksum
How to use checksums
2ba5095e849b308c94c888c283418be9d9cb519f6d8e0eb879e99877945422c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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 Dec 15, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page