Alexaによる野球チャンネルの自動化3(Nature Remo Local API)

前回はNatutre RemoのクラウドAPIを使用してテレビのリモコン信号を制御しましたが、この方法だとNature Remoのクラウドサーバーを経由することになり、5分間30回のリクエスト回数の制限に引っかかりやすい、Nature Remoのサーバーが落ちていると使えない、という問題がありました。これを回避するために、Local APIを使用して、サーバーを経由せず直接Nature Remoに通信してリモコン信号を出す方法を探りました。
※方法など前回と重複するものは記載しません。

Nature Remoのアドレスを固定する

Nature Remoに対して直接通信するわけですが、Remoは今までwifiルーターのDHCPによってIPアドレスが割り当てられていました。このまま状態でプログラムを作ると使用開始前にRemoのIPアドレスを調べて、それに対して通信を行うという面倒なものになりそうなので、まずアドレスを固定しました。
他のwifiルーターにも同じような機能はあると思うのですが、私の持っているwifiルーターBuffalo Air Station WSR-1166DHPL2(古い安物)では、DHCPにMACアドレスに対して固定のIPアドレスを割り当てるという機能がありましたので、それを使用します。

まず、RemoのMACアドレスを調べます。
Test3.py
from remo import NatureRemoAPI
api = NatureRemoAPI(‘XXXアクセストークンXXX’)
devices = api.get_devices()
print(devices)

実行結果にmac_address=’xx:xx:xx:xx:xx:xx’とRemoのMACアドレスがあるので、それをもとにアドレスを固定化します。JSON整形ツールで整形するとMACアドレスを探しやすいです。
wifiルータにログインし、[詳細設定]-[LAN]-[DHCPリース]画面を開き、該当のMACアドレスに対して固定のIPアドレスが割り当てられるように設定します。wifiルーターの再起動で反映されます。

