Node-REDで地震情報を監視させてLINE通知する

この記事は約29分で読めます。
※当サイトではリンク先にプロモーションを含みます、詳細はプライバシーポリシーをご参照ください。

プロローグ

個人的な勉強を兼ねての内容を、備忘録として記載。

ホントはLINE通知とALEXAに通知させたかったが、Node-REDをFREENASのJail環境で動かすと「node-red-contrib-alexa-remote2-v2」がうまく動かず(クッキーをうまく保持してくれない)、苦肉の策でLINE通知のみにしています。

この記事書いてて気づいたんですが、ソースのAPIのバージョンが古いものでした。
この記事書き終わったらv2に対応させようと思います。。。

工学社
¥2,530 (2024/11/10 05:34:19時点 Amazon調べ-詳細)

内容

はじめに、筆者は趣味の範囲でやっているだけなので内容についてはある程度多めに見てください…
動作保証や、動作による被害などについては一切の責任を負いません。

地震情報のソース

今回、ソースとしてP2P地震情報JSON API v1を利用させていただいています。
指定のURIをHTTP GETすると、JSON形式で地震情報が返ってきます。
IPアドレス単位で30リクエスト/分を超えなければよいそうなので、余裕をみて5秒に1回リクエストして前回から変化があって、かつ特定の震度以上であれば通知するようにしています。

概要

内容は数のような感じです。

5秒おきに情報を取ってきて、特定の震度(今回は5強以上)であればLINE通知するようにしています。
JSON形式で返ってくるので、その内容を小分けにしてfunctionで通知する文字列に整形。
LINE通知はLINE Notify APIを利用して、整形した文字列を引数として単純にcurlでPOSTするようにしています。

フローJSON

今動かしている風呂のJSONが以下の通りです。
とりあえず動いていますが、使用感次第で変更予定です。

必ず「Authorization: Bearer」のところに自身で発行したAPI IDを入力するようにしてください。

