トップ画像
妻に家事を頼んでみた【LLM統合スマートホーム】

執筆者: кемо

最終更新: 2025/12/25

はじめに

やあ、KEMOだよ。
突然ですが、家事面倒くさくないですか?面倒くさいですよね。

なので

妻に頼みました。
「配偶者に家事を任せっぱなしにするのは時代錯誤だ」
とか言われそうですが許してください。

準備

まず、そこら辺に転がっているラズパイ5を拾ってきます。
そして余っているミニPCも用意。

ここでAmazonで以下を注文

合計約4万円程度です。ブラックフライデーで買ったのでお安いね!

スマートホームシステム

さて、本題です。用意したものでシステムを構築します。
だいたいこんな感じ(ぐちゃぐちゃmermaid)

頑張って書いたんですけど、クソみたいなレイアウトはどうしようもありませんでした。許して。
もうちょっと簡略化して、頑張ってGoogleSlideで作ったのがこれです。

うーん、それなり。及第点でしょう。

まずはラズパイにHomeAssistantOS(以下HAOS)を入れます。これは名前の通り、スマートホーム用のOSで、これを入れたPCをハブとして扱うことができます。
こいつの優秀な点は他のユーザが作った便利なアドオンを入れられることです。例えば、毎回SSHするのはめんどくさいのでWebSSHというアドオンを入れておく、こうすればダッシュボードからコンソールをいじることができます。

いろいろ接続したHAのダッシュボード

妻に挨拶をしてもらおう

はい、これでHAOSの準備はできました。
でも悲しいことに妻は何もしてくれません。
とりあえず、「いってらっしゃい」と「おかえり」を言ってほしいですね…
つまり、私の外出と帰宅をなんとか知らせたい。
じゃあスマホの位置によって外出と帰宅を検知しましょう。
自宅のエリアにスマホがあれば在宅、なければ不在として、この2つの状態の行き来の際に、声をかけてくれるようにすればよさそうです。

ここで問題発生。妻は自宅にいます。同じWi-Fiに繋がっている間は位置を共有できますが、私が外出した場合、スマホと自宅Wi-Fiの通信はなくなります。こうなっては、妻は私の位置を把握できません。ここは簡易的なVPNでつなぐことにしました。TailScaleをスマホとサーバーにいれます。これに接続すればVPNを使えるようになるので万事解決。ExitNodeを切ったりしないと普通の通信ができなくなります(なぜかMagicDNSも動かない…)。

VPNで常に自宅にいる妻と通信できるようになりました。位置情報だけでなく、支持も送れたり、センシング情報も見れたりするので、外出先からでも自宅に指示を飛ばせます。

本題を忘れてしまうところでした。では私の位置情報をトリガーにして挨拶をするようにします。
はい。

かわいい。

妻に掃除してもらおう

挨拶ができるシステムは掃除もできる!
なので掃除してもらいます。ロボット掃除機を部屋にポン置きして、それをHAOSから操作するだけ。
せっかくなので自動化しましょう。私が日中に外出した場合、自動で掃除を始めたらよさそうです。さっき、「いってらっしゃい」を言ってくれるようにしたので、そこにロボット掃除機を起動するコマンドを追加します。

いい感じ。

余談ですが、今回購入したロボット掃除機のSwitchBot K10はコンパクトかつ(比較的)低価格なので、学生の皆様におすすめです。

おかえりなさいの準備してくれ…

妻は挨拶も掃除もしてくれますが、帰ってきても部屋は寒いままです。
ぬくもりが欲しいですよね。
なので、エアコンをつけてもらいましょう。エアコンの赤外線信号を読み取らせて、スマートリモコンに登録します。これをHAOSから操作することによって実現できそうです。

今回はSwitchBot製品としての統合ではなく、Matterとしての統合を行います。Matterとは、メーカーやOSの垣根を超えてあらゆるスマート家電を繋ぐために作られた通信規格です。このロゴがついた製品であれば、AppleやGoogle、Amazonなどどの会社のスマートスピーカーやスマホからでも、相性を気にせず自由に操作できるようになります。

