7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

夫婦の家事事情をAlexaとTrelloで解決した話

Last updated at Posted at 2021-02-15

0.前日譚

我が家(共働き・夫婦二人暮らし)の家事の分担は原則「気づいたものがやる」で回っています。
この「気づいたものがやる」はある意味で平等に見えるのですが、その実、気が利く者の方が損をするシステムでもあります。

早い話、僕が、
「洗濯回さなきゃな、ゴミ捨てなきゃな、あと皿も洗わなきゃな」
と考えている一方、妻が、
「洗濯、コンロ磨き、カーテンにリセッシュ、バスマットの除菌、洗剤の詰め替え、ゴミ捨て、トイレ掃除、床掃除、シーツの取り換え、テレビの埃拭き、皿洗い etc etc...」
と、いろんな家事をタスクとして積んでいれば、担当する家事のタスク量も全く違うわけですね。

image.png
※イメージ図です

このことを先日、妻が言いにくそうに指摘してきたため、僕は「確かにそうだなぁ」と思いました。(今まですまぬ。。。妻よ。。。)

1.Trelloの導入

というわけで現状課題の分析と理想像を策定。

  • AsIs
    • 家事が二人の間で共有されておらず、妻側にとって納得感を持った家事の分担ができていない。
  • ToBe
    • 家事のリストを見える化し、お互いに家事の一覧がいつでも確認できる。その上で二人の協議を以て家事を分担する。(お互いを尊重する気持ちが大事)

タスクの見える化と言えば、まず真っ先にタスク管理ツールが思い浮かびます。
その中でも、操作が簡単で、全体的なレイアウトもシンプルな、Trelloを採用することとしました。
スマホアプリ版もあるので、「お互いに家事の一覧がいつでも確認できる」という要件も満たせます。

ここまで決めたところで、ふと、我が家のリビングに鎮座する専ら音楽再生機と化しているecho show君が目に入ります。
Alexa……、お前、やれるのか……?

#2. Alexaスキル開発

Alexaにてタスク名を登録できるようになれば、それすなわち、声出しによる互いの家事の共有になるのではないかという発想。
システム概略図は下記みたいな感じです。

image.png

上記を実現するため、早速、AlexaSkillsKitを用いて、開発していきます。

なお、Amazonアカウントの取得やAlexaスキルの基礎的な開発方法は下記のチュートリアルに譲ります。
チュートリアル

まず、想定されるタスク名は任意(「風呂掃除」、「買い出し」等)であるため、Alexaに任意の言葉を認識させるため、インテントの設定を行います。

{
    "interactionModel": {
        "languageModel": {
            "invocationName": "家事の追加",
            "intents": [
                {
                    "name": "TaskIntent",
                    "slots": [
                        {
                            "name": "task",
                            "type": "any"
                        }
                    ],
                    "samples": [
                        "{task}"
                    ]
                },
                {
                    "name": "AMAZON.CancelIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.HelpIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.StopIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.NavigateHomeIntent",
                    "samples": []
                }
            ],
            "types": [
                {
                    "name": "any",
                    "values": [
                        {
                            "name": {
                                "value": "ほげほげ"
                            }
                        }
                    ]
                }
            ]
        }
    }
}

image.png

image.png

TaskIntentは任意の言葉が入るサンプル発話{task}を持ちます。
また{task}のスロットタイプにanyを作成し、スロット値は適当にほげほげとしておきます。
本来、Intentはスキルに対するユーザの意図を表すため、このような何でも許容する設定は推奨されませんが、今回はタスク名を自由発話させたいため、上記設定で行きます。

Intentの設定が完了しましたので、次にコードです。
今回はTrelloにアクセスするライブラリとしてpy-trelloを用いることとしました。
lamdaサーバにてpy-trelloを扱うために、まずは設定ファイルを書き換えます。

requirements.txt
boto3==1.9.216
ask-sdk-core==1.11.0
py-trello

続いて、lamda_function.pyを以下のコードを記述します。

lamda_function.py
from ask_sdk_core.skill_builder import SkillBuilder
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.dispatch_components import AbstractExceptionHandler
from ask_sdk_core.handler_input import HandlerInput

from ask_sdk_model import Response
from trello import TrelloClient

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

