はじめに:テレワークの運動不足を「技術」で解決する
クラウドエンジニアの皆さん、運動していますか?
私は毎日リモートワークで、気づけば一日中座りっぱなし……という日が珍しくありません。
「1時間おきに運動すればいい」と分かっていても、自分に甘いのが人間です。そこで思いました。
「サボったらLINEで怒られるシステムを作ればいいのでは?」 と。
しかし、私は普段インフラ設計がメインで、アプリケーションコード(Pythonなど)を書くのは正直苦手です。
そこで今回は、特別な開発ツールは一切使わず、「Gemini」 と 「Google Cloud Shell」 だけを使って、完全AI任せでの構築に挑戦しました。
- ロジック(コード): Gemini に書いてもらう
- インフラ(デプロイ): Gemini にコマンドを作ってもらい、Cloud Shellに貼り付ける
ローカル環境の構築すら不要。ブラウザだけで完結させた記録を共有します。
構想フェーズ:AIを「壁打ち相手」にして要件を固める
いきなり作り始める前に、まずは Gemini とチャットをして「どんな構成にするか」を相談しました。
この 「要件定義の壁打ち」 が非常に実りある時間でした。
1. クラウド選定:AWS か Google Cloud か?
普段業務で使っているのは AWS ですが、今回は個人開発です。
Gemini に相談したところ、「個人の小規模アプリなら、Cloud Run (Functions Gen2) の無料枠が手厚い Google Cloud がおすすめ」 と提案されました。
また、私自身が最近 Google Cloud認定資格 (PCA: Professional Cloud Architect) を取得したばかりだったので、「得た知識を実際の構築で試してみたい」というモチベーションとも合致し、Google Cloudの採用即決となりました。
2. 入力デバイス:物理ボタン か スマホ か?
当初は「IoTボタンのような物理デバイスを買おうか」とも悩みましたが、Gemini は「手持ちの Apple Watch と iPhone のショートカット機能を使えば、追加ハードウェアなしで実現できる」 と提案してくれました。
実はこれ、私にとって渡りに船でした。
ちょうど Apple Watch を買ったばかり で、単なる時計や通知確認以外に「ガジェットとして面白い使い道はないか?」と探していたタイミングだったからです。
作ったもの:サーバーレス・スクワット監視
今回構築したシステムの全体像はこちらです。

処理の流れ
- Input: Apple Watchの「ショートカット」ボタンをタップ。
- Process: Cloud Run functions がリクエストを受け、Firestoreに「スクワット実施ログ」を保存。
- Monitoring: Cloud Schedulerが平日9時〜18時の間、1時間おきに巡回。
- Notification: 直近1時間にログがなければ、LINE Messaging API経由で「座りっぱなしです!」と警告通知。
0. 前準備:土台を整える
AIにコードを書かせる前に、データの保存先と通知の宛先だけは用意する必要があります。
1. LINE Messaging API の開設
LINE Developersコンソールでチャネルを作成し、以下の2つを取得して控えておきます。
- チャネルアクセストークン(長期)
- ユーザーID(自分のLINEアカウント宛)
※LINE Messaging APIの具体的な開設手順やコンソールの操作については、過去記事「Amazon Bedrockでブログ要約をLINE通知する」で解説しています。設定に迷った場合は、こちらも合わせて参考にしてください。
2. Firestore (データベース) の作成
Google Cloud側でデータを保存する場所を作ります。ここもGUIでポチポチやってもいいのですが、せっかくなので Gemini に頼んでみました。
Geminiへの指示:
「Firestoreをネイティブモードで、東京リージョン(asia-northeast1)に作成するコマンドを教えて」
提示されたコマンドを Cloud Shell に貼り付けて実行し、一瞬でデータベースの準備が完了しました。
# 実際に実行したコマンド gcloud firestore databases create --location=asia-northeast1
※初めて実行する場合、「APIを有効にしますか?」と聞かれるので Y を押して進めます。
開発フェーズ1:Geminiに「ロジック」を書かせる
土台ができたらアプリケーションのコード(Python)です。
ここでのポイントは、「自分では1行も書かない」ことです。
普段ならエディタを開いて「どう書くんだっけ…」と悩みますが、今回は Gemini に向かって、やりたいことをそのまま伝えました。
Geminiへの相談内容:
「Apple Watchからデータを受け取ってFirestoreに保存したい」
「1時間おきにチェックして、データがなかったらLINEに警告を送る機能がほしい」
このように要件を伝えていくと、Gemini はすぐに main.py のコード全文を生成してくれました。
私は内容をざっと見て、おかしなところがないか確認するだけです。
実際に作成されたコードがこちらです。
(※トークン部分は環境変数から読み込むように記述されています)
作成された main.py
import os from datetime import datetime, timedelta import pytz import functions_framework from google.cloud import firestore from linebot import LineBotApi from linebot.models import TextSendMessage
Firestoreクライアントの初期化
db = firestore.Client() JST = pytz.timezone('Asia/Tokyo')
@functions_framework.http def record_squat(request): """ Apple Watchからのリクエストを受け取り、 Firestoreに現在時刻と回数を保存する関数 """ doc_ref = db.collection('squat_logs').document() doc_ref.set({ 'created_at': datetime.now(JST), 'count': 10 }) return 'Squat Recorded!', 200
@functions_framework.http def check_and_notify(request): """ 直近1時間のログを確認し、 運動していなければLINEに通知を送る関数 """ # LINE設定の読み込み(ここで読み込まないとエラーになるため) line_access_token = os.environ.get('LINE_CHANNEL_ACCESS_TOKEN') line_user_id = os.environ.get('LINE_USER_ID')
if not line_access_token or not line_user_id:
# 環境変数が設定されていない場合はエラーを返す
print("Error: LINE configuration not found.")
return 'Error: Env vars not set', 500
# トークンがある場合のみ初期化
line_bot_api = LineBotApi(line_access_token)
now = datetime.now(JST)
one_hour_ago = now - timedelta(hours=1)
# 1時間以内のログがあるか検索
docs = db.collection('squat_logs') \
.where('created_at', '>=', one_hour_ago) \
.limit(1) \
.stream()
if any(docs):
return 'Good Job! You moved.', 200
else:
# ログがなければ警告送信
try:
line_bot_api.push_message(
line_user_id,
TextSendMessage(text='⚠️ 座りっぱなしです!スクワットをしてください!')
)
return 'Alert Sent', 200
except Exception as e:
print(f"LINE Error: {e}")
return 'Error sending notification', 500
また、Geminiは必要なライブラリをまとめた requirements.txt も教えてくれました。
これも同じ場所に保存します。これが抜けているとデプロイ時にエラーになるので注意してください。
requirements.txt
google-cloud-firestore line-bot-sdk functions-framework pytz
【Tips】Cloud Shell エディタを使うと便利
ファイルの作成は、ターミナルでコマンドを叩かなくても大丈夫です。
画面上部にある 「エディタを開く(鉛筆アイコン)」 をクリックすると、VS Codeのような画面が開きます。
そこで右クリックして「新しいファイル」を作成し、上記のコードを貼り付けるのが一番カンタンです。
開発フェーズ2:Geminiで「インフラ」を作る
コードができたらデプロイです。
ここでは、Geminiに生成してもらったコマンドを少し調整して、「記録用」と「監視用」の2つの関数をデプロイしました。
1. 記録用関数のデプロイ
Apple Watchから叩かれる関数です。認証なしでアクセスできるように設定します。
gcloud functions deploy record-squat
--gen2
--runtime=python311
--region=asia-northeast1
--source=.
--entry-point=record_squat
--trigger-http
--allow-unauthenticated
※途中「APIを有効にしますか?」と聞かれたら Y で進めてください。
2. 監視用関数のデプロイ
こちらはLINEへの通知機能を持つため、環境変数でトークンを渡します。
(※コマンド内の [YOUR_TOKEN] などの部分は、前準備で控えた自分の値に書き換えて実行してください)
gcloud functions deploy check-and-notify
--gen2
--runtime=python311
--region=asia-northeast1
--source=.
--entry-point=check_and_notify
--trigger-http
--allow-unauthenticated
--set-env-vars LINE_CHANNEL_ACCESS_TOKEN="[YOUR_TOKEN]",LINE_USER_ID="[YOUR_ID]"

