KAWAJUNのドアノブを直す

ウチのドアノブはKAWAJUNのものです。
KAWAJUNのドアノブは4つの部品から構成されています。

メインとなるケースロック部
hw.kawajun.jp

ドアに開けた穴を隠したり、鍵の取っ手部分を提供するプレート
hw.kawajun.jp

そして持ち手となるレバーハンドル
hw.kawajun.jp

最後に、壁側に取り付けるストライク
hw.kawajun.jp

今回は、リビングのドアが閉まる際に、このドアノブがガタガタしているので直します。
おそらく締めなおすだけだろうと思います。まずは、分解していきます。

まず、レバーハンドルを外すために、レバーハンドルを固定するネジを探します。
KAWAJUNの場合、ほとんどがドアを開いてレバーハンドルを見るとネジが見えるはずですが、ウチのRVタイプはネジが隠されています。
レバーハンドルの茶色いプラスチックを、レバーハンドル先端から引っ張ります。

茶色いプラスチックパーツが外れます。パーツはこんな形状で、ツメで引っ掛かっています。

茶色いプラスチックが外れたところを見ると、隠しネジが現れます。

この右のプラスネジを外すと、レバーハンドルを引き抜くことができます。
固着気味なので、両方のレバーハンドルを水平に引きます。

レバーハンドルを引き抜いたら、プレートの下にマイナスドライバや車の内装剥がしを入れて、てこの原理でプレートの金属カバーだけをはがします。
この時点でグラグラしてました。

金属プレートを外すと、このようなプラスチックプレートが、両面についていて、ネジで挟み込むように固定されています。
上下のネジを外します。

下側のネジがおかしいなぁと、思ったら、下側のネジ受け側のプラスチックがポッキリと折れてました。

ただ、両方、皿ネジが入るようにできているようです。
ドアとプラスチックプレートの合計の厚みは約50mm。使われているネジはM4。
そこで、M4の20mmネジを2本、M4の20mmの高ナット1本を用意しました。

これを使って、両方からねじ込み、強力に挟み込んでやります。

強く締結されました。

金属プレートとハンドルレバーを元に戻します。
ドアノブ付近のガタは直りましたが、それ以外にもドア中央の半透明アクリルプレートが、固定されている木枠に隙間ができて、ガタガタいっています。
こちらは隙間に透明のシリコンシーラントを、薄型のスパッジャーを使って埋め込んで、ガタを直しました。

ちなみに、もともとついていたロックケースはLWシリーズでしたがこちらは廃盤。
あらたにLJケースロックとなっていてLWケースロックと互換性があり、バネの耐久性が向上し、経年劣化によってレバーハンドルが水平に戻らなくなることが少なくなっているそうです。
トイレのレバーハンドルが2度ほど傾いていたので、LJロックケースに交換すると、水平に戻りました。
ロックケースは上記の手順にプラスして、ドア側面のネジ2個を外すだけなので、簡単です!
ハンドルレバーやプレートは高価ですが、JLJロックケースは1個1,000以下で買えるので、どんどん交換しましょう!

Dovecot 2.4へのバージョンアップでconfを書き直す。

Dovecotが2.3から2.4になったことで、コンフィグレーションファイルの書式が大幅に変わり、ハマりました。
しかし、時代は進化したもので、Geminiに聞くとだいたい解決します。

まず、Dovecot起動時にこんなエラーが。

doveconf: Fatal: Error in configuration file /etc/dovecot/dovecot.conf line 24: The first setting must be dovecot_config_version
 * Error parsing /etc/dovecot/dovecot.conf
 * ERROR: dovecot failed to start

どうやら、2.4からはconfにバージョンを記載しなければならないようです。
syslog-ngみたいだな。
2.3のdovecot.confをバックアップし、2.4のデフォルトのdovecot.conf(cp ._cfg0001_dovecot.conf dovecot.confを実行。数字は今までのアップデートによっていくつかあると思うけど、最大のものを採用。)から編集していきます。

まずは、/etc/dovecot/dovecot.confの適当な場所に、次の2行を入れます。

dovecot_config_version = 2.4.0
dovecot_storage_version = 2.4.0

動作しているdovecotは2.4.4ですが、2.4.0で正常に動作します。

プロトコルはPOP3s(POP3をTLSで通信する)なので、protcolsにpop3を記述します。

protocols {
#  imap = yes
#  lmtp = yes
  pop3 = yes
}

メールボックスの設定です。
デフォルトのひな型は、/srv/mail/%{user}とかにあるsdbox形式のメールボックスを読みに行くような設定ですが、postfixのmaildir形式で、かつ/home/{ユーザー名}/.maidirという場所に保存されていますので、それを変えます。

mail_home = /home/%{user}
mail_driver = maildir
mail_path = ~/.maildir

続いて、SSL関係です。
ssl_cert =<がssl_server_cert_file =へ、ssl_key =<がssl_server_key_file =へ、ファイルの指定方法が変わることはGeminiが教えてくれましたが、ssl_dh =<の指定方法や、prefer_ciphersの指定方法が変更になったことまでは教えてくれず、

