【ラズパイ】【いろいろ計測モニター】CPU温度をWindows側で表示する

前回の記事で、ラズパイのCPU温度を取得できることが分かったので、

これをいろいろ計測モニターに表示させるところまでやっていきたいと思います。

PythonでLinuxコマンドを実行し、結果を得るには以下の様にプログラミングします。

import subprocess

args = ['vcgencmd', 'measure_temp']
res = ""
try:
    res = subprocess.run(args, stdout=subprocess.PIPE)
except:
    print("Error.")

print(res.stdout)

参考記事

https://qiita.com/tdrk/items/9b23ad6a58ac4032bb3b

これを実行すると出力はこうなります。

これを色々と加工して、Windows側に渡すパラメータにします。

実際に組み込んだコード。

def getCPUTemp():
    args = ['vcgencmd', 'measure_temp']
    res = ""
    try:
        res = subprocess.run(args, stdout=subprocess.PIPE)
    except:
        return "Error."
    return res.stdout.decode().split('=')[1].strip().replace('\'C', '℃')
        data = {
            'datetime' : datetime.datetime.now().strftime('%Y:%m:%d %H:%M:%S'),
            'temperature': Temperature,
            'humidity': Humidity,
            'cputemp' : getCPUTemp()
        }

えっと、何をしているかというと、

まずは、res.stdoutの値はバイト文字なので、これをdecode()で文字列に変換します。

その後、split(‘=’)で=で文字列を分割し、後方の文字列([1])を取得します。

しかし、その文字列の中には不要な改行文字(\n)が入っているので、strip()で削除。

そして、「’C」と表示させているところをreplace()で「℃」に置き換えています。

これをJsonのパラメータに追加します。

ここまで出来ればWindows側は表示するだけなので、Windows側コードは割愛。

【ラズパイ】raspberry PI4には冷却用ファンを取り付けよう!

人が触れない温度。

https://qiita.com/BearcubThaw/items/070be8be8dc14e5837f4

$ vcgencmd measure_temp

というコマンド、ラズパイ専用コマンドがありまして、

このコマンドでCPUの温度を出力することが出来ます。

上のスクショはファン無し、アイドル状態で放置した状態でコマンド打った結果。

この温度、お風呂だったら入れないね。

この状態のまま重たい処理を実行させると、さらにCPU温度が上がって、ラズパイは確実に壊れます。

なので、ラズパイ専用のファンを買いました。

ネジが一本どっか行ったけど気にするな。

こっちは老眼で小さい部品見えないんだよ。

部品の中にはヒートシンクも入っていました。

これをCPUに貼り付けると、熱を吸い取って、表面積の多い凸凹部分に熱を伝え、これをファンの風で冷却します。

ファンを回した結果はこちら。

37℃まで下がりました。

人肌レベルですね。

まぁ、ラズパイ4はお勉強用のマシンなので、常時起動しておくことは少ないと思いますが、これで安心です。

ちなみに。

ラズパイZeroの方ですが、

ちょっと温度高め?

触っても熱くないですが。

(ラズパイ4は明らかに手で触れないくらい熱かった。)

うーん、今走らせてるサービス処理、もう少し軽くするか。

こういった温度をWindows側でモニタリングするツールを作ってもいいね。

老眼が進行していって大変です。

ちょっと前までパソコン作業用のメガネを装着していると、

非常に目が疲れる、という事に気がついたのです。

目が疲れすぎて、少しディスプレイを眺めているだけで耳鳴りがする。

なんか、老眼って、40過ぎるとどんどん進行していくんで、その都度メガネを調整しなくちゃいけないらしいよ。

めんどくさい。

めんどくさいけど、このままじゃ何も出来ないので、仕方なく、前回老眼の診察をして貰った眼科に行って、もう少し度の弱いメガネを処方して貰いました。

そして、その処方箋を持って、札幌アピア地下一階のZoffでメガネを作成。

Zoffって、比較的早い時間(今回は30分で出来上がった)し、値段も安い(今回は5500円)ので、今後も早いサイクルでメガネを買い換える事を考えると、こっちの方がお金がかからないのかな、と思いました。

遠近両用メガネを作ったって、便利そうだけど、度が合わなくなったらまた作り直さなくちゃいけないんでしょ?

しらんけど。

メガネを付け替える必要がなくなるってだけで、度が変わったらレンズも変えなきゃいけないはず。

老眼の進行が止まってくれれば良いんだけど、実際問題どうなるか分からないし。

で、メガネ作りました。

調子は良いです。😄

ディスプレイも見やすくなったし、なにより耳鳴りもなくなりました。