class LaunchRequestHandler(AbstractRequestHandler):
    """Handler for Skill Launch."""
    def can_handle(self, handler_input):
        # type: (HandlerInput) -> bool

        return ask_utils.is_request_type("LaunchRequest")(handler_input)

    def handle(self, handler_input):
        # type: (HandlerInput) -> Response
        speak_output = "登録するタスク名を教えて下さい。"
        
        return (
            handler_input.response_builder
                .speak(speak_output)
                .ask(speak_output)
                .response
        )


class TaskIntentHandler(AbstractRequestHandler):
    def can_handle(self, handler_input):
        # type: (HandlerInput) -> bool
        return ask_utils.is_intent_name("TaskIntent")(handler_input)

    def handle(self, handler_input):
        # type: (HandlerInput) -> Response
        
        # ユーザ発話内容をそのまま取得
        task_name = handler_input.request_envelope.request.intent.slots["task"].value
        
        # Trelloのkeyとsecretを設定
        client = TrelloClient(
            api_key='XXXXXXXXXXXXX',
            api_secret='XXXXXXXXXXXXX',
        )
        
        # TrelloのボードIDとリストIDを設定
        BOARD_ID="XXXXXXXXXXXXX"
        board=client.get_board(BOARD_ID)
        LIST_ID="XXXXXXXXXXXXX"
        target_list=board.get_list(LIST_ID)
        
        # Trelloにカードを追加
        target_list.add_card(task_name)
        
        # Alexaの発話内容を設定
        speak_output = task_name + " を登録しました。"

        return (
            handler_input.response_builder
                .speak(speak_output)
                # .ask("add a reprompt if you want to keep the session open for the user to respond")
                .response
        )

#デフォルトコードは記載を割愛
class HelpIntentHandler(AbstractRequestHandler):
class CancelOrStopIntentHandler(AbstractRequestHandler):
class SessionEndedRequestHandler(AbstractRequestHandler):
class IntentReflectorHandler(AbstractRequestHandler):
class CatchAllExceptionHandler(AbstractExceptionHandler):

sb = SkillBuilder()

sb.add_request_handler(LaunchRequestHandler())
sb.add_request_handler(TaskIntentHandler())
sb.add_request_handler(HelpIntentHandler())
sb.add_request_handler(CancelOrStopIntentHandler())
sb.add_request_handler(SessionEndedRequestHandler())
sb.add_request_handler(IntentReflectorHandler()) # make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers

sb.add_exception_handler(CatchAllExceptionHandler())

lambda_handler = sb.lambda_handler()

ポイントはhandler_input.request_envelope.request.intent.slots["task"].valueで設定したIntentに対するユーザ発話が取得できるところです。

なお、上記コードのAPIキーとボードID/リストIDは自分用に読み替えて下さい。

TrelloのAPIキーの取得は下記から可能です。
https://trello.com/app-key

また、ボードIDとリストIDの取得は下記コードを実行すれば取得できます。

GetTrelloID.py
from trello import TrelloClient

client = TrelloClient(
    api_key='XXXXXXXXXXXXX',
    api_secret='XXXXXXXXXXXXX',
)

boards=client.list_boards()
for board in boards:
    print(board.name)
    print(board.id)
    print(board.url)
    lists = board.all_lists()
    for list_ in lists:
        print("    " + list_.name)
        print("    " + list_.id)
        print("    ---------------")
    print("---------------")

これで、ひとまずAlexa側のコーディングは完了。デプロイして実行してみます。

#3. 実行イメージ

  1. 発話にてAlexaに家事の追加を指示。
    image.png

  2. その後のTrelloの画面
    image.png

#4. 実証

さて、実際にこのAlexaスキルを妻に説明して、運用してみたところ、

想像以上に好評でした。

※下記は実際の我が家のTrelloです。(画像はPC版です)
image.png

  • Trelloによるタスク管理はシンプルで使いやすい
  • 家事の全てが見える化できて、タスクの偏りによる不公平が生じない
  • 発話することで家事を登録するため、家事に対する連帯感が沸く
    • また、発話自体が互いのタスクの確認になるため、手間が省ける

妻からは等々のフィードバックを頂きました。(ありがてえ)

今後、運用を回し、新たな要件・問題点等が生じたら、逐次対応していくつもりです。

#5. 余談

開発中に気づいたんですけど、
AlexaはデフォルトでToDo機能を持ってるんですね。(悲)
Amazon Alexa で Todoist を使う

#6. 参考文献

(公式)チュートリアル
(公式)スキルのサンプル 日本語情報が少なくて、サンプルコードが正直一番参考になった。
ユーザーの自由発話に対応する Alexa Skill を作る
TrelloAPIをpythonで使う

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?