doveconf: Fatal: Error in configuration file /etc/dovecot/conf.d/10-ssl.conf line 54: ssl_dh: Unknown setting: ssl_dh
doveconf: Fatal: Error in configuration file /etc/dovecot/conf.d/10-ssl.conf line 17: prefer_ciphers: Invalid value: yes

と、怒られて起動できません。
/etc/dovecot/conf.d/10-ssl.confを書き換えます。
いままでバラバラの行に設定していたssl関連をssl{}にまとめるようです。
(path/to/は皆さんの環境で保存されているcertファイルの場所に書き換えてください。)

ssl_server {
   ssl_server_cert_file = /etc/letsencrypt/path/to/fullchain.pem
   ssl_server_key_file = /etc/letsencrypt/path/to/privkey.pem
   ssl_server_dh_file = /etc/dovecot/dh.pem
   ssl_server_prefer_ciphers = server
}

prefer_ciphersはssl_server_prefer_ciphersという名称に変更となり、yes noではなく、serverでサーバー側のcipherを強制し、clientだと、クライアント側のcipherを受け入れることになるので、セキュリティ上serverとします。

ssl_cipher_list =は今までの書式と変更ありません。
ついでですが、いままでssl = yesだったものをssl = requiredに変更します。(なぜ平文を許容していたのだろう・・・)

また、引き続き平文パスワードを許容しないように、/etc/dovecot/conf.d/10-auth.confの中にあるdisable_plaintext_auth = yesという記載を、

auth_allow_cleartext = no

という記載に変更します。

これで起動するようになるのですが、メーラーで受信ボタンを押してからログを見ると・・・。

Jun 10 23:01:31 gentoo dovecot[7465]: pop3-login: Logged in: user=<xxxxxx>, method=PLAIN, rip=192.168.0.256, lip=192.168.0.1, mpid=7832, TLS, session=<zzzzzzzzzzzzzz>
Jun 10 23:01:31 gentoo dovecot[7465]: pop3(xxxxxx): Error: Unknown UNIX UID user: vmail (from mail_uid setting)

こんなエラーがずーっと出てきます。
これは、デフォルトのdovecot.confに記述されているuid=vmailとgid=vmailが悪さをしています。
vmailというユーザーはいないので、uid=dovecotとgid=dovecotを指定してみると、

Jun 10 23:10:49 gentoo dovecot[9966]: pop3-login: Logged in: user=<xxxxxx>, method=PLAIN, rip=192.168.0.256, lip=192.168.0.1, mpid=9990, TLS, session=<zzzzzzzzzzzzzz>
Jun 10 23:10:49 gentoo dovecot[9966]: pop3(xxxxxx)<9990><zzzzzzzzzzzzzz>: Error: chdir(/home/xxxxxx/) failed: Permission denied (euid=97(dovecot) egid=97(dovecot) missing +x perm: /home/xxxxxx, dir owned by 1000:100 mode=0700)
Jun 10 23:10:49 gentoo dovecot[9966]: pop3(xxxxxx)<9990><zzzzzzzzzzzzzz>: Error: Couldn't open INBOX: stat(/home/xxxxxx/.maildir/tmp) failed: Permission denied (euid=97(dovecot) egid=97(dovecot) missing +x perm: /home/xxxxxx, dir owned by 1000:100 mode=0700)

というような、各ユーザーフォルダへのアクセス権がない、と言われます。
これをGeminiに尋ねると、そもそもuidとgidを設定したことで、vmailなり、dovecotなりのユーザー権限でメールボックスにアクセスするため、アクセス権がないといわれることを意味し、uidとgidを設定してはいけない、と、言われました。
また、各ユーザー権限でアクセスするために設定すべきは、

passdb pam {
}

userdb passwd {
}

この2つでした。
パスワードはpam認証を指定し、ユーザー権限はpasswdファイルを参照するということです。
passdb pam {}はデフォルトでも入力済みだったため、userdb passwd {}を追加しました。

また、最初から記述されている、

namespace inbox {
  inbox = yes
  separator = /
}

は、残したままにしています。

これでメールクライアントからエラーなくメールをとりに行くことができるようになりました。

SONOFF basic R1のコンデンサ交換

拙宅にはいろいろな場所に2017年ころに購入したSONOFF basic R1(ESP8266にAC入力とリレーでAC出力ができる小型デバイス)に、ESPEasyがインストールされたデバイスがゴロゴロしています。

そのなかで、常用して便利に使っている寝室の照明スイッチがあります。

gentoolinux.hatenablog.com

この寝室の照明スイッチを司るSONOFF basic R1ですが、半年前くらいから時折WiFiの接続に失敗するようになりました。
押しボタンスイッチからON OFFできるのですが、LANからは応答がない状態です。
そんな時に押しボタンスイッチのON OFFを何度も繰り返すと、それすら反応しなくなり、再起動を余儀なくされます。
再起動すると治るので、この時はそれほど気にしてませんでした。

ところが、2026年2月下旬、寝ている最中に突然未明、照明が煌々と着くという不具合が、数日ほど続くようになりました。
このSONOFF basic R1はESPEasyのRulesで、起動時にGPIO-12すなわちリレーをONにせよ、というルールが記述されています。
ということは、未明に突然再起動してしまったということです。

