Giter Site home page Giter Site logo

activitywatch / aw-watcher-afk Goto Github PK

View Code? Open in Web Editor NEW
43.0 6.0 27.0 330 KB

Watches keyboard and mouse activity to determine if you are AFK or not (for use with ActivityWatch)

License: Mozilla Public License 2.0

Python 97.89% Makefile 2.11%
activitywatch activitywatch-watcher mouse-activity afk

aw-watcher-afk's Introduction

aw-watcher-afk

Build Status

Watches your keyboard and mouse activity to determine if you are AFK (away from keyboard) or not. By default, a period of at least 3 minutes inactivity is flagged as AFK.

How to install

To install the pre-built application, go to https://activitywatch.net/downloads/

To build your own packaged application, run make package

To install the latest git version directly from github without cloning, run pip install git+https://github.com/ActivityWatch/aw-watcher-afk.git

To install from a cloned version, cd into the directory and run poetry install to install inside an virtualenv. If you want to install it system-wide it can be installed with pip install ., but that has the issue that it might not get the exact version of the dependencies due to not reading the poetry.lock file.

aw-watcher-afk's People

Contributors

erikbjare avatar exoji2e avatar huantianad avatar iloveitaly avatar johan-bjareholt avatar lgtm-com[bot] avatar soxofaan avatar tsrberry avatar victorwinberg avatar whazor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

aw-watcher-afk's Issues

Hibernation and afk events sometimes heavily overlap.

I've been receiving a couple of those, for instance in the following log :

2017-07-23 01:54:32,389 [INFO ]: No longer AFK  (aw_watcher_afk.afk:99)
2017-07-23 04:19:23,139 [INFO ]: Woke up from suspend/hibernation  (aw_watcher_afk.afk:94)
2017-07-23 04:19:23,735 [INFO ]: Received heartbeat after pulse window, inserting as new event. (bucket: aw-watcher-window_ker)  (aw_server.api:154)
2017-07-23 04:19:24,141 [INFO ]: Became AFK  (aw_watcher_afk.afk:105)
2017-07-23 04:19:24,226 [WARNING]: Inserting event that has a older timestamp than previous event!
Previous:{'id': 17206, 'timestamp': datetime.datetime(2017, 7, 23, 7, 52, 36, 809000, tzinfo=datetime.timezone.utc), 'duration': datetime.timedelta(0, 1606, 330391), 'data': {'status': 'hibernating'}}
Inserted:{'id': 17208, 'timestamp': datetime.datetime(2017, 7, 23, 7, 52, 1, 770000, tzinfo=datetime.timezone.utc), 'duration': datetime.timedelta(0, 1642, 370692), 'data': {'status': 'afk'}}  (aw_datastore.datastore.Bucket:110)
2017-07-23 04:19:26,144 [INFO ]: No longer AFK  (aw_watcher_afk.afk:99)
2017-07-23 10:37:25,039 [INFO ]: Woke up from suspend/hibernation  (aw_watcher_afk.afk:94)
2017-07-23 10:37:25,206 [INFO ]: Received heartbeat after pulse window, inserting as new event. (bucket: aw-watcher-window_ker)  (aw_server.api:154)
2017-07-23 10:37:26,040 [INFO ]: Became AFK  (aw_watcher_afk.afk:105)
2017-07-23 10:37:26,129 [WARNING]: Inserting event that has a older timestamp than previous event!
Previous:{'id': 17218, 'timestamp': datetime.datetime(2017, 7, 23, 8, 23, 38, 523000, tzinfo=datetime.timezone.utc), 'duration': datetime.timedelta(0, 22426, 515437), 'data': {'status': 'hibernating'}}
Inserted:{'id': 17220, 'timestamp': datetime.datetime(2017, 7, 23, 8, 23, 33, 515000, tzinfo=datetime.timezone.utc), 'duration': datetime.timedelta(0, 22432, 525563), 'data': {'status': 'afk'}}  (aw_datastore.datastore.Bucket:110)
2017-07-23 10:37:27,043 [INFO ]: No longer AFK  (aw_watcher_afk.afk:99)

Looks like being afk starts a couple of seconds before closing the lid / going to sleep, and then on wake-up the hibernation event is added first, and then an afk event (covering the same time period ? that time is logged twice ?) is added ?

