Skip to content

Repository files navigation

Clocking Assistant

Clocking in and out is boring. Why dont you automate it? This python module will do it for you in no time!

Key features

  • Automatically perform clock in/out operations from your favourite time tracking app.
  • Run hooks right after clocking in/out.
  • Provides a plugin-driven architecture that makes it easy to add support for any time tracking app and any notification service.
  • Out of the box support for Woffu.
  • Out of the box support for Telegram notifications after clocking in/out.

Setup

  1. Download the latest release
  2. Install the module
    pip install -e clocking_assistant-X.Y.Z.tar.gz
  3. Create the configuration file in /srv/clocking_assistant/config.json. This will vary depending of the service you use to clock in. You should look for you tracking service in drivers, but overall it will look somewhat like this:
    {
      "driver": {
          "name": "driver name",
          "credentials": {
              "api-key": "secret-key"
          },
          "options": {
            ...
          }
      },
    }
  4. Setup a cron job to clock in and out whenever you like:
    crontab -e
    
    # Cron file
    0 9 * * * python -m clocking_assistant clock-in
    0 14 * * * python -m clocking_assistant clock-out

If the configuration file does not exist, an error will be raised and the application will exit.

Arguments

Argument Description Default Value
--config File used to configure the program /srv/clocking_assistant/config.json.
[operation] Required positional argument. Must be either clock-in or clock-out. Specifies the operation to be performed by the module.

Drivers

Here's a list of currently supported time tracking services:

Woffu

Features

  • Automatically skip non working days, such as weekends, national and regional holidays and requested PTO.
  • Human-like behaviour (see humanize flag).

Configuration

Sample configuration:

{
  "driver": {
    "name": "woffu",
    "credentials": {
      "username": "<woffu username>",
      "password": "<woffu password>",
    },
    "options": {
      "humanize": true
    }
  }
}

Options

Name Description Default Value
humanize Adds a random delay (between 0 and 120 seconds) whenever the scripts is about to clock in or out. This way we ensure clocking hours are always slightly different, but your cron job should take this delay into account! false

Hooks

This module offers support for running hooks after clocking in/out.

Telegram notifications are supported out of the box, but there's room for more integrations through the plugins architecture ;)

Telegram

To receive a message via Telegram bot anytime the module clocks you in or out, simply set up the telegram hook in your configuration file:

{
  "username": "<YOUR WOFFU USERNAME>",
  "password": "<YOUR WOFFU PASSWORD>",
  "hooks": [
    {
      "name": "telegram",
      "args": {
        "api_key": "<TELEGRAM BOT KEY>"
      }
    }
  ]
}

You may also customize the notification message by specifying it in the args section:

{
  ...
  "hooks": [
    {
      "name": "telegram",
      "args": {
        "api_key": "<TELEGRAM BOT KEY>",
        "message": "Custom message"
      }
    }
  ]
}

Don't forget to text your bot before you run the script for the first time!

Plugins

You may add your own time trackers and hooks!

Plugins are loaded from /srv/clocking_assistant/plugins, and their data is stored under /srv/clocking_assistant/plugins/data/${plugin_name} by default. This is customizable by plugins and plugins_data (respectively) keys within the configuration file:

{
  ...
  "plugins": "/etc/clocking-assistant/plugins",
  "plugins_data": "/var/clocking-assistant/plugins"
}

Have in mind that any feature that allows running arbitrary code is somewhat a risk. Only use plugins you trust!

Creating a new hook

To make a new hook, you just need to create a Python script with a class extending HookHandlerBase, set the hook name associated to this handler and implement the run method. For instance, let's write a very simple discord plugin that will be executed whenever the hook 'discord' is defined:

from clocking_assistant import HookDefinition, HookHandlerBase

class DiscordHandler(HookHandlerBase):

  def __init__(self, cache_dir: str) -> None:
      super().__init__('discord', cache_dir)

  def run(self, hook: HookDefinition):
    key = hook.args['api-key']
    message = hook.args['message']
    # Actually do something...

Now you'd only need to place the script under the plugins folder and add the custom hook to the configuration file!

{
  ...
  "hooks": [
    {
      "name": "discord",
      "args": {
        "api-key": "hello",
        "message": "there"
      }
    }
  ]
}

Creating a new driver for a time tracking service

If your time tracking service of choice is not supported, you may just support it yourself.

You will need to create a Python script with a class extending ClockingServiceBase, set the plugin name associated to this service and implement the clock_in, clock_out and is_working_day methods. Here's some boilerplate code:

from clocking_assistant import ClockingServiceBase

class MyTrackerService(ClockingServiceBase):
  def __init__(self, data_dir: str, credentials: Dict[str, str], options: Dict[str, Any]) -> None:
        super().__init__("myTracker", data_dir, credentials, options)

  def is_working_day(self) -> bool:
    # Check whether today is a working day
    working_day = ...
    return working_day

  def clock_in(self):
    api_key = self.credentials['api-key']
    opt = self.options['some-option']
    # Actually clock in
  
  def clock_out(self):
    api_key = self.credentials['api-key']
    opt = self.options['some-option']
    # Actually clock out

Now you'd only need to place the script under the plugins folder and select your custom driver in the configuration file!

{
  "driver": {
    {
      "name": "myTracker",
      "credentials": {
        "api-key": "secret-key",
      },
      "options": {
        "some-option": "some value" 
      } 
    }
  }
}

Releases

Packages

Contributors

Languages