数日続いたので、寝るときは電源のスイッチを切ることにしました。
しかしこれでは、「スイッチに行かなくても、ベッドに入ったまま照明が消せる」というメリットをスポイルしています。

とうとうSONOFF basic R1が故障したのか・・・。手持ちの予備と交換するか・・・。
と、思いましたが、症状の不安定さから、もしかして電源の異常かしら? コンデンサ抜けかしら? と、思いました。

このブログでも、何度か電源が入らない機器故障が、電源周りのコンデンサ抜けで、交換修理しています。

gentoolinux.hatenablog.com
gentoolinux.hatenablog.com

調べてみたら、はやりそれらしいことを示唆している掲示板がありました。

https://www.letscontrolit.com/forum/viewtopic.php?t=8823

これを読むと、SONOFF basic R1には16V 470uFと400V 3.3uFの2つのコンデンサが載っていて、特に16V 470uFは抜けて94ufまで落ち込み、WiFiが不安定になっていたことが書かれています。
これは同じ症状だろうと思い、コンデンサ交換してみます。

秋月電子でルビコンのコンデンサを購入します。
残念ながら400V 3.3uFのコンデンサが売っていないので、400V 4.7uFで代用します。
(Geminiさんに聞いてみたところ、ほぼ問題ないだろうということです。)

では、寝室のスイッチを分解していきます。
当然ですが、ここからは電気工事士の資格が必要です。


寝室のコスモワイドスクエアタイプ。上がGPIO-14につながっている押しボタン。下がSONOFF basic R1のAC電源供給をオンオフするスイッチ。


カバーを外すとこんな感じに2つのスイッチが隠されてます。


スイッチを外すとVVFケーブルから4分岐差し込みが出てきます。SONOFF basic R1、オンピカの電源、下にある非常用ライトに電源を供給しています。


スイッチの水平横方向にSONOFF basic R1が隠されていました。

取り出したSONOFF basic R1を、電源供給用のVVFと照明側のVVFを外し、GPIO-14につながっているデュポン中継コネクタも外します。
そして、外装を外して出てきた基板です。


写真上側が400V 3.3uF 中央が16V 470uF


こちら側が二次側で整流にかかわる16V 470uF。それほど膨らんでなさげ。


こちら側は一次側にいる400V 3.3uF。こちらも何事もなさげ。

しかし、コンデンサを取り換えることにします。


丸の位置がコンデンサの足です。左上が400V 3.3uF 右が16V 470uF。

この16V 470uVの+が曲者で、隣のチップ部品とダイオードを、大量の半田で無理やりつないでいます。
そして、このSONOFF basic R1は矢印で示したダイオードにも半田が載っていますが、別の予備のSONOFF basic R1は半田がつながっていませんでした。
どっちが正しいのかしら?
とりあえず、繋げることにします。


外したコンデンサと新品のルビコンコンデンサ。

はずすときはもう使わないコンデンサなので、全く大事にせずに熱をじっくり加えてグリグリ外しますが、新品のコンデンサは壊してはいけないので、コンデンサの足に熱逃がしのアルミクリップを付けてから、はんだを盛ります。


熱逃がしのアルミクリップ

コンデンサを交換したので、正しく動作するのか、基板裸の状態でテストします。

とりあえず、起動してWiFiもつながるし、スイッチも効くことを確認したので、取り外してケースに戻すことにします。
この時、素手でテストしていたので、電源を切ったのにまだ一次側に電気が残っていたようで、基板に触れて軽く感電しました。
ちょっと痛かったです。
ちゃんとゴム手袋しましょう。


元通り(最初の画像と一緒ですけど・・・)

コンデンサを交換して1週間ほど経過しますが、WiFiが切れてLANから操作できなくなることもなく、安定して動作しています。
ついでに、リビングの温湿度を計測しているSONOFF basic R1、ベッドのヘッドボードの押しボタンと接続し、押すと寝室の照明をON OFFする(HTTPをGETしているだけ)のSONOFF basic R1、予備のSONOFF basic R1の3つのSONOFF basic R1のコンデンサすべて交換しました。

これであと10年は持ってくれるとありがたいです。

アイホン集合住宅用インターホンシステムVHK-RMAシリーズの呼び出しを拡張する4

これまで、インターホンにハードウェアnodeMCUの設置を行い、nodeMCUにインストールされたESPEasyの設定を行い、家庭内サーバーにCGIを設置してGoogle Home Miniでチャイム音を鳴らすところまでを行いました。

gentoolinux.hatenablog.com
gentoolinux.hatenablog.com
gentoolinux.hatenablog.com

Google Home Miniの音が聞こえない範囲にいることも考え、LINEに通知も送りたいと思います。
2025年3月に終了したLINE Notifyに代わり、LINE Messaging APIを使って家族のLINEグループに通知を飛ばします。


1. LINE公式アカウントの作成

Messaging APIを利用するには、まず「LINE公式アカウント」を作成する必要があります。
2026年2月時点では、月200通まで無料(コミュニケーションプラン)で利用可能です。

