Personal Automation Dashboard for Your Daily Tasks

Personal Automation Dashboard for Your Daily Tasks

๐‰๐จ๐ข๐ง ๐œ๐จ๐ฆ๐ฆ๐ฎ๐ง๐ข๐ญ๐ฒ - ๐‚๐‹๐ˆ๐‚๐Š ๐‡๐„๐‘๐„

Imagine having one private dashboard where you can create, schedule, enable, disable, and manually run your own daily automations.

In this A-to-Z guide, we'll build one using Python + Flask + SQLite + APScheduler.

You can later extend it with reminders, backups, reports, file organization, website monitoring, and many other personal workflows.


๐Ÿงฐ What You'll Need

  • Python 3
  • Flask
  • APScheduler
  • SQLite
  • Any Windows/Linux/macOS PC
  • Android + Termux also works

Install Python:

https://www.python.org/downloads/

Check it:

python --version

On Linux/Termux:

python3 --version

1. Create the Project

Create a folder:

personal-automation

Inside it:

personal-automation/
โ”œโ”€โ”€ app.py
โ”œโ”€โ”€ requirements.txt
โ”œโ”€โ”€ templates/
โ”‚   โ””โ”€โ”€ index.html
โ””โ”€โ”€ data/

2. Create a Virtual Environment

Windows

python -m venv venv
venv\Scripts\activate

Linux / macOS / Termux

python3 -m venv venv
source venv/bin/activate

3. Install Flask and APScheduler

Create:

requirements.txt

Add:

Flask
APScheduler

Install:

pip install -r requirements.txt

APScheduler supports recurring interval and cron-style jobs, which we'll use for our automations.

https://apscheduler.readthedocs.io/


4. Create app.py

Open:

app.py

Paste:

from flask import Flask, render_template, request, redirect, url_for
from apscheduler.schedulers.background import BackgroundScheduler
from datetime import datetime
import sqlite3
import os

app = Flask(__name__)

DB_FILE = "automation.db"

scheduler = BackgroundScheduler()
scheduler.start()


# -------------------------
# DATABASE
# -------------------------

def get_db():
    conn = sqlite3.connect(DB_FILE)
    conn.row_factory = sqlite3.Row
    return conn


def init_db():

    conn = get_db()

    conn.execute("""
        CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            action TEXT NOT NULL,
            schedule_type TEXT NOT NULL,
            schedule_value TEXT NOT NULL,
            enabled INTEGER DEFAULT 1,
            last_run TEXT,
            run_count INTEGER DEFAULT 0
        )
    """)

    conn.commit()
    conn.close()


# -------------------------
# AUTOMATION ACTIONS
# -------------------------

def execute_action(task_id):

    conn = get_db()

    task = conn.execute(
        "SELECT * FROM tasks WHERE id = ?",
        (task_id,)
    ).fetchone()

    conn.close()

    if not task or not task["enabled"]:
        return

    os.makedirs("data", exist_ok=True)

    action = task["action"]

    if action == "daily_note":

        filename = datetime.now().strftime(
            "data/daily-note-%Y-%m-%d.txt"
        )

        with open(filename, "a", encoding="utf-8") as file:

            file.write(
                f"Automation executed: "
                f"{datetime.now().isoformat()}\n"
            )

        message = f"Created {filename}"

    elif action == "system_report":

        filename = datetime.now().strftime(
            "data/system-report-%Y-%m-%d.txt"
        )

        with open(filename, "w", encoding="utf-8") as file:

            file.write("Personal System Report\n")
            file.write("======================\n")
            file.write(
                f"Generated: "
                f"{datetime.now().isoformat()}\n"
            )

        message = f"Created {filename}"

    elif action == "backup_marker":

        os.makedirs("data/backups", exist_ok=True)

        filename = datetime.now().strftime(
            "data/backups/backup-%Y-%m-%d-%H%M%S.txt"
        )

        with open(filename, "w", encoding="utf-8") as file:

            file.write(
                f"Backup created: "
                f"{datetime.now().isoformat()}\n"
            )

        message = f"Created {filename}"

    else:

        message = "Unknown action"

    conn = get_db()

    conn.execute("""
        UPDATE tasks
        SET last_run = ?,
            run_count = run_count + 1
        WHERE id = ?
    """, (
        datetime.now().isoformat(),
        task_id
    ))

    conn.commit()
    conn.close()

    print(message)


# -------------------------
# SCHEDULER
# -------------------------

