(更新: 2026.04.08)

Google Calendar統合でタスク管理を進化:DASHとの連携実装

はじめに

タスク管理システム(DASH)とGoogle Calendarを統合することで、タスク登録・期限管理・リマインダーを一元化できます。この記事では、複数Googleアカウントを扱いながらカレンダー連携を実現する実装を紹介します。

統合の目的

タスク追加時の自動カレンダー登録

DASHにタスクを追加すると、自動的にGoogle Calendarにも登録されます。

ユーザー: 「3/30までにニチギワールド様対応」
  ↓
DASHに登録(tasks.json)
  ↓
Google Calendar(クロスリンク)に自動登録

複数アカウント対応

アカウント判定に基づいて、適切なGoogle Calendarに振り分けます。

  • クロスリンク → work@example.com
  • プログラミングスクール → school@example.com

実装:Calendar API統合

認証設定

各アカウントのOAuth2トークンを管理します。

from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build

CALENDAR_SCOPES = ['https://www.googleapis.com/auth/calendar']

def authenticate_calendar(account):
    """
    アカウント別のCalendar API認証
    """
    token_map = {
        "crosslink": "token_calendar_crosslink.json",
        "programming_school": "token_calendar_programming.json"
    }

    token_path = token_map[account]
    creds = Credentials.from_authorized_user_file(token_path, CALENDAR_SCOPES)

    return build('calendar', 'v3', credentials=creds)

タスク→カレンダーイベント変換

def task_to_calendar_event(task):
    """
    DASHタスクをGoogle Calendarイベントに変換
    """
    event = {
        "summary": task["title"],
        "description": f"チーム: {task['team']}\n優先度: {task['priority']}\n推定時間: {task['estimated_minutes']}分",
        "colorId": get_color_by_priority(task["priority"])
    }

    # 期限あり → 終日イベント
    if task["due_date"]:
        event["start"] = {"date": task["due_date"]}
        event["end"] = {"date": task["due_date"]}

    # 時刻指定あり → 時刻付きイベント
    if task.get("due_time"):
        start_datetime = f"{task['due_date']}T{task['due_time']}:00+09:00"
        end_datetime = calculate_end_time(start_datetime, task["estimated_minutes"])

        event["start"] = {"dateTime": start_datetime, "timeZone": "Asia/Tokyo"}
        event["end"] = {"dateTime": end_datetime, "timeZone": "Asia/Tokyo"}

    return event

def get_color_by_priority(priority):
    """
    優先度に応じた色ID
    """
    color_map = {
        "high": "11",  # 赤
        "medium": "5",  # 黄
        "low": "2"  # 緑
    }
    return color_map.get(priority, "1")

自動登録フロー

def add_task_with_calendar_sync(task_text):
    """
    タスクを追加し、Google Calendarにも登録
    """
    # 1. AI判定でタスク分類
    task = add_task_auto(task_text)

    # 2. Google Calendarに登録
    try:
        service = authenticate_calendar(task["account"])
        event = task_to_calendar_event(task)

        result = service.events().insert(
            calendarId='primary',
            body=event
        ).execute()

        # カレンダーイベントIDを保存
        task["calendar_event_id"] = result["id"]
        save_task(task)

        print(f"📅 Google Calendarに登録完了: {task['title']}")

    except Exception as e:
        print(f"⚠️ カレンダー登録失敗: {e}")
        print("   タスクはDASHに保存済み")

    return task

カレンダー→タスク同期

外部イベントの取り込み

Google Calendarに直接追加されたイベントをDASHに取り込みます。

def sync_calendar_to_dash(account, days_ahead=7):
    """
    Google Calendarの新規イベントをDASHに同期
    """
    service = authenticate_calendar(account)

    # 今後N日間のイベントを取得
    now = datetime.now().isoformat() + 'Z'
    end = (datetime.now() + timedelta(days=days_ahead)).isoformat() + 'Z'

    events_result = service.events().list(
        calendarId='primary',
        timeMin=now,
        timeMax=end,
        singleEvents=True,
        orderBy='startTime'
    ).execute()

    events = events_result.get('items', [])

    for event in events:
        event_id = event['id']

        # 既にDASHに登録済みか確認
        if is_event_in_dash(event_id):
            continue

        # 新規イベント → DASHに追加
        task = calendar_event_to_task(event, account)
        add_task_to_dash(task)

        print(f"📥 カレンダーから取り込み: {task['title']}")