ということで、登録しました。
先ほどとは少し変えて、自宅から少し離れた場所を通過したときに、エアコンをつけるようにしましょう。自宅に着いた瞬間につけても寒いですからね。

さすが。

My Wife、返事して!

これだけのことしてくれている妻ですが、返事がありません…
なんとか私の声を認識してほしいですね。

ということで、準備したスピーカーフォンの出番です。
OpenWakeWordでウェイクワード(OK,GoogleやAlexaみたいなの)を検出するようにしましょう。OpenWakeWordのカスタムモデルは公式が用意している、このGoogleColabNotebookで学習できます。簡単。

今回はとりあえず「hazuki」と呼びかけるようにしました。
学習方法は認識させたい単語を入れるだけ。ただし、英語音声でしか作れないので「ha zoo_key」とすることで日本語発音に近づけるという方法を使います。
短い単語だとうまく認識できないので、頭に「OK」などを付けると効果的。

正直、精度はあんまよくないです。日本語モデルを作る記事も書くかもしれません。

妻と話そう

やっぱり夫婦の会話って大事だと思うんですよ。

というか、この記事のメインはこれです。本来、一般的なスマートホーム機器は簡易的な意味の分析(「Alexa, 電気付けて」みたいな)をして動作するのですが、この処理をLLMに置き換えます。言ってしまえば、ただの非効率なリソースの無駄遣いなのですが、最大のメリットとして雑談ができます。

作ったのは意味分析とチャット機能、あとLLMに渡すツールです。
まず、マイクがウェイクワードを認識するとSTT(HAOS上のWhisper)を開始します。そして、そのままテキストをミニPCに送ります。
テキストの意味分析後にツールコールしてMQTTにHAOSに対する指示を投げます。
それを読み取ったHAOSが接続された機器に対する操作を行うという流れになっています。
チャット機能を使う場合はMQTTに投げる代わりに、チャットレスポンスを生成して、それをTTS(ミニPC上のCoeiroinkエンジン)で音声に変換。これをHAOSに直接投げ返して、スピーカで再生します。

APIはOpenAI API準拠で作ります。理由は後ほど解説します。
ヘルスチェックとチャットさえあればいいでしょう。

肝心のLLMですが、ミニPC上で3Bの軽量モデルを動かしています。ここで外部API使うのは甘えじゃないですか?

考えてみてください。OpenAIなんて後どれくらいもつかわかりません。AnthropicやGoogleだってそうです。リージョン・アカウントBANや利用料金の大幅な上昇も考えられます。たとえ企業がやらかさなくても、昨今の状況を加味すると、規制の強化でLLMのチャット能力(特に今回のような用途)が低下する or BANの対象になることも想定されます。

こんなやつらに妻を任せていいんですか???

妻の生殺与奪の権をプロバイダに握らせるな!!

コードはここで公開しています。

やっぱ品質が問題なんですよね、3Bモデルだと結構きついです。そのため甘えGeminiフォールバック機能がついていますが、無料枠減少のせいでまともに使えません。この問題を解決するために大学か部のリソースに専用のLLMサーバを寄生させることも考えましたが、さすがに怒られそうなのでやめました。

さて、実はここで少し問題が発生します。HAOSはなんとカスタムAIアシスタントの構築をサポートしているので、ウェイクワード→STT→アシスタント→TTSの流れを簡単に構築できるようになっています。

しかし、このアシスタント部分を自作LLMサービスに置き換える方法がデフォでは存在しません。通常はOpenAI統合を用いてOpenAI APIを使用するのですが、これをなんとか置き換えたい。仕方ないので外部アドオンを使用することのできるHACSという拡張を入れます。そして、そこから拡張版OpenAI統合を落としてきて利用します。アシスタントのベースURLを自作サーバのものに変えれば万事解決です。

実際に動いている様子を載せられないのが悔しい。仕方ないのでデバッグモードでの通常チャットの様子を貼ります。

メイドキャラになってるのは公開用です。流石にそのままは晒せません。

会話(音声付き)