def schedule_task(task):

    job_id = f"task_{task['id']}"

    try:
        scheduler.remove_job(job_id)
    except Exception:
        pass

    if not task["enabled"]:
        return

    if task["schedule_type"] == "interval":

        minutes = int(task["schedule_value"])

        scheduler.add_job(
            execute_action,
            "interval",
            minutes=minutes,
            args=[task["id"]],
            id=job_id,
            replace_existing=True
        )

    elif task["schedule_type"] == "daily":

        hour, minute = map(
            int,
            task["schedule_value"].split(":")
        )

        scheduler.add_job(
            execute_action,
            "cron",
            hour=hour,
            minute=minute,
            args=[task["id"]],
            id=job_id,
            replace_existing=True
        )


def load_tasks():

    conn = get_db()

    tasks = conn.execute(
        "SELECT * FROM tasks"
    ).fetchall()

    conn.close()

    for task in tasks:
        schedule_task(task)


# -------------------------
# DASHBOARD
# -------------------------

@app.route("/")
def index():

    conn = get_db()

    tasks = conn.execute("""
        SELECT *
        FROM tasks
        ORDER BY id DESC
    """).fetchall()

    conn.close()

    return render_template(
        "index.html",
        tasks=tasks
    )


# -------------------------
# CREATE AUTOMATION
# -------------------------

@app.route("/add", methods=["POST"])
def add_task():

    name = request.form["name"]
    action = request.form["action"]
    schedule_type = request.form["schedule_type"]
    schedule_value = request.form["schedule_value"]

    conn = get_db()

    cursor = conn.execute("""
        INSERT INTO tasks
        (name, action, schedule_type, schedule_value)
        VALUES (?, ?, ?, ?)
    """, (
        name,
        action,
        schedule_type,
        schedule_value
    ))

    task_id = cursor.lastrowid

    conn.commit()

    task = conn.execute(
        "SELECT * FROM tasks WHERE id = ?",
        (task_id,)
    ).fetchone()

    conn.close()

    schedule_task(task)

    return redirect(url_for("index"))


# -------------------------
# ENABLE / DISABLE
# -------------------------

@app.route("/toggle/<int:task_id>")
def toggle_task(task_id):

    conn = get_db()

    task = conn.execute(
        "SELECT * FROM tasks WHERE id = ?",
        (task_id,)
    ).fetchone()

    if task:

        new_status = 0 if task["enabled"] else 1

        conn.execute("""
            UPDATE tasks
            SET enabled = ?
            WHERE id = ?
        """, (
            new_status,
            task_id
        ))

        conn.commit()

        updated = conn.execute(
            "SELECT * FROM tasks WHERE id = ?",
            (task_id,)
        ).fetchone()

        schedule_task(updated)

    conn.close()

    return redirect(url_for("index"))


# -------------------------
# RUN NOW
# -------------------------

@app.route("/run/<int:task_id>")
def run_now(task_id):

    execute_action(task_id)

    return redirect(url_for("index"))


# -------------------------
# DELETE
# -------------------------

@app.route("/delete/<int:task_id>")
def delete_task(task_id):

    try:
        scheduler.remove_job(
            f"task_{task_id}"
        )
    except Exception:
        pass

    conn = get_db()

    conn.execute(
        "DELETE FROM tasks WHERE id = ?",
        (task_id,)
    )

    conn.commit()
    conn.close()

    return redirect(url_for("index"))


# -------------------------
# START
# -------------------------

if __name__ == "__main__":

    init_db()

    load_tasks()

    app.run(
        host="127.0.0.1",
        port=5000,
        debug=False
    )

5. Create the Dashboard

Open:

templates/index.html

Paste:

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<meta
    name="viewport"
    content="width=device-width, initial-scale=1.0"
>

<title>Personal Automation Dashboard</title>

<style>

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: Arial, sans-serif;
    background: #f4f6f8;
    color: #1f2937;
}

header {
    background: #111827;
    color: white;
    padding: 25px;
}

header h1 {
    margin: 0;
}

header p {
    opacity: .7;
}

.container {
    max-width: 1000px;
    margin: auto;
    padding: 25px;
}

.card {
    background: white;
    padding: 22px;
    border-radius: 14px;
    margin-bottom: 20px;
    box-shadow: 0 5px 20px rgba(0,0,0,.06);
}

input,
select,
button {

    width: 100%;

    padding: 12px;

    border: 1px solid #d1d5db;

    border-radius: 8px;

    margin-top: 8px;

    margin-bottom: 15px;

    font-size: 15px;
}

