CPUをOpen Hardware MonitorとNodeJSで監視してSlackで通知する

# 何がしたいか
重いシミュレーションを長い時間かけてリモートPCで回し続けるのはやっぱり不安な点があり，特に知らん間に冷却装置が不調を来したらどうしようという不安に苛まれる，まして多少はCPUをチューニングしているような状態だとそれは尚更になる<br>
ということでスクリプトでCPU監視し続けて，温度が一定値を超えたらSlackに通知を投げ，Remote Desktopで非常措置を迅速に行えるようにした（ソフトの関係上でWindows限定だけど）~~（ネットワークが切れた場合のことは知らんものとする）~~



## 大まかな筋書き

+ サーバーモードのOpen Hardware MonitorでPCを監視
+ NodeJSでそのAPIを叩いてJSONを取得・加工
+ CPUの状態を評価して必要な場合はWebhookのAPIを叩く
+ Slackで確認して対応する




# 内容



## Open Hardware Monitorの設定


### インストール

https://openhardwaremonitor.org/


### サーバーモードで起動
管理者権限で`OpenHardwareMonitor.exe`を立ち上げた後に「Options」->「Remote Web Server」->「Run」で開始<br>
`localhost`でアクセス可能，ポートは`Options`->`Remote Web Server`->`Port`で設定できる，ここに出るリンクのIPアドレスはグローバルアドレスらしいけど，普通に`localhost`のほうが早いし楽なのでオススメ，環境によってはコロコロ変わるし



## NodeJSの用意
ハードウェアが絡むせいで色々と面倒だからWSLとか使わずにPowerShellから直にNodeJSを動かせるようにする


### 管理（nvm）の入手
他のツールで工夫するのも面倒なので公式が推してる`nvm-windows`を入れる

https://openhardwaremonitor.org/

https://github.com/coreybutler/nvm-windows/releases/

最新版の`nvm-setup.zip`を落として解凍，適当に回答してインストール


### NodeJSの入手
PowerShellを**管理者権限で起動**（じゃないとインストール後に有効化できない）<br>
`nvm list available`で出てきたバージョンから好きなものを選んで`nvm install x.y.z`<br>
最後に`nvm use x.y.z`，なぜか管理者権限が必要でない場合は`status:1`が返ってくる


## VSCodeの用意
あったら楽なので

https://code.visualstudio.com/download

入れたらgitの拡張機能も入れておくべし



## gitの用意

https://soluna-eureka.hatenablog.com/entry/2021/12/09/181714

実は上の記事でWSL2のUbuntuの中にgitを入れる前にWindowsにもgitを入れていた<br>
特に変なことをしなければインストールに問題は起きないしVSCodeの拡張機能にも対応してくれている（この場合は**絶対にAdjusting your PATH environmentで真ん中を選ぶ必要がある**ので注意）

https://git-scm.com/download/win

https://docs.microsoft.com/ja-jp/devops/develop/git/install-and-set-up-git

下の記事がわかりやすいかも

https://sukkiri.jp/technologies/devtools/git/git_win.html



## Slackの用意
適当なメアドでサインインしてブラウザ上で適当にワークスペースを作って通知専用のチャンネルを作る<br>
「設定と管理」「ワークスペースの設定」から「管理者設定」の画面が出るので左の「App管理」をクリック<br>
上の「Appディレクトリ」で「webhook」を検索して「Incoming Webhook」をクリック，「Slackに追加」を選択<br>
「チャンネルへの投稿」と「名前をカスタマイズ」「説明ラベル」を適当に編集して「Webhook URL」を確保

なお，複数のWebhook URLを使い分けたい場合は「Slackに追加」で更に作成できる，上限数は知らんけど



## プロジェクト作成
良さげなディレクトリを作ったらVSCodeから開いて拡張機能から`git init`する<br>
次にVSCode内でPowershell（ターミナル）を開いて`npm init`，適当に入力する<br.
さらに以下を`npm install`する

+ `@slack/webhook`
+ `date-and-time`
+ `get-json`
+ `node-schedule`
+ `post-json`
+ `simple-get-json`
+ `simple-post-json`



## スクリプト作成

+ JSONデータのうちCPU温度がある場所については各自で確認すること
  + シングルCPUなら`obj[0]['Children'][1]['Children'][1]['Children']`が持ってる配列に格納されている
+ 必ず`http://localhost:[numTCPport]/data.json`を叩くこと
  + これは実際ブラウザ上でJSONを確認できる
+ `coreTempLimit`で通知を出したいCPU温度の下限値を設定できる

```index.js
const scheduler = require('node-schedule');
const { getJSON } = require('simple-get-json');
const datetime = require('date-and-time');
const { IncomingWebhook } = require("@slack/webhook");

const slackURL = "[slack webhook url]";
const slackWebhook = new IncomingWebhook(slackURL);
const monitorURL = "http://localhost:8085/data.json";

const coreTempLimit = 50;

async function accessJSON() {
    var res = await getJSON(monitorURL);
    var raw = JSON.stringify(res, null, 4);
    var obj = JSON.parse(raw)['Children'];
    var tgt = obj[0]['Children'][1]['Children'][1]['Children'];
    return tgt;
}

async function makeMessage(tgt) {
    var cpuParam = "";
    var coreName = "";
    var coreTemp = "";
    var heatFlag = false;

    tgt.forEach(cpuCore => {
        coreName = cpuCore['Text'];
        coreTemp = cpuCore['Value']
        cpuParam += (coreName + " is " + coreTemp + "\n")
        floatCoreTemp = parseFloat(coreTemp);
        if (floatCoreTemp > coreTempLimit) {
            heatFlag = true;
        }
    });
    var txt = cpuParam + datetime.format(new Date(), 'HH:mm:ss:SSS YYYY/MM/DD');
    var flg = heatFlag;
    console.log(flg);
    return [txt, flg];
}

async function sendMessage(txt, flg) {
    if (flg) {
        await slackWebhook.send({
            text: `${txt}`
        });
    }
}


const scheduleBase = scheduler.scheduleJob("*/1 * * * * *", function() {
    var tgt;
    var txt = "";
    var flg = false;
    (async() => {
        tgt = await accessJSON();
        [txt, flg] = await makeMessage(tgt);
        await sendMessage(txt, flg);
    })();
});
```



## 稼働
`node index.js`で永久に稼働する，Slackにメッセージが飛べば成功<br>
デバッグ代わりに`flg`を出力している




# 改善したいところ
+ 検知間隔の設定を改善
  + `*/1 * * * * *`は1秒毎という意味，2なら2秒毎
+ GUI設定の実装
  + NodeJSのお得意技
+ データ化，グラフ化
+ ローカルネットワークで繋がる他の複数のPCと連携
  + 繋げっぱなしのPCクラスタのローカルアドレスは変わらん
  + GUIを経由しての登録・利用が生きる
  + たかがテキストデータだし輻輳にはならん