まずは LINE Official Account Manager にアクセスし、個人のLINEアカウントでログインします。

アカウント名: 「インターホン通知」など分かりやすい名前を付けます。
業種: 適当なもの(個人、ITなど)でOKです。

作成後、右上の「設定」>左の「利用プラン」から、「コミュニケーション」が「利用中」になっていて、無料メッセージ数が200通になっていることを確認しておきます。


2. Messaging APIを有効にする

公式アカウントが作れたら、プログラムから制御できるように「Messaging API」を有効化します。
「設定」>「Messaging API」メニューを開きます。
「Messaging APIを利用する」ボタンをクリック。
プロバイダー名(自分の名前などでOK)を入力・選択して進めます。
これで、LINE Developersコンソール 側にも今作ったアカウントが表示されるようになります。


3. LINE Developersでの設定:グループ参加許可

ここが一番のハマりどころです。デフォルトでは公式アカウントはグループに参加できず、1対1のやりとりしかできません。
家族にも通知が行くように、グループ参加を許可します。

[LINE Developers] にログインし、作成したチャネルを開きます。
(LINE Official Account Managerのホーム画面にいる場合は、アカウントリストから該当のリスト(上で設定した●●の通知など)をクリックし、右上の「設定」をクリック、左のメニューの「Messaging API」をクリックして出てきた右ペイン一番下にある、「その他の設定はLINE Developersコンソールから行えます。」からLINE Developersコンソールに行きます。先ほど作成したチャネルがあるはずなので、それをクリックします。)

「Messaging API設定」タブをクリックして表示させ、下へスクロール。
「LINE公式アカウント機能」の項目にある「グループ・複数人トークへの参加」の「編集」をクリック。

設定画面で「許可する」に変更して保存します。

この設定を忘れると、グループに招待してもボットが即座に自動退会してしまいます。


4. アクセストークンの発行

 プログラムからメッセージを送るための「鍵」を取得します。
 「Messaging API設定」タブの最下部にある「チャネルアクセストークン(長期)」の発行ボタンを押し、表示された英数字をコピーしておきます。

同時に、「チャネル基本設定」タブにある「チャネルシークレット」もメモしておきます。


5.グループIDの取得

 LINE Messaging APIを使ってLINEグループに通知を送る際、グループIDが必要になりますが、これ、管理画面のどこにも書いていないのです。
 グループIDを特定するには、ボットをグループに招待し、ボットに届いた「Webhookイベント」を生データで確認する必要があります。自宅Gentooサーバー上に簡単なデバッグ用CGIを仕掛けて、グループIDを引っこ抜いた際の手順をまとめます。

a:Webhookを受け取る準備(Gentooサーバー側)

ボットがイベントを受け取った際、その中身をログに吐き出すための単純なCGIを設置します。
まずは、Apacheのログディレクトリなどに書き込み権限のあるログファイルを作っておきます。

    touch /tmp/line_webhook.log
    chmod 666 /tmp/line_webhook.log

次に、Webhookの呼び出しを受けるCGIを作成します。

getgroupid.cgi

#!/home/iot/bin/python3
import sys
import json

#標準入力からWebhookのJSONデータを受け取る
body = sys.stdin.read()

#届いた内容をそのままログファイルに追記
with open('/tmp/line_webhook.log', 'a') as f:
f.write(body + "\n")

print("Content-Type: text/plain")
print("")
print("OK")

b: LINE Developersでの設定

LINE Developersコンソールの「Messaging API設定」タブで、作成したCGIのURLを登録します。

Webhook URL: https://あなたのドメイン/iot/getgroupid.cgi
Webhookの利用: ON に設定

「検証」ボタンを押して「成功」と出れば、ボットとサーバーが繋がった合図です。


c: グループIDを「釣る」

いよいよIDを特定します。
通知を送りたいLINEの家族グループに、作成した公式アカウントを「招待」します。
グループに参加した瞬間、またはグループ内で何か発言した瞬間に、ボットにWebhookが飛びます。
サーバーのログを確認します。

tail -f /tmp/line_webhook.log
 ||<

すると、以下のようなJSONデータが届いているはずです。

>|json|
    {
    "destination": "Uxxxxxxxx...",
    "events": [
    {
    "type": "join",
    "source": {
    "type": "group",
    "groupId": "C123456789abcdef0123456789abcdef"
    },
    ...
    }
    ]
    }

この "groupId": "C..." という33文字の文字列こそが、探し求めていた通知先のグループIDです。

d: 後片付け

IDが判明したら、セキュリティのためWebhook URLの設定を消すか、CGIを削除しておきましょう。特定したIDは、この後作成する通知用Pythonスクリプト(line_notifier.py)の GROUP_ID 変数に貼り付けます。


6. Pythonによる通知スクリプト

仮想環境(/home/iot)に、通知用のスクリプトを作成します。

/home/iot/line_notifier.py

#!/home/iot/bin/python3

-- coding: utf-8 --

import requests
import json
import datetime
--- 設定情報 ---

ACCESS_TOKEN = 'あなたのアクセストークン'
GROUP_ID = 'Cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' # グループID
---------------