button {

    background: #111827;

    color: white;

    border: none;

    cursor: pointer;
}

.task {

    border: 1px solid #e5e7eb;

    padding: 16px;

    border-radius: 12px;

    margin-bottom: 15px;
}

.task-title {

    font-size: 18px;

    font-weight: bold;
}

.status {

    display: inline-block;

    padding: 5px 9px;

    border-radius: 20px;

    font-size: 12px;

    margin-top: 8px;
}

.enabled {

    background: #dcfce7;

    color: #166534;
}

.disabled {

    background: #fee2e2;

    color: #991b1b;
}

.actions {

    display: flex;

    gap: 8px;

    flex-wrap: wrap;
}

.actions a {

    text-decoration: none;

    padding: 9px 12px;

    border-radius: 7px;

    background: #eef2ff;

    color: #3730a3;
}

.actions .delete {

    background: #fee2e2;

    color: #991b1b;
}

</style>

</head>


<body>


<header>

<h1>โš™๏ธ Personal Automation Dashboard</h1>

<p>
Manage your daily automations from one private dashboard.
</p>

</header>


<div class="container">


<div class="card">

<h2>โž• Create Automation</h2>


<form method="POST" action="/add">


<label>Task Name</label>

<input
    type="text"
    name="name"
    placeholder="Morning Daily Note"
    required
>


<label>Automation</label>

<select name="action">

<option value="daily_note">
Create Daily Note
</option>

<option value="system_report">
Create System Report
</option>

<option value="backup_marker">
Create Backup Marker
</option>

</select>


<label>Schedule</label>

<select name="schedule_type">

<option value="daily">
Every Day
</option>

<option value="interval">
Every X Minutes
</option>

</select>


<label>Schedule Value</label>

<input
    type="text"
    name="schedule_value"
    placeholder="09:00"
    required
>


<small>

Daily example: 09:00<br>

Interval example: 60

</small>


<button type="submit">

Create Automation

</button>


</form>

</div>


<div class="card">

<h2>๐Ÿ“‹ Your Automations</h2>


{% if tasks %}


{% for task in tasks %}


<div class="task">


<div class="task-title">

{{ task["name"] }}

</div>


<span class="status
{% if task['enabled'] %}
enabled
{% else %}
disabled
{% endif %}
">

{% if task["enabled"] %}

ENABLED

{% else %}

DISABLED

{% endif %}

</span>


<p>

Action:

<strong>
{{ task["action"] }}
</strong>

</p>


<p>

Schedule:

<strong>

{{ task["schedule_type"] }}
โ€”
{{ task["schedule_value"] }}

</strong>

</p>


<p>

Runs:

{{ task["run_count"] }}

</p>


<p>

Last run:

{{ task["last_run"] or "Never" }}

</p>


<div class="actions">


<a href="/run/{{ task['id'] }}">

โ–ถ Run Now

</a>


<a href="/toggle/{{ task['id'] }}">

{% if task["enabled"] %}

Disable

{% else %}

Enable

{% endif %}

</a>


<a
    class="delete"
    href="/delete/{{ task['id'] }}"
>

Delete

</a>


</div>


</div>


{% endfor %}


{% else %}

<p>No automations created yet.</p>

{% endif %}


</div>


</div>


</body>

</html>

6. Start the Dashboard

Inside the project folder:

python app.py

Linux/Termux:

python3 app.py

You'll see:

* Running on http://127.0.0.1:5000

Open:

http://127.0.0.1:5000

Your personal automation dashboard is now running.


7. Create Your First Automation

For example:

Task Name

Morning Daily Note

Automation

Create Daily Note

Schedule

Every Day

Time

09:00

Click:

Create Automation

You'll now see the task on the dashboard.


8. Test It Immediately

Instead of waiting until 09:00, click:

โ–ถ Run Now

The application creates:

data/daily-note-2026-10-02.txt

Inside the file you'll find the execution time.


9. Create an Automatic Report

Create another task:

Task Name:
Daily System Report

Choose:

Create System Report

Schedule:

Every Day

Time:

18:00

At 18:00, the scheduler will automatically execute the task while the Python application is running.


10. Create an Interval Automation

Select:

Every X Minutes

Enter:

60

That means:

Run
 โ†“
60 minutes
 โ†“
Run
 โ†“
60 minutes
 โ†“
Run

APScheduler's interval trigger is designed for this type of recurring execution.


11. Enable / Disable Tasks

Every task has an:

Enable / Disable

button.

For example:

Daily Backup
๐ŸŸข ENABLED

Tap:

Disable

and the scheduled job stops.

Tap:

Enable

and it becomes active again.


12. Delete an Automation

Tap:

Delete

The task is removed from:

automation.db

and its scheduled job is also removed.


13. How the System Works

The complete flow is:

          Dashboard
              โ”‚
              โ†“
        Create Task
              โ”‚
              โ†“
          SQLite DB
              โ”‚
              โ†“
         APScheduler
              โ”‚
       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”
       โ†“      โ†“      โ†“
     Daily  Interval Cron
       โ”‚      โ”‚      โ”‚
       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”˜
              โ†“
        Python Action
              โ”‚
              โ†“
        Local File/Data

14. Add Your Own Automations

This is the most useful part.

Inside:

execute_action()

you can add additional actions.

For example:

elif action == "weekly_report":

    os.makedirs("data", exist_ok=True)

    filename = datetime.now().strftime(
        "data/weekly-report-%Y-%m-%d.txt"
    )

    with open(filename, "w", encoding="utf-8") as file:

        file.write("Weekly Report\n")
        file.write("================\n")
        file.write(
            f"Created: "
            f"{datetime.now().isoformat()}\n"
        )

Then add the option to the HTML:

<option value="weekly_report">
    Create Weekly Report
</option>

Now it becomes selectable from your dashboard.


15. Ideas You Can Add Later

Your dashboard can eventually handle:

๐Ÿ“ Daily journal
๐Ÿ’พ Local backups
๐Ÿ“Š Automatic reports
๐Ÿ“ File organization
๐ŸŒ Website availability checks
๐Ÿงน Temporary-file cleanup
๐Ÿ“ฆ Automatic archives
๐Ÿ”” Local reminders
๐Ÿ“… Daily planning
๐Ÿ“ˆ Personal statistics

Keep each action explicitly defined in your application rather than allowing users to submit arbitrary shell commands through the web interface.


16. Access It From Another Device

If you want to open the dashboard from your phone on the same Wi-Fi network, change:

host="127.0.0.1"

to:

host="0.0.0.0"

So:

app.run(
    host="0.0.0.0",
    port=5000,
    debug=False
)

Find the computer's local IP.

Windows

ipconfig

Linux

ip addr

Suppose the computer shows:

192.168.1.20

On your phone, open:

http://192.168.1.20:5000

Both devices must be connected to the same network.

Don't expose this development server directly to the public internet. If you eventually make it remotely accessible, add authentication, HTTPS, firewall rules and proper production deployment.


17. Important: Keep Python Running

The scheduler only works while:

app.py

is running.

If you close the terminal:

Python stops
     โ†“
Scheduler stops
     โ†“
Automations stop

For a permanent setup, you can later run the dashboard on an always-on PC, mini-PC, Raspberry Pi or home server.


18. Final Project

Your folder should look like:

personal-automation/
โ”‚
โ”œโ”€โ”€ app.py
โ”‚
โ”œโ”€โ”€ requirements.txt
โ”‚
โ”œโ”€โ”€ automation.db
โ”‚
โ”œโ”€โ”€ data/
โ”‚   โ”œโ”€โ”€ daily-note-2026-10-02.txt
โ”‚   โ””โ”€โ”€ backups/
โ”‚
โ””โ”€โ”€ templates/
    โ””โ”€โ”€ index.html

๐Ÿš€ Final Result

You've created your own local automation dashboard:

       โš™๏ธ AUTOMATION DASHBOARD
                 โ”‚
     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
     โ†“           โ†“           โ†“
  Create       Schedule    History
     โ”‚           โ”‚           โ”‚
     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                 โ†“
            APScheduler
                 โ”‚
        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ†“        โ†“        โ†“
      Notes    Reports  Backups
        โ”‚        โ”‚        โ”‚
        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                 โ†“
            Local Storage

You now have a foundation that can be expanded into a personal Zapier/IFTTT-style dashboard running on your own machine.

Python

https://www.python.org/

Flask

https://flask.palletsprojects.com/

APScheduler

https://apscheduler.readthedocs.io/

APScheduler User Guide

https://apscheduler.readthedocs.io/en/3.x/userguide.html

Python SQLite

https://docs.python.org/3/library/sqlite3.html

APScheduler Interval Trigger

https://apscheduler.readthedocs.io/en/3.x/modules/triggers/interval.html

APScheduler Cron Trigger

https://apscheduler.readthedocs.io/en/3.x/modules/triggers/cron.html

Report Page