Nature Remo Local APIのページ(https://local-swagger.nature.global/)にもありますし、それを説明したサイトにもありますが、dns-sdコマンドを使っています。これについて調べてみました。

dns-sdコマンドはmDNS(マルチキャストDNS)に関係しており、既にmDNSはWindows10 に搭載している、ということまではわかりましたが、dns-sdコマンドをコマンドプロンプトで打ってもそんなコマンドがないという感じです。
探した結果、以下のページが参考になりました。

networking – dns-sdコマンドラインテストツールをWindowsまたはLinuxにインストールする方法
https://tutorialmore.com/questions-1800406.htm

dns-sdはアップルのサイトでBonjour SDKをインストールすると使えるようになるとのことでした。以下のサイトにアクセスし、[Bonjour SDK for Windows]をクリックし、ダウンロードします。Apple IDの入力を求められます。アカウントがない場合は作成します。
https://developer.apple.com/bonjour/

Bonjour SDKをインストールするとdns-sdコマンドがコマンドプロンプト使えるようになりました。

>dns-sd -B _remo._tcp

しかし、いつまで待っても何の応答もありません。Ctrl+Cで強制終了しました。
いろいろ調べてみましたが、wifiルーターの以下の設定が気になりました。
[詳細設定]-[無線設定]-[マルチキャスト制御]画面のSnooping機能が「使用する」になっていました。これはネットワークの余計なトラフィックを減少させるため、セキュリティのためにある機能のようです。理解したわけではありませんが、これを一時的に解除し、試してみました。終わったら使用する、に戻しました。

> dns-sd -B _remo._tcp
Browsing for _remo._tcp
Timestamp     A/R Flags if Domain                    Service Type              Instance Name
11:20:11.476  Add     2 24 local.                    _remo._tcp.               Remo-XXXXXX

Nature Remoが見つかったようです。このあと終わらないのでCtrl+Cで強制終了しました。得られた名前に対して.localを付け加えて以下のコマンドも試しました。

> dns-sd -G v4 Remo-XXXXXX.local
Timestamp     A/R Flags if Hostname                  Address                                      TTL
11:23:47.264  Add     2 24 Remo-XXXXXX.local.        192.168.xx.xx                                120

固定で割り当てたアドレスが取得できました。dns-sdなるものをネットで調べるのにかなり時間がかかってしまいましたので、得られた回答に少し拍子抜けしました。要は名前をマルチキャストすると該当するデバイスが返事を返す仕組みになっていて、それを使ってIPアドレスを取得しろ、ということだったのかな。Bonjour SDKはこれ以上必要ないのでアンインストールしました。

Nature Remo Local APIについて

Local APIにはGET /messageとPOST /message2つのインターフェースしかありません。GETは引数無し、POSTはメッセージのみです。この2つで何をどうすれというのでしょうか?
以下のページを参照にしました。

Nature RemoのローカルAPIを叩いて家電を操作する
https://takagi.blog/controlling-home-appliances-using-local-api-with-nature-remo/

どういうことかというと、まずリモコンをRemoに向けて、あるボタンを押します。Remoはリモコンの信号を受信すると青く点滅し、その赤外線信号のデータを一定時間記憶します。
GETするとRemoは記憶している赤外線の信号データをメッセージとして返信します。返信されたメッセージをそのボタンの信号としてメモしておきます。
メモした赤外線信号データをPOSTすると、Remoから赤外線信号を送出する、ということのようです。
どうやらRemo本体にはテレビや照明、エアコンの型式別のデータは持っておらず、リモコンのボタン1つ分のデータしか保持していないようです。

コマンドプロンプトで以下のコマンドを発行し、GETコマンドを送信します。192.168.xx.xxはRemoのIPアドレスです。

>curl -X GET http://192.168.xx.xx/messages -H “X-Requested-With: curl” -H “Expect:”

レスポンスとして以下のようなデータが返されます。
{“format”:”us”,”freq”:36,”data”:[3401,1821,353,516,……中略…… ,362,1380,351]}
レスポンスとして表示されたデータをボタンと対応させてメモしておきます。これを必要なボタンの種類だけ行います。
同じボタンでも押したときによってデータの値が微妙に違います。データの数値の意味はわかりませんが、Remoの赤外線信号の計測データなのでしょう。
※freq:36とあるのは36Hz=27.8ms間隔?、dataは27.8ms毎の信号レベル?どうでもいいことかもしれないが若干気になります。

Pythonのnature remoライブラリget_ir_signal関数を使っても赤外線信号データを取得できますが、出力がライブラリ独自のものに整形されてしまっているので、そのままでは使えませんでした。このため、curlコマンドを使用しました。curlコマンドはWindows10で標準になったようです。
送信は簡単なのでnature remoライブラリ関数send_ir_signal()を使用します。

Local API版プログラム

上記を踏まえ、今日の野球チャンネルに切り替えるプログラムを以下のように改修しました。
remo_ip=にはRemoのIPアドレスに置き換えてください。
xx-button=の部分はcurlコマンドで取得した赤外線信号のデータに置き換えてください。
プログラムをftpで転送し、上書きます。

BaseballCh.py
import pandas as pd
import openpyxl
import datetime
from remo import NatureRemoLocalAPI

excel_file = './FightersCh.xlsx'
remo_ip = '192.168.xx.xx'
bs_button = '---bs_button_data---'
cs_button = '---cs_button_data---'
down_button = '---down_button_data---'
ok_button = '---ok_button_data---'
s_button = '---s_button_data---'
ch1_button = '---ch1_button_data---'
ch2_button = '---ch2_button_data---'
ch3_button = '---ch3_button_data---'
ch4_button = '---ch4_button_data---'
ch5_button = '---ch5_button_data---'
ch6_button = '---ch6_button_data---'
ch7_button = '---ch7_button_data---'
ch8_button = '---ch8_button_data---'
ch9_button = '---ch9_button_data---'
ch0_button = '---ch10_button_data---'

# 日付の取得
dt = datetime.datetime.today()
month = dt.month
day = dt.day

# 今日のチャンネルの取得
openpyxl.reader.excel.warnings.simplefilter('ignore')
df = pd.read_excel(excel_file, sheet_name=str(month))
ch = df.iloc[day-1, 3]
if ch == ch:
    # チャンネルあり、チャンネル名の操作取得
    df_ch = pd.read_excel(excel_file, sheet_name=str('channel'))
    for row in range(len(df_ch)):
        if ch == df_ch.iloc[row, 1]:
            # chの操作数取得
            num = df_ch.iloc[row, 2]
            # Nature Remoオブジェクトの取得
            api = NatureRemoLocalAPI(remo_ip)
            # 操作数でループ
            for i in range(num):
                # ボタン操作を送信
                button = str(df_ch.iloc[row, 3+i]).upper()
                if button == 'BS':
                    api.send_ir_signal(bs_button)
                elif button == 'CS':
                    api.send_ir_signal(cs_button)
                elif button == 'S':
                    api.send_ir_signal(s_button)
                elif button == 'DOWN':
                    api.send_ir_signal(down_button)
                elif button == 'OK':
                    api.send_ir_signal(ok_button)
                elif button == '0':
                    api.send_ir_signal(ch0_button)
                elif button == '1':
                    api.send_ir_signal(ch1_button)
                elif button == '2':
                    api.send_ir_signal(ch2_button)
                elif button == '3':
                    api.send_ir_signal(ch3_button)
                elif button == '4':
                    api.send_ir_signal(ch4_button)
                elif button == '5':
                    api.send_ir_signal(ch5_button)
                elif button == '6':
                    api.send_ir_signal(ch6_button)
                elif button == '7':
                    api.send_ir_signal(ch7_button)
                elif button == '8':
                    api.send_ir_signal(ch8_button)
                elif button == '9':
                    api.send_ir_signal(ch9_button)
            break

課題

テストしてわかったのですが、5分間30回というリクエスト回数制限はLocal APIを使っても変わりませんでした。何故かそう思いこんでいたようです。
サーバーを経由してないため、Nature Remoサーバーが落ちていても動作できるのは、多分そうだと思いますが、試していないのでわかりません。
同じボタンなのに、試行毎にちょっとずつ違うデータが取得されるというのも少し気になります。(後日、数字の9をテレビが認識してくれないのが発覚し、データを再設定しました。)

Alexaによる野球チャンネルの自動化2(Nature API)

定型アクションによる自動チャンネル変更は節が変わる度に定型アクションのメンテナンスが必要でした。年間放送スケジュールは決まっているため、これを使ってチャンネルを変更する方法を考えてみました。 リモコンを自動化するNature RemoはAlexaと連携するだけではなく、Nature APIと呼ばれるHTTP通信でのリモコン機能も提供しています。これにより、個人が独自に作成したプログラムからNature Remoを制御できます。

Nature Developer Page
https://developer.nature.global/

チャンネル変更のテスト

まず、Nature APIでチャンネルを変更するテストをしてみました。
以下のページを参考にしました。

Nature Remo を Python から操作する
https://qiita.com/morinokami/items/6eb2ac6bed48d2c7534b

テスト環境はWindows10+VisualStudioCodeにしました。Pythonも含め、既に過去にインストールしていたからです。Pythonがインストールされていればどの環境でも問題ないと思われます。
とりあえず、PythonのNatureRemoライブラリをインストールしました。

>pip install -U nature-remo
-Uオプションは、指定されたすべてのパッケージを、利用可能な最新バージョンにアップグレードするという意味のようです。

Nature APIを使用するには以下のサイトでアクセストークンと呼ばれるIDを取得しなければなりません。
https://home.nature.global/
アクセストークンは取得したときの画面でしか確認することができず、後で見ることができないので注意してください。画面に表示された文字列をコピーして保存しておきます。

リモコン操作を行うには、アクセストークンの他にもAppliance IDと呼ばれる家電IDも必要です。家電IDを取得するテストプログラムは以下のようになります。

Test1.py

from remo import NatureRemoAPI
api = NatureRemoAPI('XXXXXXXXX')
appliances = api.get_appliances()
print(appliances)

XXXXXXXXXの部分はNatureのWebサイトで取得したアクセストークンになります。使用したNatureRemoライブラリはHTTP通信が隠蔽されていて、とても簡単に使用できます。
テストプログラムを実行し、成功するとJSON文字列が出力されます。これをJSONを見やすくしてくれるサイトで整形します。
https://json.onl.jp/

得られた結果からテレビのAppliance IDを探し、メモします。我が家の場合、照明、エアコンの下にテレビの記載がありました。

また、必要なボタン名(name=で示される)もメモしておきます。本当はシーンを直接指定したかったのですが、私はNatureAPIからシーンを取得することはできませんでした。

上記で得られた情報でチャンネルを切り替えるテストプログラムです。
GAORA sports(CS254)に切り替えます。
ご自身で取得したアクセストークンとAppliance ID、ボタン名をコピーして実行してください。
チャンネルの切り替え操作はご自分のテレビの操作に合わせたプログラムにしてください。
Test2.py

from remo import NatureRemoAPI

access_token = '-----アクセストークン-----'
appliancees_id = '-----Appliance ID-----'
bs_button = 'input-bs'
cs_button = 'input-cs'
down_button = 'down'
ok_button = 'ok'
s_button = 'submenu'
ch1_button = 'ch-1'
ch2_button = 'ch-2'
ch3_button = 'ch-3'
ch4_button = 'ch-4'
ch5_button = 'ch-5'
ch6_button = 'ch-6'
ch7_button = 'ch-7'
ch8_button = 'ch-8'
ch9_button = 'ch-9'
ch0_button = 'ch-10'

api = NatureRemoAPI(access_token)

api.send_tv_infrared_signal(appliancees_id, cs_button)
api.send_tv_infrared_signal(appliancees_id, s_button)
api.send_tv_infrared_signal(appliancees_id, down_button)
api.send_tv_infrared_signal(appliancees_id, down_button)
api.send_tv_infrared_signal(appliancees_id, ok_button)
api.send_tv_infrared_signal(appliancees_id, ch2_button)
api.send_tv_infrared_signal(appliancees_id, ch5_button)
api.send_tv_infrared_signal(appliancees_id, ch4_button)

チャンネルが切り替わったでしょうか?
注意点があります。NatureRemoAPIは5分間に30回の使用制限があります。上記の場合は1回のチャンネル切り替えに8回の送信を行っていますので、連続して行うと3回までしか成功しません。4回目の途中でエラーになってしまいます。

次にその日のチャンネルを取得する方法です。Pythonのpandasというライブラリを使用すればExcelファイルを操作できるという事で、Excelに情報を格納することにしました。

その日のチャンネルを取得し、変更するプログラム

まず、以下のようなExcelファイルを作りました。月ごとにシートを作りました。
曜日、対戦相手はプログラムでは使いませんが、見やすくするために項目を作りました。ミスなく入力できるように、対戦相手とチャンネルは[channel]シート、[team]シートで定義したリストから選択するようにしています。
曜日は1日の曜日を入力後、ドラッグすれば以下の曜日が入ります。

[channel]シートにはチャンネル名とチャンネルへのリモコン操作も定義しました。ボタン操作数も汎用性を持たせるために定義しておきました。

Excelファイルはダウンロードできるようにしておきました。FightersCh.xlsxというファイル名です。

このExcelファイルを読み込み、チャンネルを変更するPythonプログラムは以下のようになりました。
BaseballCh.py

import pandas as pd
import openpyxl
import datetime
from remo import NatureRemoAPI

excel_file = './FightersCh.xlsx'
access_token = '-----アクセストークン-----'
appliancees_id = '-----Appliance ID-----'
bs_button = 'input-bs'
cs_button = 'input-cs'
down_button = 'down'
ok_button = 'ok'
s_button = 'submenu'
ch1_button = 'ch-1'
ch2_button = 'ch-2'
ch3_button = 'ch-3'
ch4_button = 'ch-4'
ch5_button = 'ch-5'
ch6_button = 'ch-6'
ch7_button = 'ch-7'
ch8_button = 'ch-8'
ch9_button = 'ch-9'
ch0_button = 'ch-10'

# 日付の取得
dt = datetime.datetime.today()
month = dt.month
day = dt.day

# 今日のチャンネルの取得
openpyxl.reader.excel.warnings.simplefilter('ignore')
df = pd.read_excel(excel_file, sheet_name=str(month))
ch = df.iloc[day-1, 3]
if ch == ch:
    # チャンネルあり、チャンネル名の操作取得
    df_ch = pd.read_excel(excel_file, sheet_name=str('channel'))
    for row in range(len(df_ch)):
        if ch == df_ch.iloc[row, 1]:
            # chの操作数取得
            num = df_ch.iloc[row, 2]
            # Nature Remoオブジェクトの取得
            api = NatureRemoAPI(access_token)
            # 操作数でループ
            for i in range(num):
                # ボタン操作を送信
                button = str(df_ch.iloc[row, 3+i]).upper()
                if button == 'BS':
                    api.send_tv_infrared_signal(appliancees_id, bs_button)
                elif button == 'CS':
                    api.send_tv_infrared_signal(appliancees_id, cs_button)
                elif button == 'S':
                    api.send_tv_infrared_signal(appliancees_id, s_button)
                elif button == 'DOWN':
                    api.send_tv_infrared_signal(appliancees_id, down_button)
                elif button == 'OK':
                    api.send_tv_infrared_signal(appliancees_id, ok_button)
                elif button == '0':
                    api.send_tv_infrared_signal(appliancees_id, ch0_button)
                elif button == '1':
                    api.send_tv_infrared_signal(appliancees_id, ch1_button)
                elif button == '2':
                    api.send_tv_infrared_signal(appliancees_id, ch2_button)
                elif button == '3':
                    api.send_tv_infrared_signal(appliancees_id, ch3_button)
                elif button == '4':
                    api.send_tv_infrared_signal(appliancees_id, ch4_button)
                elif button == '5':
                    api.send_tv_infrared_signal(appliancees_id, ch5_button)
                elif button == '6':
                    api.send_tv_infrared_signal(appliancees_id, ch6_button)
                elif button == '7':
                    api.send_tv_infrared_signal(appliancees_id, ch7_button)
                elif button == '8':
                    api.send_tv_infrared_signal(appliancees_id, ch8_button)
                elif button == '9':
                    api.send_tv_infrared_signal(appliancees_id, ch9_button)
            break

今月の月のシートを開き、今日のチャンネル名を取得します。
チャンネルがあればチャンネルシートで該当するチャンネルの行を見つけ、その行の操作数と操作を取得し、ボタン操作を送信します。
このプログラムを動作させるために、追加でpandas,numpy,openpyxlをインストールする必要があります。

>pip install pandas
>pip install numpy
>pip install openpyxl

このプログラムの場合BaseballCh.pyとFightersCh.xlsxは同じディレクトリになければなりません。
プログラムを実行させ、意図通りに機能することを確認します。

AlexaとPythonプログラムをNode-Redで繋げる1

AlexaとPythonプログラムを連携させるためにNode-REDを使います。
以前、以下のページを見たときは衝撃的でした。これに従って進めます。

WM×LI: Amazon Echo と Raspberry Pi を Node-RED Alexa Home Skill Bridge で連携させて声でパソコンを起動したりシャットダウンしたりする.
https://nort-wmli.blogspot.com/2018/11/amazon-echo-raspberry-pi-node-red-alexa.html

以下のURLでNode-REDアカウントを作成し、デバイスを作成します。
Login or RegisterのRegisterでアカウントを作成してから、Loginします。
https://alexa-node-red.bm.hardill.me.uk/

Add Deviceを押下し、デバイスを追加します。
名前と動作を入力します。
今回は居間にある玄関カメラモニター用のラズパイでPythonプログラムを作動させる予定なのでRaspberryPiLivingという名前にしてみました。
ActionsはOnにしかチェックしませんでした。
Application Typeはよくわかりませんが、ACTIVITYにしてみました。
OKを選択し、デバイスを追加します。

次にNode-REDスキルを有効にして作成したデバイスを検出します。
スマホのAlexaアプリを起動して、「その他」-「スキル・ゲーム」-「検索」でNode-REDを検索します。

Node-REDを選択し、有効にします。

Node-REDのページで登録したユーザー名とパスワードを入力します。

正常にリンクができたことを確認し、閉じるボタンを押下します。

「端末の検出」を選択します。

シーンとしてデバイスが検出されたようです。「完了」を押します。
(2022/08/02追記)
Application TypeをACTIVITYにしたためにシーンとして検出されたようです。
それ以外だとデバイスとして検出されます。

Alexaアプリの「デバイス」-「シーン」で確認すると、作成したデバイス「RaspberryPiLiving」が追加されたのが確認できました。

ラズベリーパイにNode-REDをインストール

ラズベリーパイにNode-REDをインストールします。
最初は以前セットアップした防犯カメラモニター用のラズベリーパイにNode-REDだけをインストールしようとしましたが、OSの再インストールからすることにしました。
(私の理解力が無く、最新のOSをインストールしないと実現できないと思ってしまったのです。)

Raspberry PiのホームページからRaspberry Pi Imagerをダウンロードし、インストールします。最新のOSをインストールするために最新のImagerをインストールします。
https://www.raspberrypi.com/software/
ImagerでDesktop(Recommended)を選択し、イメージをSDに書き込みます。

書き込んだSDをRaspberryPiにセットし電源を入れます。
画面の指示に従い、国設定、ユーザー/パスワード設定、画面ブランク設定、Wifi設定、Softwareアップデートを行い、再起動を行います。(スクリーンショットが撮れませんでした)
メインメニューから「設定」-「Raspberry Piの設定」を選択し、インターフェースタブでSSHを有効にします。(有効にしないとftpが使えません)

メインメニューから「設定」-「Recommanded Software」を選択し、「Programming」カテゴリのNode-REDにチェックを入れ、「Apply」ボタンを押下します。
ダウンロードとインストールが始まり、成功したら「Installation complete」と表示されます。

ターミナルを開き、Node-REDの自動起動を有効にして、Node-REDを起動します。
$ sudo systemctl enable nodered
$ sudo systemctl start nodered

AlexaとPythonプログラムをNode-Redで繋げる2

ブラウザを起動し、http://xxx.xxx.xxx.xxx:1880を開きます。xxx.xxx.xxx.xxxはラズベリーパイのIPアドレスです。ラズベリーパイでも別のPCからでも構いません。

画面右上の三本線をクリックし、「パレットの管理」を選択します。
「ノードを追加」を選択して,「alexa-home-skill」と入力します。
「no-red-contrib-alexa-home-skill」が表示されたら「ノードを追加」ボタンを押下します。

「追加」ボタンを押下します。追加されたら「閉じる」ボタンでパレットの管理画面を閉じます。

画面左側のパレットの下にalexaが追加されます。

パレットから「alexa-home」と「debug」をフロー図に配置し、繋げます。
「debug」ノードは配置すると「msg.payload」の表示に変わってしまいました。
通信内容を表示する、という意味なのでしょう。

「Alexa Home」ノードをクリックします。Acount横の鉛筆アイコンをクリックします。

Node-REDのユーザー名とパスワードを入力し、「追加」ボタンを押下します。

DeviceにNode-REDのページで作成したデバイスを選択し、「完了」を押します。

Alexa Homeノードがデバイス名の表示に変わります。

右上の「デプロイ」ボタンを押下して設定内容を送信します。

テストしてみます。
スマホのAlexaアプリで「その他」-「定型アクション」で定型アクションを追加します。
「アクションを追加」を押下し、「スマートホーム」-「シーンをコントロール」と選択していき、デバイス「RaspberryPiLiving」を選択します。確認画面で「追加」を押します。

画面右上の虫アイコンを選択し、デバッグウインドウを表示します。
定型アクションを実行すると、デバッグウインドウにメッセージが表示されます。
AlexaとNode-REDが繋がったことが確認できました。

AlexaとPythonプログラムをNode-Redで繋げる3

次にRaspberryPiのPythonプログラムを転送します。
ftpアプリでBaseballCh.pyとFightersCh.xlsxを転送します。
ftpはバイナリモードになっていることを確認してください。テキストモードで転送するとファイルが壊れます。
転送先は適切なディレクトリを選択すべきですが、ここでは仮に/home/pi/にしておきます。

ターミナルで必要なPythonライブラリのpandas、numpy、openpyxl、NatureRemoAPIをインストールします
$ pip install -U pandas
$ pip install -U numpy
$ pip install -U openpyxl
$ pip install -U nature-remo

ここで転送したプログラムを起動してみます。
$ python BaseballCh.py
すると次のようなエラーが発生しました。

IMPORTANT: PLEASE READ THIS FOR ADVICE ON HOW TO SOLVE THIS ISSUE!

Importing the numpy C-extensions failed. This error can happen for
many reasons, often due to issues with your setup or how NumPy was
installed.

We have compiled some common reasons and troubleshooting tips at:

    https://numpy.org/devdocs/user/troubleshooting-importerror.html

Please note and check the following:

  * The Python version is: Python3.9 from "/usr/bin/python"
  * The NumPy version is: "1.22.4"

and make sure that they are the versions you expect.
Please carefully study the documentation linked above for further help.

Original error was: libcblas.so.3: cannot open shared object file: No such file or directory

エラーメッセージ示されたページで確認すると、libatlas-base-devをインストールするか、numpyをアンインストールし、python3-numpyをインストールしてみろ、とのことでした。

指示通りlibatlas-base-devをインストールしたところ、エラーなく動作するようになりました。
$ sudo apt install libatlas-base-dev

Node-REDに戻り、debugノードを削除して代わりに「exec」ノードを配置、接続します。
「exec」ノードをクリックします。

コマンドに「python /home/pi/BaseballCh.py」、名前に「チャンネル変更」と入力し、「完了」ボタンを押下します。

「デプロイ」ボタンでフローを送信します。

最後に「日ハムの試合にして」という定型アクションを変更します。チャンネルのシーンを削除し、Node-REDデバイスを追加します。これで作成完了です。

『アレクサ、日ハムの試合にして』と言うと北海道日本ハムファイターズを放送するチャンネルに切り替わるはずです。

課題

節の変わり目でいちいちメンテナンスする必要がないようにシステムを変更する事が出来ました。しかし、不満な点があります。

1)常に稼働するコンピュータが必要である。
自分の場合は防犯カメラで24時間稼働中のラズパイがありそれを使用しましたが、ない場合はこれだけのために稼働させることになるため、スマートな感じがしないです。
Alexaスキルを作成できれば解決するかもしれません。