I did compute that I have 12 days of logged time (the sum of events durations) over the last 10 days. Some of it might be due to two processes running, but if hibernated time is counted twice that's a much more likely explanation. Is it meant to be ?

Detect when audio is active

I've not looked into what APIs might be available but I would love to have the AFK detection be able to detect when I'm on a video conference and listening / speaking versus actually AFK. Given the various audio privacy features I'm hopeful we can find some hooks to check for active programs bound to a mic input versus just speaker output.

It might be sane to say if a microphone is present AND it's bound to an application then extend the AFK timeout to say 30 minutes. This wouldn't really cover webinar style one way presentations but at least we can get halfway there :)

document the default `timeout` better

I was curious about how aw-watcher-afk detects inactivity (in particular, the time after which "afk" is flagged) and it took me some effort to figure that out.
I eventually I had to dive in the source code to find out it was 3 minutes:

I think it would be useful to document/mention this default timeout value, e.g. here:

Look at arbtt for how they handle input etc.

https://bitbucket.org/nomeata/arbtt/src/

Read a bit of their source, which is well written (Haskell).

Turns out there is a GetLastInputInfo on Windows which returns a LASTINPUTINFO struct containing the timestamp of last input, they even explicitly write "this function is useful for input idle detection".

arbtt also do some calls on macOS which we might want to do something equivalent in aw-watcher-window to since the current solution (using AppleScript) is a total mess.

Might be useful to use some of the solutions they have in aw-watcher-window if there turns out to be any issues with the way we currently do thing there.

Add logging of screen power/lock state

Windows

Linux

Best would be if this functionality was extracted to a library, which could poll/listen for state change for multiple environments. The process-monitor should probably be outsourced to a stable lib, or abstracted away in a lib.

Movies count as AFK(?)

Hi there! thanks for ActivitWatch, this is a very nice tool!
I'm trying to track the computer usage of my daughter (in cooperation with her), and I noticed a difference of about 20min between her actual computer usage and the tracker. Then I found out that during specific movies (not all of them) the logger assumed that she'd be afk. seems like an issue to me...
running linux mint 20.3 Cinnamon
Bildschirmfoto vom 2022-12-28 10-41-00
Bildschirmfoto vom 2022-12-28 10-38-09
cheers
hirntot

No Documentation: Mofify the data manually

Currently there is no documented way of modifying the data manually to correct an error or change a certain behavior of the tool. The need to modify the data manually spun out of the current implementation not adding the time spent listening to something. Which ends up not calculating zoom calls at all. Which is a big part of someone's productivity. The current solution for this issue is implemented only in webbrowser tabs but not for standalone applications. I would like to be able to manually modify the data collected for a certain app in a certain day.

Fail to build for developer install

When building for developer with command make build DEV="true",
Makefile script fail as below:

$ make build DEV="true"
pip3 install . -r requirements.txt --editable

Usage:   
  pip install [options] <requirement specifier> [package-index-options] ...
  pip install [options] -r <requirements file> [package-index-options] ...
  pip install [options] [-e] <vcs project url> ...
  pip install [options] [-e] <local project path> ...
  pip install [options] <archive url/path> ...

--editable option requires 1 argument
Makefile:10: recipe for target 'build' failed
make: *** [build] Error 2

Odd behavior after suspend

A couple of times after suspend i have seen that the not-afk label is extended for the whole suspended time, for example 8h when i put my computer on suspend during the night when i was sleeping. After the next check interval however (30s) the event will be replaced by a new "not-afk" event reducing the duration and timestamp again. That makes this less of an issue, but the expected behavior would be that it would say "afk" during the hibernation.

Actual

22.30 Set computer on suspend
07.30 Woke up computer, last non-afk event extended to 8h duration
07.31 8h long non-afk event is being replaced by a new shorter non-afk event but still with the timestamp 8h ago which would make the current window events filtered due to there not being any non-afk events during that period

Expected

22.30 Set computer on suspend
07.30 Woke up computer, a new afk event of 8h is created and a new non-afk event is created afterwards

Crash on suspend

Seems like the last refactor broke suspend sometimes? It works fine on my desktop but this occured on my laptop just now.

