Metadata-Version: 2.4
Name: aw-watcher-lid
Version: 0.1.0
Summary: ActivityWatch watcher for laptop lid events and system suspend/resume
License: MPL-2.0
License-File: LICENSE
Keywords: activitywatch,watcher,laptop,lid,suspend,time-tracking
Author: Tobias Brox
Author-email: tobias@redpill-linpro.com
Requires-Python: >=3.13,<4.0
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Utilities
Requires-Dist: PyGObject (>=3.42.0,<4.0.0)
Requires-Dist: aw-client (>=0.5.13,<0.6.0)
Requires-Dist: dbus-python (>=1.3.2,<2.0.0)
Project-URL: Homepage, https://github.com/tobixen/aw-watcher-lid
Project-URL: Repository, https://github.com/tobixen/aw-watcher-lid
Description-Content-Type: text/markdown

# 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`:

```json
{
  "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)

```bash
# 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:

```bash
# 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:

```toml
[aw-qt]
autostart_modules = ["aw-server", "aw-watcher-afk", "aw-watcher-window", "aw-watcher-lid"]
```

3. 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:**

```bash
# 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:**

```bash
# 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:

```bash
# Run directly
poetry run aw-watcher-lid

# Or after install
aw-watcher-lid
```

## Configuration

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

```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

```bash
# 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](https://github.com/ActivityWatch/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:

```bash
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)