しゃべったと言っても文面です、私しかしゃべってません。
これは悲しいので、声を付けましょう。

まあGoogleTTS等の棒読みっぽい声なら簡単につけれます。なんたってHAOSが普通にサポートしてますからね。でもせっかくならかわいい声で話してほしいよ…

代表的なTTSってなんでしょう?かわいい声といったらVOICEVOXですが、あれは使われすぎてて正直声のイメージが固定されてるんですよね。なんて名乗ろうと、どんな口調だろうと、春日部つむぎは春日部つむぎなんですよ。

COEIRINKを使いましょう。これなら配布モデルとかも簡単につかえるし、比較的にリソースの消費が少なかった気がします。公式からGUI版をとってきて中身のエンジンのみを動かして、それに処理を投げます。都合のいいことにHACSにVOICEVOX TTS統合も落ちていたのでね。これは楽そうですね、COEIROINKはVOICEVOXみたいなもんやし。

そんなうまくいかないんだなあ、これが。VOICEVOXとCOEIROINKではAPIの仕様が割と違います(v2から互換がなくなった)。そのためこれをつなぐ何かが必要なんですね。仕方ないので、アドオンのコードを書き換えます。といってもリクエストを書き直しただけです。気が向いたら公開するかも。

# coeiroink向け調整
try:
    async with aiohttp.ClientSession() as session:
        async with session.post(f"{url}/v1/style_id_to_speaker_meta", params={"styleId": int(speaker)}) as meta_res:
            if meta_res.status != 200:
                _LOGGER.error(f"Failed to fetch speakerUuid for styleId {speaker}")
                return (None, None)
            meta_data = await meta_res.json()
            speaker_uuid = meta_data["speakerUuid"]

        predict_json = {
            "speakerUuid": speaker_uuid,
            "styleId": int(speaker),
            "text": message,
            "speedScale": float(speed),
            "volumeScale": float(volume),
            "pitchScale": float(pitch),
            "prePhonemeLength": 0.1,
            "postPhonemeLength": 0.1,
            "outputSamplingRate": 24000
        }

        _LOGGER.debug(f"Sending predict request to COEIROINK: {predict_json}")
        async with session.post(f"{url}/v1/predict", json=predict_json) as response:
            if response.status != 200:
                error_detail = await response.text()
                _LOGGER.error(f"Predict failed with status {response.status}: {error_detail}")
                return (None, None)
            
            data = await response.read()
            _LOGGER.debug("Audio data (WAV) received directly from predict")
            return ("wav", data)

except Exception as err:
    _LOGGER.error(f"Unexpected error in TTS request: {err}")
    return (None, None)

残念ながら問題がもう一つ残っています。エンジンがローカルホスト(127.0.0.1)で受け付けているので、HAOSからAPIを叩けません。これはsocatで迂回させることによって解決します。要は、特定ポートに飛んできたリクエストを、ローカルホストの特定ポートへのリクエストへ回します。

socat TCP-LISTEN:{PORT},fork,reuseaddr TCP:127.0.0.1:{PORT}

ここまでした価値のある可愛さです。エンジンはミニPCに積んでるので、そっちで適当に切り替えるだけで声はいくらでも変えられます。

今後の展望・将来性

拡張性は高めだと思います
一応、

  • ライフログ・ナレッジベースアプリの統合(半年前から放置)
  • 交通機関・天気予報ツールの追加
  • スマートカーサービスへの接続(一敗)
  • アバターの表示(去年頓挫)

あたりを計画しています。

最重要計画はアバターの表示です、今は妻の姿が見えなくて悲しい。クソデカディスプレイを買う準備ができてないので仕方ないね。
というか本来、アバター表示とアプリ統合をメインにする予定でした。しかし、なぜか予定が増え続けているため、すべてが後ろ倒しになっています。

やったら記事出しますね。

おわりに

これ現実に存在するコンテンツなんですね。
実際に人同士でやっている方々がいるのか…

今日(投稿日)はクリスマスらしいです。

おわああああああああ【完】

爆散するKEMO
取得に失敗しました

2023年度 入部

GitHub