Traceback (most recent call last):
  File "/usr/bin/aw-watcher-afk", line 11, in <module>
    load_entry_point('aw-watcher-afk', 'console_scripts', 'aw-watcher-afk')()
  File "/home/johan/Programming/activitywatch/aw-watcher-afk/aw_watcher_afk/__main__.py", line 28, in main
    watcher.run()
  File "/home/johan/Programming/activitywatch/aw-watcher-afk/aw_watcher_afk/afk.py", line 111, in run
    self.change_state(self.second_last_activity)
AttributeError: 'AFKWatcher' object has no attribute 'second_last_activity'

Call for documentation: how does the event model work?

Alright, so I started playing around with aw-client, and reading this watcher's events.

import aw_client
ac = aw_client.ActivityWatchClient("_")
ac.connect()
afk_events = ac.get_events("aw-watcher-afk_ker", 10**6)
recent_events = afk_events[:50]
recent_events.reverse()
for e in recent_events:
    print(e["timestamp"], ",", e["data"]["status"])

returns

a big log
2017-07-16 07:17:04.486000+00:00 , hibernating
2017-07-16 07:26:10.397000+00:00 , not-afk
2017-07-16 07:26:10.397000+00:00 , afk
2017-07-16 07:26:11.426000+00:00 , not-afk
2017-07-16 07:32:32.052000+00:00 , afk
2017-07-16 07:42:08.010000+00:00 , afk
2017-07-16 07:42:08.010000+00:00 , not-afk
2017-07-16 07:44:32.273000+00:00 , afk
2017-07-16 08:04:17.377000+00:00 , afk
2017-07-16 08:04:17.377000+00:00 , not-afk
2017-07-16 08:24:52.358000+00:00 , afk
2017-07-16 08:40:57.009000+00:00 , afk
2017-07-16 08:40:57.009000+00:00 , not-afk
2017-07-16 09:09:43.786000+00:00 , afk
2017-07-16 14:07:19.997000+00:00 , afk
2017-07-16 14:07:19.997000+00:00 , not-afk
2017-07-16 14:07:49.129000+00:00 , afk
2017-07-16 16:19:37.189000+00:00 , afk
2017-07-16 16:19:37.189000+00:00 , not-afk
2017-07-16 16:19:45.277000+00:00 , afk
2017-07-16 16:50:56.040000+00:00 , afk
2017-07-16 16:50:56.040000+00:00 , not-afk
2017-07-16 16:52:38.301000+00:00 , afk
2017-07-16 16:56:00.650000+00:00 , afk
2017-07-16 16:56:00.650000+00:00 , not-afk
2017-07-16 17:30:10.037000+00:00 , afk
2017-07-16 17:33:25.327000+00:00 , afk
2017-07-16 17:33:25.327000+00:00 , not-afk
2017-07-16 17:55:29.364000+00:00 , afk
2017-07-16 18:04:20.395000+00:00 , afk
2017-07-16 18:04:20.395000+00:00 , not-afk
2017-07-16 20:47:11.804000+00:00 , afk
2017-07-16 20:54:19.568000+00:00 , not-afk
2017-07-16 22:56:31.960000+00:00 , not-afk
2017-07-16 23:35:50.099000+00:00 , afk
2017-07-16 23:39:27.463000+00:00 , not-afk
2017-07-16 23:40:40.589000+00:00 , afk
2017-07-16 23:48:10.283000+00:00 , not-afk
2017-07-16 23:51:58.601000+00:00 , afk
2017-07-16 23:57:09.038000+00:00 , not-afk
2017-07-16 23:57:10.046000+00:00 , afk
2017-07-17 00:02:03.486000+00:00 , not-afk
2017-07-17 00:06:06.826000+00:00 , afk
2017-07-17 00:19:02.071000+00:00 , not-afk
2017-07-17 00:20:40.235000+00:00 , afk
2017-07-17 00:24:45.588000+00:00 , not-afk
2017-07-17 00:30:40.616000+00:00 , afk
2017-07-17 00:33:55.918000+00:00 , not-afk
2017-07-17 01:22:29.849000+00:00 , afk
2017-07-17 01:27:50.428000+00:00 , not-afk

What am I seeing here ?

What does it mean when there are two afk, or two not-afk (atk, at the keyboard ?) events one after the other ? What is the default state ?