そして、気がついたことがもう一つありまして、

裸眼の視力が0.08→0.3に上がった。👍

老眼になると、視力が回復するのって本当なんですね。

0.3では何も見えないがな!

正直なこと言うと、頻繁にメガネを付け替えなくちゃいけないので、めんどくさいです!

【ダイエット支援】【食事管理】データ編集ダイアログ処理を作成する。

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

データ編集処理を作成していきます。

やり方は、体重管理機能のものと同じです。

EatingEditDialogComponent.vue

<template>
    <div>
        <div id="overlay" v-show="show">
            <div id="content">
                <p v-if="error_flg == true" class="error">
                    <ui>
                        <li v-for="error in errors">{{ error }}</li>
                    </ui>
                </p>
                <table class="edit">
                    <tbody>
                        <tr>
                            <td>日付</td>
                            <td>
                                <input type="date" v-model="contents.date" v-if="datehold" readonly>
                                <input type="date" v-model="contents.date" v-else>
                            </td>
                        </tr>
                        <tr>
                            <td>品名</td>
                            <td><input type="text" v-model="contents.item" /></td>
                        </tr>
                        <tr>
                            <td>時間帯</td>
                            <td>
                                <select name="timezone" v-model="contents.timezone">
                                    <option value="1" selected>朝</option>
                                    <option value="2">昼</option>
                                    <option value="3">夜</option>
                                    <option value="4">間食</option>
                                </select>
                            </td>
                        </tr>
                        <tr>
                            <td>タンパク質</td>
                            <td><input type="number" v-model="contents.protein" /></td>
                        </tr>
                        <tr>
                            <td>脂質</td>
                            <td><input type="number" v-model="contents.liqid" /></td>
                        </tr>
                        <tr>
                            <td>炭水化物</td>
                            <td><input type="number" v-model="contents.carbo" /></td>
                        </tr>
                        <tr>
                            <td>カロリー</td>
                            <td><input type="number" v-model="contents.calorie" /></td>
                        </tr>
                    </tbody>
                </table>
                <p id="command">
                    <button @click="clickEdit">編集</button>
                    <button @click="closeModal">閉じる</button>
                </p>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    props: ['show', 'date', 'datehold'],
    data() {
        return {
            errors: [],
            error_flg: [],
            param: {},
            contents: {},
        };
    },
    methods: {
        dataSet: function(data) {
            this.contents = data;
        },
        clickEdit: function() {
            var self = this;
            this.param.contents = this.contents;
            axios.post('/api/eating/update', this.param).then(function(response){
                self.clear();
                self.closeModal();
                self.$emit('update');
            }).catch(function(error){
                self.error_flg = true;
                self.errors = error.response.data.errors;
            });
        },
        closeModal: function() {
            this.$parent.showEditDialogContent = false;
        },
        clear: function() {
            this.contents.date = this.date;
            this.contents.item = "";
            this.contents.timezone = 1;
            this.contents.protein = "";
            this.contents.liqid = "";
            this.contents.carbo = "";
            this.contents.calorie = "";
            this.error_flg = false;
            this.errors = [];
        }
    }
}
</script>
EatingDetailComponent.vue

        <eating-edit-dialog-component ref="editDialog" :show="showEditDialogContent" :date="date" :datehold=true @update="invokeUpdateList"></eating-edit-dialog-component>

        onClickEdit: function(timezone, id) {
            var editData = {};
            this.datalists[timezone].forEach(element => {
                if(element.id == id){
                    editData.id = id;
                    editData.date = this.date;
                    editData.item = element.item;
                    editData.timezone = timezone + 1;
                    editData.protein = element.protein;
                    editData.liqid = element.liqid;
                    editData.carbo = element.carbo;
                    editData.calorie = element.calorie;
                    return true;
                }
            });
            this.$refs.editDialog.dataSet(editData);
            this.showEditDialogContent = true;
        },

Editボタンをクリックすると、detail側でEditダイアログに表示するパラメータを作成し、Editダイアログに渡します。

refパラメータを使用することで、親から子のモジュールの関数を呼び出すことができるので、これを利用してパラメータ一式を子モジュールに渡します。

編集ダイアログで編集をクリックすると、APIを呼び出してデータの更新を行います。

ApiController.php

    /**
     * データを一件取得する
     */
    public function update(Request $request)
    {
        $paramNames = $this->eatingManagement->getParam();

        $param = [];
        foreach($paramNames as $name) {
            $param[$name] = $request->contents[$name];
        }

        $this->eatingManagement->update($param, Auth::user(),  $request->contents['id'], $request->contents['timezone']);
        
        return response()->json();
    }