イベント→タスク変換

def calendar_event_to_task(event, account):
    """
    Google CalendarイベントをDASHタスクに変換
    """
    title = event.get('summary', '無題')
    description = event.get('description', '')

    # 開始日時の取得
    start = event['start'].get('date') or event['start'].get('dateTime', '').split('T')[0]

    task = {
        "id": f"task-calendar-{event['id'][:8]}",
        "title": title,
        "account": account,
        "team": "general",  # 外部イベントはgeneral扱い
        "priority": "medium",
        "status": "todo",
        "due_date": start,
        "calendar_event_id": event['id'],
        "source": "calendar",
        "created_at": datetime.now().isoformat(),
        "notes": description
    }

    return task

リマインダー機能

30分前通知

Cronジョブでカレンダーをチェックし、開始30分前にリマインド通知します。

#!/bin/bash
# calendar_integration.sh remind <minutes>

MINUTES=${1:-30}

python3 << 'EOF'
import sys
from datetime import datetime, timedelta
from google_calendar_api import authenticate_calendar, get_upcoming_events

minutes = int(sys.argv[1]) if len(sys.argv) > 1 else 30

now = datetime.now()
end_time = now + timedelta(minutes=minutes)

# 両アカウントをチェック
for account in ['crosslink', 'programming_school']:
    service = authenticate_calendar(account)
    events = get_upcoming_events(service, now, end_time)

    if events:
        for event in events:
            start_str = event['start'].get('dateTime', event['start'].get('date'))
            print(f"📅 {account.upper()}: {event['summary']} ({start_str})")

if not any_events:
    print("✅ 予定なし")
EOF

Cron設定

{
  "name": "会議準備リマインダー(30分前)",
  "schedule": {
    "kind": "every",
    "everyMs": 900000
  },
  "sessionTarget": "isolated",
  "payload": {
    "kind": "agentTurn",
    "message": "cd ~/.openclaw/workspace/dash && bash calendar_integration.sh remind 30"
  },
  "delivery": {
    "mode": "announce"
  }
}

双方向同期

タスク完了時のカレンダー更新

DASHでタスクを完了すると、カレンダーイベントも完了ステータスに更新します。

def complete_task_with_calendar_sync(task_id):
    """
    タスク完了時、カレンダーイベントも更新
    """
    task = get_task(task_id)

    # DASHで完了
    task["status"] = "done"
    task["completed_at"] = datetime.now().isoformat()
    save_task(task)

    # カレンダーイベントを更新(色を灰色に)
    if task.get("calendar_event_id"):
        try:
            service = authenticate_calendar(task["account"])

            event = service.events().get(
                calendarId='primary',
                eventId=task["calendar_event_id"]
            ).execute()

            event["colorId"] = "8"  # 灰色(完了)
            event["summary"] = f"✅ {event['summary']}"

            service.events().update(
                calendarId='primary',
                eventId=task["calendar_event_id"],
                body=event
            ).execute()

            print(f"📅 カレンダーも完了に更新: {task['title']}")

        except Exception as e:
            print(f"⚠️ カレンダー更新失敗: {e}")

カレンダーイベント削除時の同期

カレンダーからイベントを削除したら、DASHタスクも削除します(定期チェックで検出)。

def detect_deleted_calendar_events():
    """
    カレンダーから削除されたイベントを検出し、DASHからも削除
    """
    tasks = load_tasks()

    for task in tasks["tasks"]:
        if not task.get("calendar_event_id"):
            continue

        try:
            service = authenticate_calendar(task["account"])
            event = service.events().get(
                calendarId='primary',
                eventId=task["calendar_event_id"]
            ).execute()

        except Exception as e:
            if "deleted" in str(e).lower() or "404" in str(e):
                # カレンダーから削除済み → DASHからも削除
                delete_task(task["id"])
                print(f"🗑️ カレンダー削除に同期: {task['title']}")

まとめ

DASHとGoogle Calendarを統合することで、タスク管理が飛躍的に効率化されます。複数アカウント対応・双方向同期・リマインダー機能により、見落としやダブルブッキングを防げます。

関連記事:
– AI駆動タスク自動振り分け
– Gmail重要メール監視システム構築
– OpenClaw Cronジョブ活用術