How comes sometimes there are afk/not-afk events at the same time ? Is this the precise moment when I last pressed something ?

What does it mean when there's a not-afka long while after an afk event ? That this is the first activity since I went away a while ago ? That would make sense. But then, the reverse, an afk event a long while after the last not-afk event ? Was this the last keypress ? For how long do I have to not touch the machine to be considered afk ?

While I did dig a bit by myself and found config.timeout which gives some hints to people willing to read code, I think answering the questions above, here first and then probably in this repos' README, would be a good start for a documentation :)

KeyboardSwitch missing arguments

So I was testing it out on Windows today. Worked well for the first 4 minutes and then:

TypeError: KeyboardSwitch() missing 8 required positional arguments: 'msg', 'vk_code', 'scan_code', 'ascii', 'flags', 'time', 'hwnd', and 'win_name'

Likely an issue in PyUserInput.

Incorrect AFK detection

Was watching a movie today, using MPV (green is mpv, orange is firefox):

image

The AFK region towards the end is where I had mpv maximized (playing the movie.)
Furthermore, I was pressing a few keys every now and then too - to raise volume or seek ahead etc.

Why could it be detecting that I was away?

Also, what happens when I'm marked AFK? Does the window watcher stop recording active windows? or are those events recorded but just not displayed on the UI?

Data is often doubled with two events starting at same timestamp but different durations

While experimenting with analysing the watcher data separately, I noticed that data often is doubled, with two events starting at identical timestamps but with different durations. Here are two screenshots demonstrating this, one from the GUI view and one from the database itself.
image
(notice the lines in the middle of the visualization of each period, there are two events there)
image

This, while it doesn't seem to affect the official visualisations much, is rather annoying to work with when working with the data directly.
Seems though like this could be an easy fix even by just filtering the data afterhand with just checking the start timestamp and comparing the durations, leaving only one event, or by implementing some sort of overlap correction.

Rewrite using the heartbeat API

aw-watcher-afk is different to aw-window etc. because of how AFK periods are calculated, great care must be taken to ensure we don't make a simplification which departs from the specification/current implementation.

I can come up with these causes of complexity that might need some thinking:

  • When does a user become AFK? When he/she has not interacted for duration x. Do we simply avoid sending heartbeats when there is no new activity and then send a heartbeat with a longer pulsetime if we're still within the non-AFK window? When he/she actually becomes AFK we need to send a heartbeat with a timestamp that's duration x old.
  • ... (there's something more I'm sure)

Log number of keystrokes, mouse delta

One aspect of this seems difficult: We'd want to log the number of keystrokes per window, so that'd mean we have to couple the keycount event duration to the window event somehow.

Not sure how to do this without tying it into the window watcher one way or another. A slightly depraved solution would be to poll/subscribe to the window events and create a new entry where appropriate. I can imagine a bunch of solutions involving the server as well but I'd rather not just for this specific case.

Keeps sending afk events if xserver is restarted

Was wondering for a long while why I didn't get any activity data visualized despite the buckets being updated regularly. I now noticed I have a 54h 14m 27s long afk event...

Steps to reproduce (haven't tested):

  1. Start a xsession from a tty
  2. Start aw-qt or the modules using systemd or something (so they survive when the xsession ends)
  3. Exit the xsession (without logging out of the tty)
  4. Start the xsession again
  5. aw-watcher-afk will now endlessly send afk events

This probably has to do with KeyboardListener and MouseListener (and, in turn, PyUserInput).

[bug] aw-watcher-afk over freerdp

I'm using aw-watcher-afk over freerdp, on Debian 11, but it seems to always report afk.
Tested using xrdp 0.9.12 (server) and xfreerdp 3.0.0-dev 2c31c3675 (client).

Avoid detecting AFK when watching a video in chrome

I've just recently started using ActivityWatch and kudos to the team for the awesome work!

I noticed that while watching videos at a stretch, the watcher usually logs AFK, leading to wrong attributions in ActivityWatch (screenshot below). Now, I understand that I'm technically indeed not using my keyboard/mouse which is probably leading to the AFK status. But I wonder if there can be a quick fix to this? Maybe it's possible to have something like an "ignore-domain" list that just ignores using the AFK filter to aggregate results for some specific domains/apps?

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.