EatingManagementRepository.php

    /**
     * データを一件取得する
     */
    public function update($param, $user, $id, $timezone)
    {
        $model = $user->EatingManagements()->where('id', $id)->first();
        foreach($this->paramNames as $name)
        {
            $model->$name = $param[$name];
        }
        $model->save();
        $oldtime = $model->timezones()->first();
        $newtime = Timezone::where('id', $timezone)->first();

        $this->detachToTimezone($model, $oldtime);
        $this->attachToTimezone($model, $newtime);
    }

データを更新するときは、IDからデータベースのデータを取得し、これのデータを上書きすることで更新できます。

ただ、時間帯の更新というのもありえるので、timezonesテーブルとのリンクを再構築しなければなりません。

いったん、リレーションからtimezonesとデタッチし、新しいtimezonesとアタッチします。

これが終わったら、入力と同様にダイアログを非表示にし、detail画面を更新します。

ちょっと表示に手間取ったけど、できました。

RustがC言語に取って代わる存在かもしれないという話。

最近になってRust言語を勉強しています。

なぜRust言語なのか。

C言語って、コンパイルすると、機械語のファイルになります。

最近のトレンドでは、JavaやC#などの中間言語(仮想マシンが中間言語ファイルを翻訳し実行する)や、Pythonなどのスクリプト言語(プログラムを1行ずつ読み取って実行する)がありますが、

Rustはコンパイルすると、中間言語を必要としない機械語のファイルになります。

しかも後発の言語なので、C言語にない機能とかも搭載されているんです。

例えば変数を効率よく使用できる

例えば、

変数初期化を強制している点(不確定変数を許容しない)、

Boolean型が存在する、

配列の不正なIndex参照を防ぐ、などなど。

C言語のありがちな不具合を未然に防いでくれると言う点でかなりメリットがあります。

しかも、実行速度もC言語にかなり近づいているんだとか。

C言語が一番最適化されていると思われていたのですが。

で、さらに注目されていることがあって、

LinuxカーネルをRustで開発できないか、というのを検討しているみたいです。

https://japan.zdnet.com/article/35157012/

カーネルって、PCを動かすのに必要なコアのプログラムですよ。

Linuxカーネルなので当然Androidにも搭載される訳ですので。

LinuxカーネルでRustが採用されたらプログラミング言語の勢力図が変わるかもしれませんね。

【ANDROID】【実質北海道一周】距離をファイルに保存する。

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/AroundHokkaido

今回はGPSの情報から取得した移動距離合計をファイルに保存する処理を作成していきます。

クラスを一つ作成し、北海道一周関連の処理はこのクラスの中で処理していきたいと思います。

package com.takilab.aroundhokkaido

import java.io.File

class AroundHokkaido {
    private val filename: String = "distance.txt"
    private val citylist: CityList = CityList()
    private var totalDistance: Double = 0.0
    private val activity: MainActivity = SingletonActivity.GetActivity()

    fun getDistance(): Double{
        val file = File(activity.filesDir, filename)
        if(file.exists()){
            totalDistance = file.readText().toDouble()
        }
        return totalDistance
    }

    fun updateDistance(distance: Double): Double {
        val file = File(activity.filesDir, filename)
        if(file.exists()){
            totalDistance = file.readText().toDouble()
        }
        totalDistance += distance
        file.writeText("%.3f".format(totalDistance))
        return totalDistance
    }
}

まず、Android内でファイルアクセスするためには、MainActivityが必要です。

exists()でファイルの存在の有無を確認し、存在していれば、ファイルに保存済みのデータを読み込みます。

ファイルはテキストで保存されているので、Double型に変換して取得します。

保存するときは、桁数を指定しないと、指数表記でテキスト保存されてDouble型に変換出来ないという問題があるので、桁数を絞っています。

これをMainActivityでUIに表示させます。

    private lateinit var aroundHokkaido: AroundHokkaido

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        SingletonActivity.SetActivity(this);

        aroundHokkaido = AroundHokkaido()
        val distance: Double = aroundHokkaido.getDistance()
        distanceText.text = "%.3f".format(distance)

        requestPermission()