【Tips】Cloud Functions と Cloud Run の関係
デプロイ完了後、コンソールを確認して少し驚きました。
「Cloud Functions」を作ったはずが、「Cloud Run」 のサービス一覧に表示されていたからです。

実はこれ、現在の Google Cloud の仕様です。
第2世代の Functions (Gen2) は、裏側の実体が Cloud Run で動いています。そのため、名称も現在は Cloud Run functions となっており、このように Cloud Run の管理画面からも「関数」として確認できるのです。
3. 定期実行(Cloud Scheduler)の設定
最後に、監視用関数を「平日の9時〜18時の間、1時間おき」に実行するジョブを作成しました。
(※ uri の部分は、check-and-notify のデプロイ後に表示されたURLを入れてください)
gcloud scheduler jobs create http squat-police-job
--schedule="0 9-18 * * 1-5"
--time-zone="Asia/Tokyo"
--uri="[監視用関数 check-and-notify のURL]"
--http-method=GET
次のステップへの準備:URLをコピーする
すべてのデプロイが完了したら、Apple Watch用に 「記録用関数 (record-squat)」のURL を控えておきます。
(Cloud Run のサービス詳細画面で、record-squat の名前の下にあるURLをコピーするのが簡単です)
連携設定:物理世界とクラウドを繋ぐ
バックエンドができたら、あとはApple Watchの設定です。
iPhoneの「ショートカット」アプリを開き、新しいショートカットを作成します。
使うアクションは 「URLの内容を取得」 です。
- URL: 先ほどコピーした
record-squatのURL - 方法 (Method):
POSTに変更(これをしないと動きません!)

これを「Apple Watchに表示」設定にするだけで、手首に「スクワット完了ボタン」が出現します。
結果:こうなりました
実際に運用してみた様子がこちらです。
1. サボった時
1時間以上ボタンを押さないと、Cloud Schedulerが作動し、容赦なくLINEが飛んできます。(※画像はテスト通知時の画面です)

2. ちゃんと運動した時
スクワットをしてApple Watchのボタンを押すと、Firestoreにデータが保存されます。
データもバッチリ届いています。
このログがある限り、次の監視タイミングでは通知がスキップされます。
「LINE通知を止めるためにスクワットをする」 という、奇妙ですが強力な習慣化サイクルが完成しました。
まとめ:インフラエンジニアこそAIを使うべき
今回、簡単なアプリ構築を通して感じたことは以下の3点です。
- ブラウザひとつで開発が完結するCloud ShellとGeminiさえあれば、環境構築もコーディングもデプロイもすべて完結します。
- インフラ操作は「対話」で行う時代へCLIコマンドを暗記しなくても、やりたいことを伝えれば適切なコマンドが出てきます。
- サーバーレス × 個人開発の相性の良さ今回の構成(Cloud Run functions + Firestore)なら、個人利用レベルではほぼ無料です。
AWSエンジニアの私にとって、Google Cloudの Cloud Shell の手軽さと、Geminiによる的確なコマンド支援は強力な武器になると感じました。
皆さんも、AIを相棒にして「自分専用の便利ツール」を作ってみてはいかがでしょうか?