[
    {
        "id": "f59d1c5b.c7ca",
        "type": "tab",
        "label": "地震速報",
        "disabled": false,
        "info": ""
    },
    {
        "id": "c90611d9.0c6d7",
        "type": "inject",
        "z": "f59d1c5b.c7ca",
        "name": "開始",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "5",
        "crontab": "",
        "once": true,
        "onceDelay": "10",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 90,
        "y": 160,
        "wires": [
            [
                "230ca9ce.0d78c6"
            ]
        ],
        "info": "5秒ごとに実行"
    },
    {
        "id": "6d686ffb.490ce",
        "type": "http request",
        "z": "f59d1c5b.c7ca",
        "name": "情報取得",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "https://api.p2pquake.net/v1/human-readable?limit=1",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "x": 440,
        "y": 160,
        "wires": [
            [
                "ce05e6ef.7170a8"
            ]
        ],
        "info": "P2P地震情報から最新の地震情報を取得"
    },
    {
        "id": "ce05e6ef.7170a8",
        "type": "split",
        "z": "f59d1c5b.c7ca",
        "name": "情報加工",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "x": 580,
        "y": 160,
        "wires": [
            [
                "8d6ab049.793b",
                "48765529.957b4c"
            ]
        ],
        "info": "JSON情報を配列に変換"
    },
    {
        "id": "6077c38.3b7193c",
        "type": "debug",
        "z": "f59d1c5b.c7ca",
        "name": "",
        "active": true,
        "tosidebar": false,
        "console": false,
        "tostatus": true,
        "complete": "history",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 290,
        "y": 200,
        "wires": []
    },
    {
        "id": "230ca9ce.0d78c6",
        "type": "change",
        "z": "f59d1c5b.c7ca",
        "name": "履歴抽出",
        "rules": [
            {
                "t": "set",
                "p": "history",
                "pt": "msg",
                "to": "history",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 280,
        "y": 160,
        "wires": [
            [
                "6d686ffb.490ce",
                "6077c38.3b7193c"
            ]
        ],
        "info": "前回情報を呼び出し"
    },
    {
        "id": "d5b4ae48.73402",
        "type": "switch",
        "z": "f59d1c5b.c7ca",
        "name": "履歴判定",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "neq",
                "v": "history",
                "vt": "flow"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 1260,
        "y": 160,
        "wires": [
            [
                "8749ccc2.040ec"
            ]
        ],
        "info": "前回通知時の情報と一致した場合、変化点ないため終了"
    },
    {
        "id": "cf3fab5b.709c58",
        "type": "link out",
        "z": "f59d1c5b.c7ca",
        "name": "Exit1",
        "links": [
            "f0ca9368.8cb55"
        ],
        "x": 1575,
        "y": 160,
        "wires": []
    },
    {
        "id": "f0ca9368.8cb55",
        "type": "link in",
        "z": "f59d1c5b.c7ca",
        "name": "",
        "links": [
            "cf3fab5b.709c58"
        ],
        "x": 75,
        "y": 360,
        "wires": [
            [
                "221fd18c.c2879e"
            ]
        ]
    },
    {
        "id": "221fd18c.c2879e",
        "type": "change",
        "z": "f59d1c5b.c7ca",
        "name": "履歴出力",
        "rules": [
            {
                "t": "set",
                "p": "history",
                "pt": "flow",
                "to": "payload",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 180,
        "y": 360,
        "wires": [
            [
                "3e99db49.85ba74"
            ]
        ],
        "info": "今回取得した情報を前回情報用のフロー変数へ変換"
    },
    {
        "id": "3e99db49.85ba74",
        "type": "switch",
        "z": "f59d1c5b.c7ca",
        "name": "震度判定",
        "property": "scale",
        "propertyType": "msg",
        "rules": [
            {
                "t": "gte",
                "v": "5",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 340,
        "y": 360,
        "wires": [
            [
                "7b511cd7.0492f4",
                "f0be9c11.e6655"
            ]
        ],
        "info": "特定の震度以上だった場合通知させる"
    },
    {
        "id": "48765529.957b4c",
        "type": "switch",
        "z": "f59d1c5b.c7ca",
        "name": "震源地判定",
        "property": "payload.earthquake.hypocenter.name",
        "propertyType": "msg",
        "rules": [
            {
                "t": "neq",
                "v": "\"\"",
                "vt": "str"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 2,
        "x": 770,
        "y": 160,
        "wires": [
            [
                "5751d91c.fb3018"
            ],
            [
                "7cff2734.c4ce68"
            ]
        ],
        "info": "震源地が空だった場合は終了する\n(過去空だったことがあったため)"
    },
    {
        "id": "5751d91c.fb3018",
        "type": "switch",
        "z": "f59d1c5b.c7ca",
        "name": "震度判定",
        "property": "scale",
        "propertyType": "msg",
        "rules": [
            {
                "t": "gte",
                "v": "1",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 1120,
        "y": 160,
        "wires": [
            [
                "d5b4ae48.73402"
            ]
        ],
        "info": "震源地が0だった場合は終了する"
    },
    {
        "id": "f0be9c11.e6655",
        "type": "debug",
        "z": "f59d1c5b.c7ca",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 510,
        "y": 400,
        "wires": []
    },
    {
        "id": "ee084991.75d8a8",
        "type": "exec",
        "z": "f59d1c5b.c7ca",
        "command": "curl",
        "addpay": true,
        "append": "",
        "useSpawn": "false",
        "timer": "",
        "oldrc": false,
        "name": "LINE通知",
        "x": 680,
        "y": 360,
        "wires": [
            [
                "5c9118a3.f451f8"
            ],
            [
                "5c9118a3.f451f8"
            ],
            []
        ],
        "info": "Line Notify用のURLをcurlで実行"
    },
    {
        "id": "7b511cd7.0492f4",
        "type": "function",
        "z": "f59d1c5b.c7ca",
        "name": "引数生成",
        "func": "msg.payload = \" -X POST -H \\\"Authorization: Bearer [ここにAPI IDを入力する]\\\" -F \\\"message=\" + msg.payload + \"\\\" https://notify-api.line.me/api/notify\"\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 500,
        "y": 360,
        "wires": [
            [
                "ee084991.75d8a8"
            ]
        ],
        "info": "LINE Notifyで通知するためのコマンド引数を生成"
    },
    {
        "id": "5c9118a3.f451f8",
        "type": "debug",
        "z": "f59d1c5b.c7ca",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 850,
        "y": 360,
        "wires": []
    },
    {
        "id": "b57e30b.6992ed",
        "type": "comment",
        "z": "f59d1c5b.c7ca",
        "name": "フロー1−1",
        "info": "",
        "x": 110,
        "y": 120,
        "wires": []
    },
    {
        "id": "f1604b77.6917c8",
        "type": "comment",
        "z": "f59d1c5b.c7ca",
        "name": "フロー1−2",
        "info": "",
        "x": 130,
        "y": 320,
        "wires": []
    },
    {
        "id": "8d6ab049.793b",
        "type": "debug",
        "z": "f59d1c5b.c7ca",
        "name": "",
        "active": true,
        "tosidebar": false,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 730,
        "y": 100,
        "wires": []
    },
    {
        "id": "8749ccc2.040ec",
        "type": "function",
        "z": "f59d1c5b.c7ca",
        "name": "メッセージ生成",
        "func": "msg.scale = msg.payload.earthquake.maxScale / 10\n\nmsg.payload = msg.payload.earthquake.hypocenter.name + \"で、\" + msg.payload.earthquake.time + \"に最大震度\" + msg.scale + \"の地震が発生しました\"\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 1440,
        "y": 160,
        "wires": [
            [
                "cf3fab5b.709c58"
            ]
        ],
        "info": "通知用メッセージを生成"
    },
    {
        "id": "7cff2734.c4ce68",
        "type": "function",
        "z": "f59d1c5b.c7ca",
        "name": "震源地仮設定",
        "func": "msg.payload.earthquake.hypocenter.name = \"どこか\"\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 940,
        "y": 200,
        "wires": [
            [
                "5751d91c.fb3018"
            ]
        ],
        "info": "震源地がたまに抜けて通知されるので、苦肉の策"
    }
]

使用感

使用感はこんな感じです。震源地が抜けるのは情報ソースの問題としていますが、正しくはフロー側の問題です。(大変失礼いたしました)
情報の発表種類次第で震源地の情報有無が分かれるので、そこの判定をさせていないため抜ける事があります。(まだ未対策デス)

エピローグ

とりあえずの内容で自身のニーズを満たせています。


はじめはラズパイで稼働させていて、情報はAlexaに喋らせていましたがフロー関数?をよく理解しておらず情報の比較用にテキストファイルをSDカードに書き出していたら数日でSDカードがお亡くなりになりました。。。。
VPNサーバも兼ねていたのでとても困り、Node-REDはFreeNASのJail環境に作っています。

今後改良したら、随時Updateしていければと思います。

記事は以上

Raspberry Pi Zero WH スターターセット (USB小型電源, 高速型32GB MicroSD, USBスイッチケーブル, ケース, HDMIケーブル, MicroUSB変換付き)
NewLife NewDesing
タイトルとURLをコピーしました