~中略~

                            override fun onResponse(call: Call, response: Response) {
                                var str = response!!.body!!.string()
                                val jsonObject = JSONObject(str)
                                val jsonArray = jsonObject.getJSONArray("Feature")
                                for (i in 0 until jsonArray.length()) {
                                    val jsonData = jsonArray.getJSONObject(i)
                                    val geometry = jsonData.getJSONObject("Geometry")
                                    val distance = geometry.getDouble("Distance")
                                    val totalDistance: Double = aroundHokkaido.updateDistance(distance)
                                    val mainHandler : Handler = Handler(Looper.getMainLooper())
                                    mainHandler.post(Runnable {
                                        distanceText.text = "%.3f".format(totalDistance)
                                    })
                                }
                            }

まず、AroundHokkaido()の中でMainActivityを使用していますので、AroundHokkaidoの初期化はSingletonActivity.SetActivity(this);の後に行わなければなりません。

で、AroundHokkaidoから現在の移動距離を取得しUIに表示します。

これがアプリ立ち上げたときの初期表示値です。

WebAPIのレスポンスを取得したときの処理も同様にします。

この炎天下の中外を走るって頭おかしいと思う。

久しぶりに運動した。

ここ最近、札幌も暑すぎて野外での運動は危険と言われてきたので。

どうせ運動するなら、空調が効いた涼しい部屋で運動したいものです。

そこで、近場のジムを調べてみました。

札幌ドームのトレーニングルームです。

一般の人でも利用できる施設で、大人500円ですが、障害者手帳があれば無料で利用できます。

今日、実際に行ってみたのですが、

トレーニングマシンの数は他の公共体育館とはダンチです。

ランニングマシンも台数が多いし、

筋トレマシンも種類が多いし、

何よりも、人が少ない。

これは、うまく利用するしかないっしょ。

夏場も頑張ってトレーニング続けるっすよ。

パーツ交換したモバイルPCを試してみた

札幌狸小路にある梅沢無線、お盆休みだってよ。

さて、こちらでパーツ交換したモバイルPCですが、

外で使ってみました。

遅っそ!

立ち上げは思った以上に早かったけど、ログインしてからが遅い。

原因はおそらくログイン直後にWindows Updateが走っているため。

Windows UpdateでCPU使用率100%行っちゃう。

まぁ、これはUpdateの確認で走っている処理なので、Updateが無ければCPU使用率元に戻るのだが、

あ、ちなみに、ネットワークはスマホの回線(LTE)をテザリングしています。

Windows Updateが終わって、CPU使用率が落ち着いても、動きがもっさりしている。

一番の要因は、やっぱりブラウザなのだろう。

最近のブラウザは色々と高性能だからね。

それなりにCPUパワーを使用します。

いまブログの記事を書いているのだが、

それでも文字入力だけでCPU使用率かなり持ってかれます。

だから、ブログ記事の更新にはあまり向かないかもしれない。

他アプリで文字入力を試してみる。

VSCodeを使ってみたところ、CPU使用率はある程度抑えられた。

ブラウザよりは。

おそらく、もっさりの原因はCPUパワーが足りないのだろう。

そりゃそうだ。第4世代のCeleronだもの。

まぁ、テキスト編集ぐらいなら十分耐えられるレベル。

ギリギリブログ記事編集かな。

写真とか、画像を含めると、ネットワーク関連がかなり足を引っ張りかも。

まぁ、せっかくパーツ交換でパワーアップしたモバイルPCなので、存分に使い倒して見せまする。

最近困らせていた耳鳴りの原因

今日の北海道は死ぬほど暑いね。

ここ最近オイラを困らせていた耳鳴りの原因ですが、

おそらく、老眼が進行したのではないかと。

40歳はバリバリの現役世代だと思いますが、

この頃から色々と体に衰えが出てきます。

更年期なので。

老眼もこの頃から現れ始めます。

確か、前回は40の時にパソコン作業用に眼科で度数を調整して貰ったメガネがあるのですが、

これが、どうも今の自分に合わなくなってきたような気がして。

実際、メガネを使用していない方が症状は軽いです。

姿勢はめっちゃ悪いですが。

多分、ディスプレイから20cmぐらいまで顔を近づけないと、ディスプレイの文字が見えない。

何にせよ、このままだといろいろ今の活動に支障が出ること間違い無しなので、

(仕事復帰することも含めて)

再び眼科に行って度数を調整して貰おうと思います。

で、街に出てきたんですが、

健康保険証の期限が切れてました。

(そういえば、新しい保険証が家に届いていたような)

今日は暑いので、飲んで帰ります。

クーポン貰ったので。

あ、老眼は年々悪くなっていくので、定期的に診察を受けた方が良いらしい。

当然、早いサイクルでメガネを変えることになります。

なので、高いメガネは避けた方がよさそう。

あと、定期的な診察は緑内障の早期発見にも繋がります。

自分、ぼっちですが何か?