2)NatureAPIの回数制限に引っかかりやすい。
1回のチャンネル変更に8回のNatureRemoサーバーとの通信が発生するので、5分間30回の制限に到達しやすいです。実際使用する上では1日1回程度しか使わないので規制に引っかかることは少ないと思いますが、昼間だと赤外線が通りにくいときがあり、何回も言ってしまうことがあるかもしれません。デバッグの時は動作確認が捗りませんでした。Nature Remoのサーバーをタダで使わせてもらっているので、制限自体は理解できます。もっと制限を緩くしてとは思いません。
解決策としては以下が思い浮かびます
a.シーン指定をできる仕組みがあれば、1回の通信で済むので回数制限を意識することは殆どなくなると思います。
b.Nature RemoのLocal APIを使えればクラウドサーバーを経由せず、LAN内で完結するので回数制限と関係なくなります。NatureRemoサーバーがダウンしていても使えるという利点もあります。

3)雨天順延等のスケジュール変更に手間がかかる。
雨天順延でスケジュールが変更になった場合、Excelファイルを修正し、それをラズベリーパイにアップロードします。これは定型アクションでチャンネル操作をまとめたシーンを指定するやり方と比べ、手間がかかります。注意してExcelファイルを作成したつもりでも間違っている心配もあります。

4)家にいないと、メンテナンスできない
ExcelファイルのアップロードはLAN内でしかできないため、家に不在のときは作業を行うことができません。発端は機械音痴の家族のためのシステムなので、これは片手落ちと言っても過言ではないかもしれません。
ただ、この場合は定型アクションで追加するアクションを一時的にNode-REDデバイスからチャンネルのシーン指定に戻すことで解決します。やはり、シンプル・イズ・ベスト。単純な方が良いシステムなのだと思わさります。