def send_line_notification():
url = 'https://api.line.me/v2/bot/message/push'
now = datetime.datetime.now().strftime('%Y/%m/%d(%a) %H:%M:%S')

headers = {
    'Content-Type': 'application/json',
    'Authorization': f'Bearer {ACCESS_TOKEN}'
}

payload = {
    'to': GROUP_ID,
    'messages': [
        {
            'type': 'text',
            'text': f"🔔 インターフォンが鳴動しました\n発生時刻: {now}"
        }
    ]
}

try:
    response = requests.post(url, headers=headers, data=json.dumps(payload))
    response.raise_for_status()
    return True
except Exception as e:
    import sys
    print(f"LINE Notification Error: {e}", file=sys.stderr)
    return False

if name == "main":
send_line_notification()

6. 動作確認

すべてが繋がると、インターホンのチャイムが鳴った瞬間に、別室のGoogle Home Miniが鳴り、家族のLINEグループに「🔔 インターフォンが鳴動しました」と通知が届きます。

ここまで、かなりのステップがかかりましたが、サーバーバックエンド、ESPeasyのエッジ制御、そしてMessaging API。これらを組み合わせた自作スマートインターホンは、15年以上前のインターホンに新たな拡張性を得ることができました。
これで、重要な宅配便を、別室にいて取り逃す、なんていうことはなくなるでしょう。

アイホン集合住宅用インターホンシステムVHK-RMAシリーズの呼び出しを拡張する3

これまで、インターホンにハードウェアnodeMCUの設置を行い、nodeMCUにインストールされたESPEasyの設定を行いました。

gentoolinux.hatenablog.com

gentoolinux.hatenablog.com

続いて、nodeMCU側から叩かれるCGIを設置し、Pythonを使って別室にあるGoogle Home Miniからチャイム音を鳴らします。

1. 全体のシーケンス

まず、どのように信号が流れるかのイメージです。
子機: ボタンが押される。
インターホン親機: AS/AE端子(スピーカー出力)に電圧が発生。
IoTユニット(NodeMCU): フォトカプラ経由のGPIO-12で検知し、ESPeasyのRulesでサーバーのCGIを叩く。
Gentooサーバー: NodeMCUからのHTTP GETリクエストを受け取り、CGI(Bash)を起動。
CGI:Google Home制御用のPythonスクリプトをバックグラウンドでキック。
Google Home Mini: Pythonからの命令を受け取り、Gentooサーバー上に予め保存してあったaiphone.mp3ファイルを再生。


2. Gentoo Linuxでの準備(Python仮想環境の構築)

Gentoo Linuxのpipインストール環境は、システム全体のPython環境を汚さないよう、python -m venvで専用の仮想環境を構築し、その中でpychromecastライブラリを運用します。

手順1:ディレクトリ作成と仮想環境(venv)の構築
まず、今回利用するPythonライブラリやファイルを置く仮想環境ディレクトリを作成します。
今回は /home/iot を仮想環境のルートとして構築します。

#ディレクトリを作成
mkdir -p /home/iot

#/home/iot を仮想環境として構築
python -m venv /home/iot

手順2:カレントディレクトリの移動とアクティベート
アクティベート(仮想環境へのエントリー)を行う前に、作成したディレクトリへ移動しておきます。

#仮想環境のディレクトリへ移動
cd /home/iot

#仮想環境を有効化(アクティベート)
. bin/activate

#成功すると、プロンプトの先頭に (iot) と表示されます
(iot) $

手順3:pychromecastのインストール
アクティベートされた状態(プロンプトが (iot) $ になっている)で、pipコマンドを使って必要なライブラリをインストールします。

#pychromecastライブラリのインストール
(iot) $ pip install pychromecast

#あわせて、HTTPリクエスト用のrequestsも入れておきます
(iot) $ pip install requests

この仮想環境内には、Python 3.13に対応したpychromecast(今回の環境ではv14.0.9)がインストールされました。

手順4:仮想環境から抜ける(ディアクティベート)
作業が終わったら、仮想環境から抜けて元のシステム環境に戻ります。

(iot) $ deactivate

これで、Google Home Miniを制御するPythonスクリプトを実行するための準備が整いました。
CGI(Bashスクリプト)からは、この仮想環境内のPythonインタープリタ(/home/iot/bin/python3)を直接指定してスクリプトをキックします。


3. Google Homeを制御するPythonスクリプト

Google Home(Chromecastデバイス)の制御には、先ほどインストールしたpychromecastライブラリを使用します。
このライブラリはアップデートが激しく、ネット上の新旧様々な情報を鵜呑みにするとエラーになります。
(GeminiにPythonを書かせましたが、何時間もエラーと格闘し、pychromecast v14.0.9に準拠した書き方にせよ、というプロンプトを与えることで、その後は2回の壁打ちだけであっけなく完成しました。プロンプトでのバージョン指定は重要です。)
今回は、Gentoo Linux上のPython 3.13環境でインストールされた pychromecast v14.0.9 に対応したコードを作成しました。

