朝6〜7時だけ!電車の遅延をGoogle Homeが自動アナウンス

Google Home

毎朝の通勤前、電車が遅れているかどうかをスマホで調べるのって地味に手間じゃないですか?
この記事では、Raspberry Pi と Google Home を使って、朝6〜7時の時間帯だけ自動的に電車の遅延情報をアナウンスする仕組みを紹介します。Yahoo!路線情報をスクレイピングして遅延・見合わせ情報を取得し、問題があったときだけ Google Home が音声で知らせてくれるので、出発前に自然と情報をキャッチできます。

なぜこの機能を作ったのか?

毎朝の通勤で利用している路線が遅延していると、乗り換えの計画が崩れたり、場合によっては早めに家を出る必要があります。
しかし毎朝わざわざスマホを開いて路線情報を確認するのは面倒で、チェックし忘れることもしばしば。
そこで、通勤前の準備をしている時間帯(朝6〜7時)に Google Home が自動で遅延情報をアナウンスしてくれる仕組みを作ることにしました。
遅延がなければ何もアナウンスしないので、うるさくなりません。

遅延してたら勝手に教えてほしい!毎朝スマホを開くのが面倒なんです。

実現したいこと

  • 朝6〜7時の時間帯だけ、15分おきに電車の遅延情報をチェックする
  • 遅延・運転見合わせが発生しているときだけ Google Home がアナウンスする
    • 平常運転のときは何もアナウンスしない(うるさくしない)
  • 複数の路線を監視対象にできる
  • Raspberry Pi 上でバックグラウンドサービスとして常時動作させる
  • 路線情報は設定ファイル(JSON)で管理し、追加・変更が簡単にできる

この記事でわかること

  • Yahoo!路線情報から BeautifulSoup でスクレイピングして運行状況を取得する方法
  • 時刻に応じて通知のオン/オフを制御する方法
  • Google Home に遅延情報を音声でアナウンスさせる方法
  • Raspberry Pi 上で systemd サービスとして常時稼働させる方法
  • 監視対象路線を JSON ファイルで柔軟に管理する方法

必要な準備と用意するもの

ハードウェア
  • Raspberry Pi(例:Raspberry Pi 5)
  • Google Home (Nest)
ソフトウェア/サービス
  • Python
    • requests
    • beautifulsoup4(bs4)
    • datetime
    • time
  • systemd(Raspberry Pi の常駐サービス化に使用)
  • Yahoo!路線情報(スクレイピング対象のWebサービス)
  • Google Home 発話ライブラリ(自作:googlehome.py)
    • 詳細は別記事を参照

完成イメージ

朝6時から7時の間、Raspberry Pi が15分おきに Yahoo!路線情報にアクセスして運行状況をチェックします。
監視している路線(例:京浜東北根岸線、京浜急行本線)のいずれかで「列車遅延」または「運転見合わせ」が発生している場合、Google Home が次のようなアナウンスをします。

「京浜東北根岸線は、〇〇駅で発生した車両点検の影響で、一部列車に遅れが出ています。」

問題がなければ何もアナウンスされません。7時を過ぎると自動的にチェックが止まるため、日中に通知が飛んでうるさくなることもありません。

システムの仕組み

システム全体の構成は下記の通りです。

  1. railways.json:監視する路線名・URL・通知レベルを定義した設定ファイル
  2. railwayinfo.py:Yahoo!路線情報をスクレイピングして各路線の運行状況を取得するライブラリ
  3. railway_delay_alert.py:時刻に応じて通知可否を判断し、遅延があれば Google Home に発話させるメインプログラム
  4. smh-railway-delay-alert.service:Raspberry Pi 上で常時稼働させるための systemd サービス定義ファイル

実装のポイント

時刻による通知制御

ループ内で現在時刻を毎秒チェックし、6〜7時の間のみ通知対象とします。15分おきに1回チェックするため、now_minute % 15 == 0 の条件を使っています。

静かな時間帯を守れる
6〜7時以外は通知しないので、日中や夜間に不意にアナウンスが流れることがない

遅延時のみアナウンス
「平常運転」の場合はループをスキップするため、毎回アナウンスされてうるさくならない

6時ちょうどにスタートしないと最初のチェックが6:15になる
サービスの起動タイミングによっては最初の15分を逃す可能性がある。必要であれば起動直後に1回チェックを入れる処理を追加する

スクレイピングによる運行状況取得

Yahoo!路線情報のページ構造を BeautifulSoup で解析し、<dt> タグから運行状況(平常運転・列車遅延・運転見合わせ など)を取得します。
遅延・見合わせ時は <dd class="trouble"> タグから詳細メッセージも取得できます。