Alexa定型アクションによる野球チャンネルの自動化

最近Amazon Echoにハマっています。スマートリモコンであるNature Remo miniを同時に買ったのですが、これとEchoを組み合わせると、言葉でテレビや照明、エアコン等を操作でき、まるで未来の家のようです。

しかしながら、音声によるテレビ操作は『アレクサ、テレビつけて/消して』と言えば電源のON/OFFができるので、この限りにおいてはまあ良しですが、チャンネル変更に至っては今一つ便利でありません。リモコンのボタン操作一つ一つをアレクサに言葉で言うことになり、BSやCSのチャンネルに合わせるのはひと苦労です。

若干切実な問題もあります。同居の親が機械音痴で何回教えてもスカパーのプロ野球にチャンネルを合わせることができません。できるときもありますが、チャンネルを見つけることができない日もあるのです。年齢を考えるとこの先改善する可能性も低いです。Echoを買う前にもいろいろ試してみましたが、イマイチしっくりきませんでした。

『アレクサ、日ハムの試合にして』と言うだけでスカパーの応援するチームのチャンネルに合わせる方法を探りました。

シーンの作成

調べたところ、シーンという機能がNature Remoにあることがわかりました。シーンは本来、複数の家電製品を同時に制御する機能です。例えば『おやすみ』のシーンでは照明、エアコン、テレビを同時に消す、というように、複数の家電製品の操作をシーンに合わせてひとまとめにするときに使います。このシーンという機能を使いチャンネル選局をすることを思いつきました。
居間にあるテレビはパナソニックの古いビエラですが、『3桁入力選曲』という機能を使って選局することにします。