特徴は以下の通りです。

 探索(Discovery)の省略: 毎回ネットワーク全体をスキャンすると遅延が大きいため、Google Home MiniのIPアドレス(192.168.x.z)を直接指定して接続を高速化しています。(あらかじめDHCPサーバーで固定IPを配るように設定済)
 v14系への適合: Chromecastクラスの初期化方法が変更されており、HostServiceInfoなどの内部モデルを自前で組み立てて渡す必要があります。
 音量制御: 再生前に音量を上げ(60%)、再生後に元の音量(40%)に戻す処理を入れています。

/home/iot/googlehomemini.py

#!/home/iot/bin/python3
# -*- coding: utf-8 -*-

import time
import pychromecast
from pychromecast.models import CastInfo, HostServiceInfo

# --- 設定情報 ---
GOOGLE_HOME_IP = '192.168.x.z'
MP3_URL = 'http://192.168.z.y/iot/aiphone.mp3'
# ---------------

def play_intercom_sound():
    try:
        # 1. 通信サービス情報の作成
        service_info = HostServiceInfo(host=GOOGLE_HOME_IP, port=8009)

        # 2. v14.0.9 の CastInfo クラスの引数定義に厳密に合わせます
        # 引数の順番: (services, uuid, model_name, friendly_name, host, port, cast_type, manufacturer)
        cast_info = CastInfo(
            {service_info},           # services
            None,                     # uuid
            "Google Home Mini",       # model_name
            "Intercom",               # friendly_name
            GOOGLE_HOME_IP,           # host
            8009,                     # port
            "cast",                   # cast_type (必須項目)
            "Google Inc."             # manufacturer (必須項目)
        )

        # 3. 初期化
        cast = pychromecast.Chromecast(cast_info)

        # 4. 接続待機
        cast.wait(timeout=1)

        #ボリュームを60%に設定
        cast.set_volume(0.6)
        time.sleep(0.1)

        # 5. メディア再生
        mc = cast.media_controller
        mc.play_media(MP3_URL, 'audio/mp3')

        # 受理されるまで20秒待機
        time.sleep(20)

        # 再生後にボリュームを 40% (0.4) に戻す
        cast.set_volume(0.4)
        time.sleep(0.2)

        # 6. 切断
        #cast.disconnect()
        return True

    except Exception as e:
        import sys
        print(f"Google Home Error: {e}", file=sys.stderr)
        return False

if __name__ == "__main__":
    if play_intercom_sound():
        print("Success")
    else:
        print("Failed")

192.168.x.yや192.168.x.zなどのサーバIPアドレスとGoogle Home MiniのIPアドレスは、皆さんの環境に合わせて書き換えて下さい。


4. Apache CGI(橋渡し役)

NodeMCUからのHTTPリクエストを受け取るCGIです。Google Home制御用と、別途作成したLINE通知用の2つのPythonスクリプトを「ほぼ同時」に実行させるため、バックグラウンド(&)で起動させます。

/PathToWWWroot/iot/interphone.cgi
(PathToWWWrootは自前の環境のWebRootディレクトリに読み替えてください)

#!/bin/bash
echo "Content-type: text/plain; charset=utf-8"
echo ""

#1. Google Home再生をバックグラウンドで実行
#仮想環境のPythonを指定して実行します
/home/iot/bin/python3 /home/iot/googlehomemini.py > /dev/null 2>&1 &

#2. LINE通知を実行(こちらも同様にバックグラウンドへ)
/home/iot/bin/python3 /home/iot/line_notifier.py > /dev/null 2>&1 &

#3ブラウザ(NodeMCU)には即座にOKを返す
echo "Interphone notification process started."


一番のハマりどころは、やはりpychromecastの仕様変更でした。「'str' object has no attribute 'cast_type'」や「Chromecast.init() takes 2 positional arguments but 3 were given」といったエラーと格闘し、最終的にHostServiceInfoを渡す形に落ち着きました。

これで、玄関のチャイムが鳴った瞬間に「別の部屋でもチャイム音が鳴る」というスマートインターフォン環境が整いました。
残りはGoogle Home miniのチャイム音とともにLINEに通知するためのPythonのプログラミングです。

アイホン集合住宅用インターホンシステムVHK-RMAシリーズの呼び出しを拡張する2

前回はハードウェアの設置を行いました。

gentoolinux.hatenablog.com

ここからはプログラミング等のソフトウェアを整えていきます。

まずは、nodeMCUにインストールしたESPEasyの設定です。
nodeMCU(ESP8266)にESPEasyをインストールする方法は割愛します。
ESP8266は1MBのROMしかないので、ESPEasyは安定板のR148をインストールしてあります。


nodeMCUハード情報:利用ピン

ESPEasyは以下のピンを使用しています。

入力ピン: GPIO12 (D6) ―― フォトカプラからの信号を受信。
WiFi状態LED: GPIO2 (D4) ―― NodeMCUボード上のLED。Wi-Fi接続状態を表示。


Devices設定:接点とWiFiステータスの定義

ESPEasyの「Devices」タブで、2つのタスクを定義します。