Yahoo!路線情報のページ構造が変更された場合は、取得するタグやクラス名を修正する必要があります。過去にも一度構造変更があったため注意が必要です。

通知レベルによる柔軟な制御

railways.json の NotificationLevel で路線ごとに通知の感度を設定できます。
例えばレベル「1」に設定すると「運転情報」以上のステータスが発生したときに通知されます。

  • 0:平常運転でも通知
  • 1:運転情報以上で通知
  • 4:列車遅延以上で通知(推奨)
  • 5:運転見合わせのみ通知

事前準備

必要なライブラリのインストール

requests と BeautifulSoup をインストールします。

pip install requests beautifulsoup4

Google Home 発話ライブラリの準備

このプログラムでは自作の googlehome.py ライブラリを使用して Google Home に発話させます。
ライブラリの準備については別記事を参照してください。

監視路線の確認

Yahoo!路線情報(https://transit.yahoo.co.jp/diainfo/)で監視したい路線のURLを事前に確認しておきます。
URLは路線ごとに異なる数字のIDが割り当てられています。

実装方法

以下のフォルダ構成でプログラムを作成します。

smarthome/
└── core/
    └── alert/
        └── railway_delay/
            ├── config/
            │   └── railways.json          # 監視路線の設定ファイル
            ├── railwayinfo.py             # 運行状況取得ライブラリ
            └── railway_delay_alert.py     # メインプログラム(常駐サービス)

監視路線の設定ファイルを作成

監視する路線を JSON ファイルで定義します。
RailwayUrl には Yahoo!路線情報の対象路線のURLを設定してください。

[
    {"RailwayName":"京浜東北根岸線","NotificationLevel":"1","RailwayUrl":"https://transit.yahoo.co.jp/diainfo/22/0"},
    {"RailwayName":"京浜急行本線","NotificationLevel":"1","RailwayUrl":"https://transit.yahoo.co.jp/diainfo/120/0"}
]

運行状況取得ライブラリを作成

Yahoo!路線情報をスクレイピングして各路線の運行状況を返すライブラリです。
メインプログラムから呼び出して使います。

# -*- coding: utf-8 -*-
import requests
import json
from bs4 import BeautifulSoup as beautifulSoup

# 監視路線の設定ファイルを読み込む
with open('config/railways.json', 'r') as f:
    railways = json.load(f)

def get_railway_infos():
    railway_infos = []

    for railway in railways:
        railway_name = railway['RailwayName']
        notification_level = railway['NotificationLevel']
        traffic_url = railway['RailwayUrl']

        # Yahoo!路線情報のページを取得
        request_web_page = requests.get(traffic_url)

        # BeautifulSoup でページを解析
        web_page_soup = beautifulSoup(request_web_page.content, 'html.parser')

        # <dt> タグから運行状況を取得
        traffic_status = web_page_soup.find('dt').text

        # 通知対象かどうかを判定
        is_output = False
        if traffic_status == '平常運転':
            if notification_level <= '0':
                is_output = True
        elif traffic_status == '運転情報':
            if notification_level <= '1':
                is_output = True
        elif traffic_status == '運転状況':
            if notification_level <= '2':
                is_output = True
        elif traffic_status == '運転計画':
            if notification_level <= '3':
                is_output = True
        elif traffic_status == '列車遅延':
            if notification_level <= '4':
                is_output = True
        elif traffic_status == '運転見合わせ':
            if notification_level <= '5':
                is_output = True
        elif web_page_soup.find('dd', class_='trouble'):
            is_output = True

        # メッセージを取得
        if traffic_status == '平常運転':
            message = '平常運転しています。'
        else:
            trouble_tag = web_page_soup.find('dd', class_='trouble')
            message = trouble_tag.text if trouble_tag else ''

        railway_infos.append({
            'railway_name': railway_name,
            'traffic_status': traffic_status,
            'message': message,
            'is_output': is_output
        })

    return railway_infos

メインプログラムを作成

時刻を監視しながら、6〜7時の間だけ15分おきに遅延情報をチェックして Google Home にアナウンスさせます。

# -*- coding: utf-8 -*-
import sys
import time
import datetime
import googlehome
import railwayinfo

# Google Home の初期設定(リビングのGoogle Homeに発話)
google_notify = googlehome.Notify(googlehome.GoogleHome.LIVING)

# 最終発話日時を初期化
last_notified_datetime = None

while True:
    # 現在の時刻を取得
    now_hour   = int(datetime.datetime.now().strftime('%H'))
    now_minute = int(datetime.datetime.now().strftime('%M'))

    # 通知フラグを初期化
    is_notify = False

    # 6〜7時の間だけ、15分おきに通知対象とする
    if 6 <= now_hour <= 7:
        if now_minute % 15 == 0:
            is_notify = True

    if is_notify:
        # JSONファイルに定義されている路線の数だけ繰り返す
        for railway_info in railwayinfo.get_railway_infos():
            # 遅延・見合わせ以外はスキップ
            if railway_info['traffic_status'] not in ('運転見合わせ', '列車遅延'):
                continue

            # Google Home に発話
            message = railway_info['railway_name'] + 'は、' + railway_info['message'] + '。'
            google_notify.speak(message)

            # 最終通知日時を更新
            last_notified_datetime = datetime.datetime.now()

    # 約57.5秒待機(毎分の0秒付近で次のループに入るようにずらす)
    time.sleep(57.5)

systemd サービスとして登録する

Raspberry Pi 起動時に自動でメインプログラムが動き始めるよう、systemd サービスとして登録します。
下記のサービスファイルを /etc/systemd/system/ に配置してください。

[Unit]
Description=Traffic Notification
After=network.target

[Service]
ExecStart=/home/<username>/Projects/venv/bin/python /home/<username>/Projects/smarthome/core/alert/railway_delay/railway_delay_alert.py
Restart=always
RestartSec=60
Type=simple
User=<username>

[Install]
WantedBy=multi-user.target

サービスファイルを配置したら、以下のコマンドで有効化・起動します。

# サービスを有効化(起動時に自動スタート)
sudo systemctl enable smh-railway-delay-alert.service

# サービスを起動
sudo systemctl start smh-railway-delay-alert.service

# 状態確認
sudo systemctl status smh-railway-delay-alert.service

コードの解説

時刻による通知制御のロジック

メインループでは毎ループ(約57.5秒ごと)に現在時刻を取得し、is_notify フラグを判定しています。

# 6〜7時の間だけ、15分おきに通知対象とする
if 6 <= now_hour <= 7:
    if now_minute % 15 == 0:
        is_notify = True

ループ間隔を57.5秒にしているのは、毎分0秒ちょうどにチェックが通過するよう少し手前でループが回るよう調整しているためです。

BeautifulSoup によるスクレイピング

Yahoo!路線情報のページでは、運行状況ステータスが <dt> タグに、トラブル詳細が <dd class="trouble"> タグにそれぞれ格納されています。

# 運行状況ステータスを取得(例:「平常運転」「列車遅延」「運転見合わせ」)
traffic_status = web_page_soup.find('dt').text

# トラブル詳細メッセージを取得
trouble_tag = web_page_soup.find('dd', class_='trouble')
message = trouble_tag.text if trouble_tag else ''

Yahoo!路線情報のページ構造は予告なく変更される場合があります。突然取得できなくなった場合は、ブラウザの開発者ツールでHTML構造を確認して取得タグを修正してください。

通知レベルによる柔軟なフィルタリング

railways.jsonNotificationLevel を変えることで、路線ごとに通知の感度を調整できます。
頻繁に遅延情報が流れる路線は感度を下げ(レベル4〜5)、重要度の高い路線は感度を上げる(レベル1〜2)といった使い方ができます。

動作確認

サービス起動後、朝6時台にプログラムが正しく動作しているかをログで確認します。

# サービスのログをリアルタイムで確認
sudo journalctl -u smh-railway-delay-alert.service -f

テストしたいときは、コードの通知条件を一時的に変更して任意の時刻でも動作するようにして確認するのが便利です。

# テスト用:時刻に関係なく常に通知対象にする
is_notify = True

テスト後は必ず元のコードに戻してください。常時通知状態のままにすると、Google Home が57.5秒ごとにしゃべり続けます。

まとめ

この記事では、Yahoo!路線情報をスクレイピングして朝6〜7時の間だけ電車の遅延情報を Google Home にアナウンスさせる仕組みを実装しました。

  • Yahoo!路線情報を BeautifulSoup でスクレイピングして運行状況を取得
  • 6〜7時の間・15分おきという条件で通知タイミングを制御
  • 遅延・見合わせ時のみ Google Home がアナウンス(平常運転は無音)
  • systemd サービスで Raspberry Pi 起動時から自動稼働
  • railways.json で監視路線を簡単に追加・変更可能

一度セットアップすれば毎朝自動でチェックしてくれるので、通勤前の情報収集がとてもラクになります。ぜひ試してみてください。

タイトルとURLをコピーしました