パナソニックのビエラのリモコン

例えばGAORA<CS254>を選局する場合、『CS』に合わせてからサブメニューである『S』ボタンを押しサブメニューを表示します。3桁入力選局は上から3番目ですので、『▼』『▼』『決定』という操作になります。次にチャンネル番号『2』『5』『4』を入力すると、GAORAが選局されます。

つまり、『CS』『S』『▼』『▼』『決定』『2』『5』『4』というテレビリモコンの一連の操作をひとまとめにした『GAORA』という名前のシーンを作成します。ボタン操作の間に間隔は不要のようです。

スマホのNature Remoアプリでシーンを作成

プロ野球を放送するチャンネルの数だけ、シーンを作成します。

フジテレビTWO、スポーツライブ+、日テレNEWS24、J SPORTS 1、J SPORTS 2、J SPORTS 3、J SPORTS 4、スカイA、日テレジータス、TBSチャンネル2、フジテレビONE

全部作ると、結構大変ですね。

定型アクションの作成

スマホのアレクサアプリの定型アクションを作成し、『アレクサ、日ハムの試合にして』と言うだけでスカパーの日ハムの試合に自動的にチャンネルが切り替わるようにします。

定型アクション名:日ハムテレビ

実行条件:音声『アレクサ、日ハムの試合にして』

アクション:[スマートホーム]-[シーンをコントロール]-[GAORA]

これで作成が完了です。

アクションで選択するシーンは節ごとに都度日本ハムファイターズの公式ホームページで確認して、定型アクションの設定を変更します。

https://www.fighters.co.jp/news/broadcast/

1週間に2度ほど定型アクションのメンテナンス作業が必要なシステムはカッコ悪いですが、これが一番簡単で最も手間がかからない方法です。現在、もっと自動的でスマートな方法を検討中ですが、調べているうちに結構な時間を費やしてしまいました。総合的に判断してこれが一番賢い方法だと自信を持って言えます。(笑)