Skip to main content

ActivityWatch watcher for laptop lid events and system suspend/resume

Project description

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

From Source (Recommended)

# 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

Method 1: aw-qt Integration (Recommended)

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

Journal Fallback (Not Recommended)

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)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aw_watcher_lid-0.1.0.tar.gz (13.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aw_watcher_lid-0.1.0-py3-none-any.whl (14.0 kB view details)

Uploaded Python 3

File details

Details for the file aw_watcher_lid-0.1.0.tar.gz.

File metadata

  • Download URL: aw_watcher_lid-0.1.0.tar.gz
  • Upload date:
  • Size: 13.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.13.11 Linux/6.17.9-arch1-1

File hashes

Hashes for aw_watcher_lid-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7868e7a34e6b5bbe3a117c3ffc4b9f2a5cfcbaa2e60d04c9a6bed3aaa79a88f1
MD5 e4249e844d9f56dfec9537713f4c267b
BLAKE2b-256 268470abd093a82dcc8f07263e89a9966778f905d0e5292b852245f356e46457

See more details on using hashes here.

File details

Details for the file aw_watcher_lid-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: aw_watcher_lid-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.2.1 CPython/3.13.11 Linux/6.17.9-arch1-1

File hashes

Hashes for aw_watcher_lid-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9e46143c340448183cb1e491d90089e465d02b3c7b2af1f072c9c21c02092498
MD5 2592f91985323d9990bc3fcaecefe066
BLAKE2b-256 21ff93426787e0d6adb088b2b624c1f0b68ee8597624b848e32a8c36ff402bfd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page