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

何がしたいか

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

大まかな筋書き

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

内容

Open Hardware Monitorの設定

インストール

openhardwaremonitor.org

サーバーモードで起動

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

NodeJSの用意

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

管理(nvm)の入手

他のツールで工夫するのも面倒なので公式が推してるnvm-windowsを入れる

openhardwaremonitor.org

github.com

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

NodeJSの入手

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

VSCodeの用意

あったら楽なので

code.visualstudio.com

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

gitの用意

soluna-eureka.hatenablog.com

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

git-scm.com

docs.microsoft.com

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

sukkiri.jp

Slackの用意

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

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

プロジェクト作成

良さげなディレクトリを作ったらVSCodeから開いて拡張機能からgit initする
次に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温度の下限値を設定できる
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にメッセージが飛べば成功
デバッグ代わりにflgを出力している

改善したいところ

  • 検知間隔の設定を改善
    • */1 * * * * *は1秒毎という意味,2なら2秒毎
  • GUI設定の実装
    • NodeJSのお得意技
  • データ化,グラフ化
  • ローカルネットワークで繋がる他の複数のPCと連携