Task 1: インターホン入力 (Switch input)
フォトカプラからのデジタル入力を受け取る設定です。
Device: Switch input を選択。
Name: なんでもよいですが、Intercom と命名。
GPIO: GPIO-12 を選択。
Internal PullUp: チェックを入れます(重要) 。これにより、フォトカプラがOFFの時は「High(1)」、ON(チャイム鳴動)の時は「Low(0)」になります 。
Switch Type: Switch を選択。
Switch Button Type: Normal Switch を選択。
Value Name 1:なんでもよいですが、今までの通例に則ってStateとしました。

これで、[Interphone#State] という変数で、0 か 1 の状態が取得できるようになります 。

Task 2: WiFiステータス (System Info)

Wi-Fiの接続状態を判定するための設定です。R148では「System Info」デバイスを使います 。
Device: System Info を選択。
Name: なんでもよいですが、Sys と命名。
Indicator: WiFi RSSI を選択 。
補足: R148では電波強度(RSSI)を監視することで、Wi-Fiの接続状態を判定します 。接続中は負の数(-70dBmなど)、切断時は0になります 。
Value Name 1: なんでもよいですが、RSSI と入力して保存 。


※設定しましたが、結局使っておらず・・・。

3. Rules設定:通知ロジック

ここがソフト側の肝となる、Rulesの設定です。ESPEasy R148の文法に合わせて記述します。
インターホンが鳴ったことを検知し(State=0)、フォトカプラがONになった瞬間にサーバーのCGIを叩きます。

「Tools」→「Rules」画面に、以下のコードを記述します 。

on Intercom#State=0 do
  // サーバーのCGIを叩く
  SendToHTTP 192.168.x.y,80,/iot/interphone.cgi
endon

192.168.x.yは皆様お持ちの家庭内サーバーのアドレスを、/iot/interphone.cgiは叩くべきcgiのロケーションに書き換えてください。

これで、ハードウェア(NodeMCU)側の設定は完了です 。
玄関でインターホンが押されれば、AS/AE接点信号をフォトカプラが検知し、NodeMCUがESPEasy R148のRulesに従って、サーバーへHTTPリクエストを送る準備が整いました。

次回は、このリクエストを受け取るGentooサーバー(http://192.168.x.y)側のソフトウェア実装、特にGoogle Home MiniとLINEのAPIとの連携について解説します。

アイホン集合住宅用インターホンシステムVHK-RMAシリーズの呼び出しを拡張する1

ウチのマンションのインターホンは、VHK-RMA-HRWという機種です。
(おそらく最後のWは、画面周囲がホワイトのWという色を表していると思います。画面周囲がシルバーのVHK-RMA-HRSもあるようです。)

リビングダイニングキッチンの壁に設置されていますが、そこから離れると、特に自分の部屋(防音)や、そうじゃなくても寝室や洗面所でさえ、呼び出し音のチャイムが聞こえません。
なんとかして他の部屋でもインターホンの呼び出しが分かるようにしたい!
そこで、このVHK-RMAの情報を探りました。

アイホン社のサイトからVHK-RMA-HRSの仕様書がダウンロードできるんですが、それによると、VHK-RMAの裏には、いくつかの拡張端子があり、そのうち使えそうな端子が2つ見つかりました。

ひとつはTD、TC接点。
こちらは、「警報・通報が発報中、移報接点が出力されます。(無電圧オープンコレクター出力)接点定格DC24V・5mA」と書かれています。
これは、発報中はスイッチがクローズになり、定格以内の電気を流せる、ということになります。
これを使えれば、何からのデバイスのGPIOで検出できそうです。

もうひとつは補助音響AS、AE接点。
ここにアイホン社純正の外部スピーカーICR-1や、ワイヤレス 呼出装置FW-TRを接続して、別の場所でも呼び出し音を鳴らす、というものです。
これを何らかのデバイスのGPIOに入力するには、フォトカプラなどを使って絶縁する回路をつくる必要がありそうです。

これらの端子がどのような物理端子なのかを確認するために、VHK-RMA-HRWの裏を開けてみました。
開け方は、通話/終話ボタンをめくったところにあるネジを1本外すだけです。


めくったところ。左側のネジを外します。

操作盤の裏の上のほうに、TD TC端子と、AS AE端子があります。

これらの端子、コネクタになっていますが、端子の間隔や周囲の大きさを測って調べると、「PH-2.0」という規格の端子であることが分かりました。
TD TC端子はPH-2.0の2ピン、AS AE端子は、防犯キースイッチのKS KSEと並んでPH-2.0の4ピンです。
これらの端子をAmazonで取り寄せて、ESPEasyをインストールしたnodeMCUで実験です。
まずは簡単に済みそうなTC TD端子とnodeMCUを、D6端子とGND端子をつないで実験です。


PH-2.0 2ピンを接続した裏面


TD TC端子と接続したnodeMCU

TD端子はD6と、TC端子はGNDと接続しました。
実験のためにドア横のインターホンを押すと、VHK-RMA-HRWは鳴動するものの、nodeMCUは反応ナシ。
どうやら、このTD TC端子は警報を発砲した時だけクローズするようで、インターホンの鳴動はウンともスンとも言わない仕様のようです。

ということで、AS AE端子に望みをかけます。
しかし、AS AE端子は、ちいさなスピーカー出力だと思われます。
出力されるのは変動が激しいAC出力。
直接nodeMCUに接続できません。

ここで、AIのお出まし!
Google Geminiに、インターホンの補助音響スピーカ端子と、ESP8266のGPIOを接続して、信号を検出するためのフォトカプラの使い方を聞いてみます。
すると、最初は汎用フォトカプラの入力に1KΩの抵抗、出力に10μFの平滑コンデンサを入れて、nodeMCUと接続する方法を推奨しました。
「スピーカー出力なので、無極性フォトカプラじゃなくていいの?」と聞くと、あたかも自分は間違っていないといわんばかりに、ACを入力するので無極性フォトカプラのほうが良い、と言い返してきました。

必要な部品は、ケースなどを含めて、

  • 無極性フォトカプラTLP620 または PC814
  • 抵抗1kΩ (1/4W)
  • 電解コンデンサ10μF~47μF (耐圧16V以上)
  • タカチSW65
  • 両面スルーホールユニバーサル基盤(nodeMCUのGPIO端子間隔に合わせて2.0mmピッチ)

特に、ケースは壁の中に入れることを考え、厚さは4.5cm以内、コンセント穴に入るように、幅は50mm以内、高さは91mm以内にしなければなりません。
それもあって、タカチのSW65にしました。
秋月電子に注文して届いた部品を、ブレッドボードに組んでみます。

PH-2.0コネクタの先には、抜き差ししやすいようにエーモンの新型接続コネクターを付けました。


間違って、使わない赤い線にも接続コネクターを付けてしまいました。


VHK-RMA-HRWの裏にPH-2.0 4ピンを接続します。


実験の全体像

これで、インターホンを鳴らしても、nodeMCUは何も検出しません。
ナゼ?

どうやら、このAS AE接点も、初期状態では警報しか出力しないようです。
設定を変えるには、「施工者設定」という、業者用の設定モードに入る必要があります。
これがなかなかわからなかったのですが、Yahoo知恵袋で答えている人がいました。

detail.chiebukuro.yahoo.co.jp

そう、知りたかったのはこれです!

まずは、パネルを開けるときのネジの右にあった、「設定」という押しにくいプラスチックのボタンを手で押しながら、細い棒状のもの(ちいさなマイナスドライバ)で奥まったリセットボタンをポチっと押します。


設定の上にある⊂の左端を押すとクリック感があるので、これを指で押しながらリセット穴に細いマイナスドライバを入れてポチっとつつく。

すると、見慣れない画面が!


まずは右下の次へ→を押します。


その他の設定を押します。


補助音響装置呼出音鳴動が、警報音のみ鳴動になっているので、▼を押して。


警報音以外も鳴動を選択して決定、戻った画面で登録を押します。

これでAS AE端子にインターホンの音が出力され、フォトカプラを通してnodeMCUが検出できるようになりました。

ブレッドボードに組んだ回路を、ブレッドボードに移植します。
回路図はこんな感じです。

ケースSW65に入れてみたところ、ケーブルを接続するコネクタの頭が、ケース内寸より高いことが分かりました。
そこで、USB接続部分だけでなく、フタにも穴を開けます。
干渉するほど出るわけでなく、ちょうど収まる感じです。

さて、ここからは電気工事を伴う隠蔽設置です。
以前設置したRaspberry Pi Zero Wの横に設置できればよかったのですが、インターホンVHK-RMA-HRWとRaspberry Pi Zero Wの間には、LGSスタッドが縦に走っており、ケーブルを渡すことができません。
そこで、VHK-RMA-HRWの真下にコンセントサイズ(91mm x 50mm)の穴を開けます


通線後に撮った、コンセントサイズの穴。

VHK-RMA-HRWの上の隙間から、通線ケーブルを落とし、コンセントサイズの穴から通します。
そして、電源用のVVF1.6x2と、2本の通信線を通線します。


結構苦労したVVF通線。

インターホンVHK-RMA-HRWの電源スイッチを切り、ブレーカーを落として、インターホンにつながっているVVFを外し、3端子差し込みコネクタを経由して、一方はインターホンVHK-RMA-HRWの電源端子に戻し、もう一方は通線したVVFに接続してnodeMCUのUSB電源用にします。


VVFの分岐

VHK-RMA-HRWインターホンの下に開けたコンセントサイズの穴には、パナソニックコスモワイドの片切スイッチを設置。
片切スイッチにインターホンから分岐した電源VVFの一方を、VVFのもう一方はコンセントを接続。
片切スイッチのもう一方とコンセントを接続します。
コンセントにはUSB電源を接続し、nodeMCUの電源とします。
USB電源とnodeMCUを壁の中に押し込み、パナソニックのコスモワイド片切スイッチを取り付けて完了です。


左は以前からあるRaspberry Pi Zero Wの電源スイッチとコンセント、右が今回のnodeMCUのスイッチ。

こうすることで、万が一nodeMCUが暴走・無反応になっても、スイッチで再起動できます。
ハードの設置はここまで。
次は、VHK-RMA-HRWのインターホン発報を検出して、LINEの通知や別の部屋のGoogle Home mini(Nest mini)から音を出すようにプログラミングしていきます。