⏱️

【タスク管理・定期情報通知】Apple Watchを便利に使う

2022/05/23に公開

ついにAppleWatchを購入した。
色々仕事が忙しくなりPC上でタスク管理がしんどくなってきたのと、健康ロガー機能が前々から気にはなっていた。遂に買ってしまった。所謂時計の奴隷。

公式の健康ロガーはかなり便利なので、手を入れる余地はあまり無いんだが
タスク管理やニュース等をAppleWatchで便利に使うには色々痒い所に手が届いていない。
という訳で、色々組み立ててみた。

タスク管理

タスク管理はThings3が最高だったので即採用。
文字盤の画面でタスク3個表示できるのが圧倒的魅力である。
AppleWatchで気軽に今日のタスクを翌日に変更できるのも良き。
本当に超良いアプリなのだけれど、残念ながらwindows版が無い。さてどうするか。

Windowsでのタスク入力はTodoistが便利。なんとAPIも使える。
という訳で、PCからのタスク入力はTodoistを使い定期的にpythonでTodoistに記入されたタスクをThings3に転送する作戦へ。(pythonを実行するPCはraspberry piで運用)
Things3はiOSのショートカットでタスクを追加できるようになっているので、これを使う。

処理のフローは下記の感じ

  1. Todoistでタスク入力(windows)
  2. python(todoistから今日のタスクだけ読み込み task.txtに変換)
  3. python(dropboxにtask.txtをアップロード)
  4. iOSショートカットでtask.txtを読み込みリストに変換
  5. ループ処理でThings3にタスク追加する。

注意点としてはショートカットでThings3のタスクを消す操作は無いので、基本的に朝1回本日のタスクをTodoistから読み込みThings3へ転送するしかない。
なので、当日のタスクはiPhoneから入力するのが良いだろう。

朝一に知りたい情報を通知するようにしたい。

Twitterの通知はtweet内容もAppleWatchで表示されるので、それを軸に情報通知処理を組み立てた。

  1. 朝に1回S&P500の株価を自動ツイートするBotを用意(上記のraspberry pi)
  2. それをフォロー、ツイートしたら通知する設定。

【余談】
iPhoneには通知しないで、AppleWatchのみ通知みたいな設定が全アプリでできればめっちゃ嬉しいんだけど、あんまり通知関係は力入れていないっぽいんだよなー。
今後は株価だけじゃなくて、良い感じのニュースとかツイートできるようにしたい。


処理2.3.のpythonコードは下記。ライブラリもりもり。公式Exampleもりもり。
なので、特にコメントすることはないが、Raspberry piでcronとpythonの組み合わせが上手く動かなかったので、scheduleライブラリを使って定期実行を行っている。

from ast import If
from http import client
import os
from pandas_datareader.stooq import StooqDailyReader
from datetime import datetime, timedelta, date
import tweepy
from os.path import join, dirname
from dotenv import load_dotenv
import schedule
import time
from todoist_api_python.api import TodoistAPI
import dropbox

dotenv_path = join(dirname(__file__), '.env')
load_dotenv(dotenv_path)
API_KEY = os.environ.get("API_KEY")
API_KEY_SECRET = os.environ.get("API_KEY_SECRET")
BEARER_TOKEN = os.environ.get("BEARER_TOKEN")
ACCESS_TOKEN = os.environ.get("ACCESS_TOKEN")
ACCESS_TOKEN_SECRET = os.environ.get("ACCESS_TOKEN_SECRET")
todoist_API_token = os.environ.get("TODOIST_API")
DROP_API_KEY_SECRET = os.environ.get("DROP_API_KEY_SECRET")
DROP_API_KEY = os.environ.get("DROP_API_KEY")

#dropbox認証
dropbox_path = "/watch/task.txt"
computer_path = "/home/pi/radiberry/todaytask.txt"
client = dropbox.DropboxOAuth2FlowNoRedirect(
    consumer_key=DROP_API_KEY, use_pkce=True,  token_access_type="offline")
authorize_url = client.start()
print("1. Go to: " + authorize_url)
print("2. Click \"Allow\" (you might have to log in first).")
print("3. Copy the authorization code.")
auth_code = input("Enter the authorization code here: ").strip()
try:
    oauth_result = client.finish(auth_code)
except Exception as e:
    print('Error: %s' % (e,))
    exit(1)
with dropbox.Dropbox(oauth2_refresh_token=oauth_result.refresh_token, app_key=DROP_API_KEY) as dbx:
    dbx.users_get_current_account()
    print("Successfully set up client!")

#株価ツイート
def job_tweet():
    start = datetime.today() - timedelta(hours=61)
    end = datetime.today() - timedelta(hours=13)
    brand = '^SPX'

    stooq = StooqDailyReader(brand, start=start, end=end)
    data = stooq.read()  # pandas.core.frame.DataFrame
    print(data)
    print(type(data.iloc[-1]))
    print(data.iloc[-1])

    today_sp500 = data.iloc[0]
    yesterday_sp500 = data.iloc[-1]

    print("--------------------------------")
    print(today_sp500.iloc[3])
    print(yesterday_sp500.iloc[3])

    # Twitter認証
    auth = tweepy.OAuthHandler(API_KEY, API_KEY_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
    api = tweepy.API(auth)

    sa_sp500 = today_sp500.iloc[3] - yesterday_sp500.iloc[3]

    p_sp500 = (sa_sp500/yesterday_sp500.iloc[3])*100

    print(round(sa_sp500, 2))
    print(round(p_sp500, 2))
    plus = "+"
    if(sa_sp500 < 0):
        plus = ""
    # ツイート
    api.update_status("S&P500:" + str(round(today_sp500.iloc[3], 2))+"\n"+"∴" + plus + str(round(
        sa_sp500, 2))+"【" + plus + str(round(p_sp500, 2))+"%】")

#タスク読み込みとアップロード
def job_task():
    f = open('todaytask.txt', 'w')
    api = TodoistAPI(todoist_API_token)
    d_today = date.today()
    # print("d_today"+str(d_today))
    try:
        tasks = api.get_tasks()
        first_wite = True
        for task in tasks:
            due = task.due
            if due != None and due.date == str(d_today):
                if first_wite:
                    f.write(task.content)
                    first_wite = False
                else:
                    f.write("\n" + task.content)
    except Exception as error:
        print(error)
    f.close()
    dbx.files_upload(open(computer_path, "rb").read(),
                     dropbox_path, mode=dropbox.files.WriteMode.overwrite)
    print("アップロード:{}".format(computer_path))
    print(str(d_today))


schedule.every().monday.at("07:20").do(job_tweet)
schedule.every().tuesday.at("07:20").do(job_tweet)
schedule.every().wednesday.at("07:20").do(job_tweet)
schedule.every().thursday.at("07:20").do(job_tweet)
schedule.every().friday.at("07:20").do(job_tweet)
schedule.every().saturday.at("07:20").do(job_tweet)

schedule.every().monday.at("07:00").do(job_task)
schedule.every().tuesday.at("07:00").do(job_task)
schedule.every().wednesday.at("07:00").do(job_task)
schedule.every().thursday.at("07:00").do(job_task)
schedule.every().friday.at("07:00").do(job_task)
schedule.every().saturday.at("07:00").do(job_task)

while True:
    schedule.run_pending()
    time.sleep(600)

Discussion