Kindle6と7 Jailbreakしてラズパイから送信した画像を表示させる

Raspberry Pi(ラズパイ)

ちょっといまさら感がありますが、E-paperが大好きな自分としてはいつかやってみたいネタのKindleをJailbreakして好きな画像を表示させることをやってみました。

JailbreakしてSSH接続で温湿度などを表示させた画像を生成してKindleに表示させる方法を見つけたので試してみました。

この記事は複数のページに別れています
作業内容はこのような感じで主にラズパイ4からPythonスクリプトで操作していきます。

イチから自分で完成させることができないので、こちらのすっごく頭の良い方(電気スマートメーターの時もお世話になりました。スマートメーターをハックするUSBドングルのWi-SUNが壊れた?みたいなので今回は使いません。)のページを真似していきます。

Kindle のディスプレイ応用例
Kindle Paperwhite を Raspberry Pi で収集したセンシングデータの表示パネルとして使う方法を紹介します.

以下、作業したメモになります。

  1. Kindle Jailbreak 調査
    1. ファームウェアバージョン Kindle 5.16.4は今のところJailbreak できない
    2. かなり古いKindle 第七世代 4GB WP63GWはVer5.7.4でJailbreak可♪
    3. Kindleのバージョン調べ
    4. Kindle Jailbreak 参考
  2. Kindle端末のリセット
  3. Kindle 初期ファームウェア
    1. ダウンロード
    2. Kindleにコピー
    3. Kindleをアップデート
  4. Kindle Jailbreak
    1. main-htmlviewer.tar.gz Download
    2. Jailbreak 入力
    3. Hotfix Download
    4. Hotfix 適用
  5. Kindle アップデート
    1. 手動アップデート
    2. 自動アップデートを防ぐ
  6. Kindle Jailbreak ツールインストール
    1. ツールダウンロード
    2. 3つのツールインストール
      1. KUAL-v2.7.31-g702078b-20231104.tar.xzのファイルは2つコピー
        1. KUAL-v2.7.31-g702078b-20231104
        2. KUAL-v2.7.xx Kindle第7世代 KT2 V5.12.2.2 の場合
      2. kual-helper-0.5.N-r18980
      3. kual-mrinstaller-1.7.N-r19303 MR Package Installer
    3. KUALを起動
  7. ツールインストール
    1. ダウンロード
    2. Kindle mrpackagesにコピー
      1. usbnet
    3. インストール
      1. Kterm
      2. スクリーンセーバー
  8. KindleをWifiでSSH接続できるようにする
    1. USBnet
    2. SSH鍵の生成 ラズパイ4での操作
      1. rootパスワード設定
      2. SSH鍵生成
      3. SSH鍵生成されたか確認
    3. authorized_keysをKindleのusbnet/etcにコピー
    4. 検索で~usbNetwork入力
    5. コマンド ;un
    6. ラズパイ4を新規インストールしたら繋がらなくなった
      1. 間違ってインストールしたと思ったがしてない 未解決
      2. SSH鍵がECDSA→ED25519に変わってる
    7. 電源を切ったら鍵を削除
    8. /mnt/us
  9. Kindleの検索まどからの操作 Helper
    1. ;711
    2. ;411
  10. Influxからデータを取得して表示
    1. InfluxDBから4つの温湿度を取得するPythonスクリプト(テスト)
    2. PIL インストール
    3. Raspberry Piに日本語フォントインストール
      1. フォントキャッシュの更新
      2. インストールされているフォントの確認
  11. matplotlibは面倒なのでやめた PNG画像保存テスト
    1. InfluxDBにアクセスしないでダミーデータでPNG画像生成してみる。
    2. InfluxDBからデータを取ってきてmatplotlibを使ったPNG画像生成
  12. PillowでPNG画像生成スクリプト
    1. Pillowインストール
    2. PNG画像生成スクリプト
  13. KindleにPNG画像を定期的に送る
    1. paramiko インストール
    2. フレームワークとスリープ停止
    3. KindleへPNG画像送信スクリプト 無限ループ版
    4. KindleへPNG画像送信スクリプト cronで定期的に実行版
  14. 植物を育ててると温湿度が気になる

Kindle Jailbreak 調査

まずはKindleでJailbreak できるのか調査。

ファームウェアバージョン Kindle 5.16.4は今のところJailbreak できない

以前、自分が買ったKindle Paperwhite第10世代はバージョンが5.16.4に自動的にアップデートされていたのでコレ↓だとJailbreak不可(Wifiを切断しておいてJailbreakできる機会まで待ちます。)

G000PP, G8S0PPKindle PaperWhite 4 (2018) WiFi, 8GBPW4

かなり古いKindle 第七世代 4GB WP63GWはVer5.7.4でJailbreak可♪

Kindle 第七世代 4GB WP63GWを2.5千円ほどでオークションで買った。

こちらはファームウェアのバージョンがKindle5.7.4だったのでJailbreak可能でした!

Kindleのバージョン調べ

MobileRead Wiki - Kindle Serial Numbers

を見ると、Kindle7世代はシリアル番号が90C6から始まっているのでKT2のよう。

B0C6, 90C6Kindle Basic (2014)KT2, BASIC[Support added in KindleTool 1.6.3]

Kindle Jailbreak 参考

ここにJailbreakの方法全て書いてある。

MobileRead Wiki - 5 x Jailbreak

日本語ではここ↓を参考にJailbreakしていく。

Kindle:jailbreak方法(5.7.x - 5.8.1.1)その1 準備編 - ドイツ語の本読んでみ・・
Oasis、新無印2016にも対応、PW3(2015)のダウングレード問題にも対...

Kindle端末のリセット

ホーム右上の点々 > 設定に行き、サイド右上の点々を再びタップすると「端末のリセット」「端末情報」を選べる。

端末情報はKindle5.7.4・シリアル番号の先頭は90C6でKT2と言われるもの。

端末のリセットを実行する。

ファームウェアバージョン5.8.5.0.2でも以下のやり方で5.6.0にダウングレードできました!

バッテリーがヘタって動かないのでMicroUSBを取ると電源が落ちる。それとMicroUSBの接触が悪い。

Kindle 初期ファームウェア

ダウンロード

MobileRead Wiki - 5 x Jailbreak

KT2を選ぶ。右クリックで新しいタブで、Downloadボタンを押す。

KT2 factory_KT2_5.6.0_initial MD5: d85a86f5c75b4b9d43648f3b6afd2e84

update_KT2_5.6.0_initial.binがDLされる。

Kindleにコピー

update_KT2_5.6.0_initial.binをKindleをPCで開いたフォルダにコピーする。

買ったKindleはバッテリーがヘタって動かないので、MicroUSBを抜かずに右クリックの取り出しで対応する。

Kindleをアップデート

設定 > 右上点々 > 設定 > 端末オプション > Kindleをアップデートでアップデートする。15分弱くらいかかった。

アップデート終わって自動再起動してPCから取り出し、端末情報を見ると5.6.0になってる!

Kindle Jailbreak

ファームウェアを5.6.0にしたのでJailbreak していきます。

main-htmlviewer.tar.gz Download

Kindle Factory Image Generic Jailbreak - MobileRead Forums
Kindle Factory Image Generic Jailbreak Kindle Developer's Corner

以下の部分でDL

main-htmlviewer.tar.gz をKindleをPCで開いたフォルダにコピーする。

Jailbreak 入力

 ;installHtml

リターンする。

自動再起動して以下のように表示される。

Hotfix Download

このページに必要な物が置いてあるみたい。

https://www.mobileread.com/forums/showthread.php?t=225030

JailBreak-1.16.N-FW-5.x-hotfix.zipをDLした。

解凍してUpdate_jailbreak_hotfix_1.16.N_install.binをKindleをPCで開いたフォルダにコピーする。

Hotfix 適用

コピーし終わったらもう一度アップデートする。

設定 > 右上点々 > Kindleをアップデートでアップデートする。

Kindle アップデート

手動アップデート

好きなKindleバージョンをDLしてアップデートすれば良いらしい。

MobileRead Wiki - 5 x Jailbreak

このページのKT2のファイルをDL、5.7.4だったのでコレにする。

あとは同様に設定 > 右上点々 > Kindleをアップデートでアップデートする。

自動アップデートを防ぐ

update.bin.tmp.partialフォルダを作ってKindleトップにコピーしておけばAmazonが勝手にアップデートしないみたい。

Kindle Jailbreak ツールインストール

ツールダウンロード

https://www.mobileread.com/forums/showthread.php?t=225030

3つDLした。

3つのツールインストール

それぞれ解凍する。

KUAL-v2.7.31-g702078b-20231104.tar.xzのファイルは2つコピー

KUAL-v2.7.31-g702078b-20231104

KUAL-v2.7.31-g702078b-20231104.tar.xzを解凍して中のKUAL-KDK-2.0.azw2をKindleのdocumentsフォルダにコピー

↓Kindleのdocuments内。

KUAL-v2.7.xx Kindle第7世代 KT2 V5.12.2.2 の場合

7世代のKindle KT2 V5.12.2.2の場合はKUALのファイルが違ったのでご注意ください。3回Jailbreakしてやっと分かった。

Update_KUALBooklet_v2.7.32_install.binをKindleのmrpackagesフォルダにコピーする。

mrpackagesフォルダは下のkual-mrinstaller-1.7.N-r19303の操作でコピーされる。

多分ですがKindle7世代~新型でV5.12.2.2以上の場合は、上の「KUAL-KDK-2.0.azw2」をdocuments内にコピーしてもKUALが表示されない場合は試してみてください。

Jailbreakできてない?とあせったがKUALのインストール方法が違っただけだった。

kual-helper-0.5.N-r18980

解凍した中のextensionsごとKindleのトップにコピーする。

kual-mrinstaller-1.7.N-r19303 MR Package Installer

2つのフォルダをKindleのトップにコピーする。

Kindleのフォルダは以下のようになった。

extensionsの中身↓

KUALを起動

マイライブラリにあるKindle LAUNCHERでKUALを起動してツールをインストールする。

Kindle Launcher(KUAL)を起動して各種ツールを起動する。

ツールインストール

ダウンロード

https://www.mobileread.com/forums/showthread.php?t=225030

スクリーンセーバーは使わないけどインストールしてみる。↑USBNetwork HackがWifiでSSH接続を可能にするツール。

Kindle mrpackagesにコピー

(以下間違えてPackages targeting the Kindle 2/DX/DXG/3/4:用をダウンロードしてしまったが?なぜか動いた。

DLして解凍後にbinファイルをKindleのmrpackeagesフォルダにコピーする。

↑コレは、コピーしてもダメだった。

ツールは mrpackagesにコピーでOKみたい。だがUpdate_**ファイルが複数あるのでどれを入れたらいいのか迷う。

Kindle第7世代 KT2 V5.12.2.2はUpdate_usbnet_0.22.N_install_touch_pw.binはエラーでインストールできない。Update_usbnet_0.22.N_install_pw2_and_up.binを入れたらインストールできた。

usbnet

kindle-usbnet-0.22.N-r19297.tar.xzを解凍して中の「Update_usbnet_0.22.N_install_pw2_and_up.bin」をコピーした。

インストール

KUAL(kindle Launcher) > Helper+ ▽ > Install MR Packagesで mrpackeagesに入っているファイルのインストール作業開始。

以下を入れてインストールしたらUSBnetが使えるようになった。SSHできるかな?

USBnetでSSHができる。

Kterm

特に必要ないけどついでにインストールしてみる。

Kterm – terminal emulator for Kindle Touch and Paperwhite
kterm – terminal emulator for Kindle Touch
https://github.com/bfabiszewski/kterm/releases/download/v2.6/kterm-kindle-2.6.zip

ktermフォルダをKUALのextensionsにコピーして、KindleでKUAL > Helper > Install MR Packagesでインストール

スクリーンセーバー

kindle-linkss-0.25.N-r18981のUpdate_linkss_0.25.N_install_touch_pw.binと、Update_linkss_0.25.N_install_pw2_and_up.binをインストールしたら動いた。

Kindle: スクリーンセーバー・カスタマイズ(jailbreak) - ドイツ語の本読んでみ・・
Kindleのスクリーンセーバーを変更する方法。◎条件・jailbreak...

こちら↑の方が詳しく説明されている。

この画像が表示されたらスクリーンセーバーハックは完了。

設定を変更したら、Screen Savers > Restart the framework nowをすると再起動する。

うまく動くけど今回はスクリーンセーバーは使わないので停止しておく。

KindleをWifiでSSH接続できるようにする

ここからが、各部屋の温湿度を表示させる設定の前段階。

USBnet

USBnetでWifiからSSH接続するようにできる。

WifiでSSHを接続できるように「Allow SSH over WiFi」を設定しておく。

SSH over Wifi」と「Enable verbose mode」もオンにしておく。SSH at boot, SSHD: Use OpenSSHもオンにする。

USBnetの初期化は、タップしても解除されないので右側の▶を押して次ページの「Restore default config」でUSBnet初期化する。

ここまできたらKindleのWifiを接続する。

SSH鍵の生成 ラズパイ4での操作

Raspi4Bにrootパスワード設定されていないので設定する。

rootパスワード設定

初期状態のラズパイでrootのパスワードが作成されていないので作っておく。

$ sudo passwd root
New password:
Retype new password:
passwd: password updated successfully

suでrootになれる。

su
Password:
root@Raspi4B:/home/go#

SSH鍵生成

Raspi4Bでrootで作業、全てリターンを押すと /root/.sshに id_rsaと id_rsa.pubが生成される。

root@Raspi4B:~# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa
Your public key has been saved in /root/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:b8F0eQnuNplWyFmg73I87uITpm4kzO76ynfyV1XjWWU root@Raspi4B
The key's randomart image is:
+---[RSA 3072]----+
|            o.. E|
|           + * +o|
|          o B =.+|
|         o + =.o |
|     o  S o O.   |
|      + ..o*..   |
|     . o o+o=    |
|   .  + +.++ .   |
|    +*o*oo.+o    |
+----[SHA256]-----+

パスワードはなにも入力しないでリターンを押す。(全てリターンだけ押す。)

SSH鍵生成されたか確認

以下が生成されている。

ls /root/.ssh
id_rsa  id_rsa.pub

id_rsa.pubをKindleにauthorized_keysとしてコピーする。↓まずはローカルにコピーしておく。

cp /root/.ssh/id_rsa.pub /home/go/authorized_keys

authorized_keysをKindleのusbnet/etcにコピー

生成した鍵をKindleの/usbnet/etcにauthorized_keysをコピー↓

検索で~usbNetwork入力

;debugOn
~usbNetwork
;debugOff

コマンド ;un

最後に;unをホームの検索窓に入力してリターンを押した後にRaspi4Bでroot SSHアクセスするとうまく接続できた!

「SSH over Wifi」と「Enable verbose mode」もオンにしておかないとダメ。

~# ssh 192.168.31.40
ssh: connect to host 192.168.31.40 port 22: Connection refused
root@Raspi4B:~# ssh 192.168.31.40
The authenticity of host '192.168.31.40 (192.168.31.40)' can't be established.
ECDSA key fingerprint is SHA256:65X9gdR9f71y6Fs9qSNZFCez8mJ8RAQ4Lhq+1c46Ttw.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.31.40' (ECDSA) to the list of known hosts.


Welcome to Kindle!

#################################################
#  N O T I C E  *  N O T I C E  *  N O T I C E  #
#################################################
Rootfs is mounted read-only. Invoke mntroot rw to
switch back to a writable rootfs.
#################################################
[root@kindle root]# ls
[root@kindle root]# pwd
/var/tmp/root
[root@kindle root]#

WindowsPCのPowerShellだとパスワード聞かれるので接続できない?みたい。

PS C:\Users\GO> ssh 192.168.31.40
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
SHA256:1XJQmm3sGHrRI7j7RyM8lzmEbBvvg0O+ZpWWwDEfmO8.
Please contact your system administrator.
Add correct host key in C:\\Users\\GO/.ssh/known_hosts to get rid of this message.
Offending ED25519 key in C:\\Users\\GO/.ssh/known_hosts:11
Host key for 192.168.31.40 has changed and you have requested strict checking.
Host key verification failed.
PS C:\Users\GO> ssh 192.168.31.40
The authenticity of host '192.168.31.40 (192.168.31.40)' can't be established.
ED25519 key fingerprint is SHA256:1XJQmm3sGHrRI7j7RyM8lzmEbBvvg0O+ZpWWwDEfmO8.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.31.40' (ED25519) to the list of known hosts.
go@192.168.31.40's password:
Permission denied, please try again.
go@192.168.31.40's password:
Permission denied, please try again.
go@192.168.31.40's password:
go@192.168.31.40: Permission denied (publickey,password,keyboard-interactive).

ラズパイ4を新規インストールしたら繋がらなくなった

なぜかパスワードを聞くようになって接続できない。

root@Raspi4B:~# sudo rm /root/.ssh/known_hosts
root@Raspi4B:~# ssh 192.168.31.40
The authenticity of host '192.168.31.40 (192.168.31.40)' can't be established
ED25519 key fingerprint is SHA256:1XJQmm3sGHrRI7j7RyM8lzmEbBvvg0O+ZpWWwDEfmO8.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.31.40' (ED25519) to the list of known hosts.
Enter passphrase for key '/root/.ssh/id_rsa':
root@192.168.31.40's password:
Permission denied, please try again.
root@192.168.31.40's password:
Permission denied, please try again.
root@192.168.31.40's password:
root@192.168.31.40: Permission denied (publickey,password,keyboard-interactive).

間違ってインストールしたと思ったがしてない 未解決

間違えて、kindle-usbnetwork-0.57.N-r18979のUSBnetを入れてしまったからかもしれない。Update_usbnetwork_0.57.N_uninstall.binをHelper+ ▽ > Install MR Packagesに入れてアンインストール。

以下の2つをインストールした。Update_usbnet_0.22.N_install_touch_pw.bin単体でインストールしようとしたらインストールできなかったので、多分Update_usbnet_0.22.N_install_pw2_and_up.binがインストールされたと思う。

SSH鍵がECDSA→ED25519に変わってる

(2つ目のKindle第6世代 PW2も同様になったが、スクリプトはなぜか正常に動くので不思議に思っていたが、以下のようにPasswordを追加すれば正常に動いた。

mykey = paramiko.RSAKey(filename=private_key_path)
 ↓
mykey = paramiko.RSAKey(filename=private_key_path, password='pass')

前回SSH鍵作る時にパスワード入れてなかった(かもしれない)からうまくいったのかもしれない。

電源を切ったら鍵を削除

バッテリーがヘタっていてMicroUSB抜くと電源切れるので再起動する。とKeyが変わったと言われる。

root@Raspi4B:~# ssh 192.168.31.40
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:EnyqIeMglLeBP7sOKfWtHidGBlYL5I6wMy8/6++nbpk.
Please contact your system administrator.
Add correct host key in /root/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /root/.ssh/known_hosts:1
  remove with:
  ssh-keygen -f "/root/.ssh/known_hosts" -R "192.168.31.40"
ECDSA host key for 192.168.31.40 has changed and you have requested strict checking.
Host key verification failed.

ラズパイ4のknown_hostsファイルが邪魔をしているので、毎回MicroUSBプラグ抜いて再起動するたび(バッテリーが効かない場合のみ) known_hostsを削除↓して、新規でSSH接続したときに「yes」を入力して接続。

root@Raspi4B:~# rm .ssh/known_hosts

/mnt/us

SSHでログインできたら、/mnt/usがトップディレクトリ。PCにKindleをUSB接続した時も同じ/mnt/usがトップのフォルダ。

ここ/mnt/usに画像を置いて表示させる。

Kindleの検索まどからの操作 Helper

今回の作業には関係ないけど、Helperコマンドいくつか。

;711

Kindleのホームの検索に「;711」リターンで以下が表示される。

;411

バージョンなどが表示される。

Influxからデータを取得して表示

ここからはラズパイ4からJetson nano(温湿度などのセンシングデータをInfluxDBに保存してある)にアクセスして温湿度データを取得後にPNG画像に出力する作業をしていきます。

InfluxDBから4つの温湿度を取得するPythonスクリプト(テスト)

とりあえずInfluxDBのデータを取得してPuttyで表示するところまでやってみました。

以下をラズパイ4に保存する。(192.168.31.53はInfluxDBが稼働しているJetson nanoのIPアドレス)

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#influxDB
from influxdb import InfluxDBClient
client = InfluxDBClient(host='192.168.31.53', port=8086, username='root', password='Pass', database='sensor')
measurement = 'air5'
hosts = ['WxBeacon2', 'Raspi3B', 'raspi3B+', 'M5Stack-Core2']
names = ['室外', '部屋', '寝室', '植物']

for host, name in zip(hosts, names):
    # ホスト名にスペースが含まれている場合はダブルクォートで囲む
    host_in_query = f'"{host}"' if ' ' in host else f"'{host}'"
    query = f'SELECT "temp", "humi" FROM "air5" WHERE host = {host_in_query} ORDER BY time DESC LIMIT 1'
    result = client.query(query)
    points = list(result.get_points())
    if points:
        for point in points:
            print(f"{name}: Time: {point['time']}, 温度: {point['temp']}, 湿度: {point['humi']}")
    else:
        print(f"No data for host: {host}")

実行すると以下のようにInfluxDBに保存されているデータが表示される。WxBeacon2はこの時ボタン電池切れで取得できず2日前のデータ・・・

室外: Time: 2023-12-28T13:23:04.126508Z, 温度: 10.55, 湿度: 75.74
部屋: Time: 2023-12-29T23:23:09.945244Z, 温度: 16.81, 湿度: 49.01
寝室: Time: 2023-12-30T01:36:02.667948Z, 温度: 16.32, 湿度: 53.44
植物: Time: 2023-12-30T01:35:54.656944Z, 温度: 16.52, 湿度: 51.4

PIL インストール

PINGイメージとして保存するのにPILが必要、最終的にラズパイのrootで使うのでrootになってからインストールしたほうが良さそう。

su
pip install matplotlib pillow

Raspberry Piに日本語フォントインストール

NotoとIPAexの日本語フォントインストール

sudo apt install fonts-noto-cjk
sudo apt install fonts-ipaexfont

フォントはBoldが好みで3つ試したが3つの中ではNotoSansCJK-Bold.ttcが見やすくて一番よさそう。

font_path = '/usr/share/fonts/opentype/ipaexfont-gothic/ipaexg.ttf'
font_path = '/usr/share/fonts/opentype/noto/NotoSerifCJK-Bold.ttc'
font_path = '/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc'

フォントキャッシュの更新

インストールしたフォントをシステムに認識させる。

sudo fc-cache -fv

インストールされているフォントの確認

日本語が使えそうなフォントは以下(他の日本語フォントではないフォントは省略しています。)

$ fc-list
/usr/share/fonts/opentype/noto/NotoSerifCJK-Bold.ttc: Noto Serif CJK JP:style=Bold
//usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc: Noto Sans CJK JP:style=Regular
/usr/share/fonts/opentype/ipaexfont-gothic/ipaexg.ttf: IPAexGothic,IPAexゴシック:style=Regular
/usr/share/fonts/opentype/noto/NotoSerifCJK-Regular.ttc: Noto Serif CJK JP:style=Regular
/usr/share/fonts/opentype/ipaexfont-mincho/ipaexm.ttf: IPAexMincho,IPAex明朝:style=Regular
/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc: Noto Sans Mono CJK JP:style=Regular
/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc: Noto Sans CJK JP:style=Bold

matplotlibは面倒なのでやめた PNG画像保存テスト

取得した温湿度データをPNG画像に保存するときにmatplotlibを使うようになっていましたが、matplotlibはもともとグラフを書くライブラリです。スクリプト作りましたが↓この方法は向いてないのでやめました。

テスト的に書いてみるが、サイズを変更するとグチャグチャになって合わせるのが面倒です。

InfluxDBにアクセスしないでダミーデータでPNG画像生成してみる。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import datetime
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
from PIL import Image
# フォントパスを指定
font_path = '/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc'
font_prop = FontProperties(fname=font_path)

# クエリ結果のデータ(ダミーデータ)
data = {
    '室外': {'temp': 25.7,'Time': '2023-12-28T13:23:04.126508Z', 'humi': 49.5},
    '部屋': {'temp': 24.7,'Time': '2023-12-29T13:21:04.126508Z', 'humi': 55.5},
    '寝室': {'temp': 24.5,'Time': '2023-12-29T13:08:04.126508Z', 'humi': 53.5},
    '植物': {'temp': 25.6,'Time': '2023-12-30T13:16:04.126508Z', 'humi': 45.1}
}

fig, ax = plt.subplots(figsize=(10, len(data) * 4)) # matplotlib フィギュアと軸を作成

# データをプロット
for i, (place, values) in enumerate(data.items()):
    ax.text(-0.1, i / 4 + 0.3, place, fontsize=50, fontproperties=font_prop)
    ax.text(-0.1, i / 4 + 0.3  - 0.09, f'{values["temp"]}°C  {values["humi"]}%', fontsize=90, fontproperties=font_prop)
    time = datetime.datetime.strptime(values["Time"], '%Y-%m-%dT%H:%M:%S.%fZ')
    ax.text(0.5, i / 4 + 0.3  - 0.13, f'{time.strftime("%Y-%m-%d %H:%M:%S")}', fontsize=30, fontproperties=font_prop)

# 日付と更新日時を表示
now = datetime.datetime.now()
ax.text(1.05, -0.1, now.strftime('%H:%M:%S'), fontsize=26, fontproperties=font_prop, ha='right', transform=ax.transAxes)
ax.text(1.05, -0.06, now.strftime('%Y-%m-%d'), fontsize=26, fontproperties=font_prop, ha='right', transform=ax.transAxes)

ax.axis('off') # 軸を非表示にする
plt.savefig('temp.png', dpi=300) # フィギュアを保存

img = Image.open('temp.png') # 画像を開く
img_resized = img.resize((1072, 1448)) # 画像のサイズを変更
img_resized.save('temp2.png') # 画像を保存

ax.axis(‘off’)にすると以下のようにグラフの線が表示される。

上画像は上下左右に余白ありすぎますが、plt.subplotsのオプションtight_layout=Trueを追加すると画面めいいっぱい使ってくれます。↓

InfluxDBからデータを取ってきてmatplotlibを使ったPNG画像生成

うまくいくかに見えたが、Kindleで表示させてみると画像の一部しか表示されない・・・サイズ変更するとガタガタになるのでmatplotlib使うのやめた。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import datetime
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
from PIL import Image
# フォントパスを指定
font_path = '/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc'
font_prop = FontProperties(fname=font_path)

#influxDB
from influxdb import InfluxDBClient
client = InfluxDBClient(host='192.168.31.53', port=8086, username='root', password='Pass', database='sensor')
import pytz
utc = pytz.utc
jst = pytz.timezone('Asia/Tokyo')
from dateutil.parser import parse
measurement = 'air5'

hosts = ['WxBeacon2', 'Raspi3B', 'raspi3B+', 'ESP32-plant']
names = ['室外', '部屋', '寝室', 'Hot']

fig, axs = plt.subplots(len(hosts), 1, figsize=(15, 15), tight_layout=True) # matplotlib フィギュアと軸を作成
for i, (host, name) in enumerate(zip(hosts, names)):
    host_in_query = f'"{host}"' if ' ' in host else f"'{host}'"
    query = f'SELECT "temp", "humi" FROM "air5" WHERE host = {host_in_query} ORDER BY time DESC LIMIT 1'
    result = client.query(query)
    points = list(result.get_points())
    ax = axs[i]
    if points:
        for point in points:
            time_str = point['time']
            time = parse(time_str)
            time = time.astimezone(jst)
            print(f"{name}: Time: {time.strftime('%Y-%m-%d  %H:%M:%S')}, 温度: {point['temp']}, 湿度: {point['humi']}")
            #ax.axis('off') # 軸を非表示にする
            ax.text(-0.25, 0.9, names[i], fontsize=60, fontproperties=font_prop)
            ax.text(-0.1, 0.7, f'{point["temp"]}', fontsize=120, fontproperties=font_prop)
            ax.text(1, 0.2, f'{point["humi"]}', fontsize=50, fontproperties=font_prop)
            ax.text(0.75, 0.2, f'°C', fontsize=60, fontproperties=font_prop)
            ax.text(1, -0.16, f'{time.strftime("%Y-%m-%d  %H:%M:%S")}', fontsize=30, fontproperties=font_prop)

# 日付と更新日時を表示
now = datetime.datetime.now()
ax.text(0.8, 0, now.strftime('更新 %Y-%m-%d  %H:%M:%S'), fontsize=30, fontproperties=font_prop, ha='right', transform=ax.transAxes)

plt.savefig('kindle.png', dpi=300) # フィギュアを保存
img = Image.open('kindle.png') # 画像を開く
#img = img.resize((768, 1024)) # 画像のサイズを変更
img_8bit = img.convert('L') # 画像を8ビットに変換
img_8bit.save('kindlesize.png') # 画像を保存

figsize=(15, 15)あたりを変更すると良いのですが・・・そもそもがmatplotlibはグラフを生成するライブラリなので、文字を並べるのには向いてない。

↑上のスクリプトで一応はPNG画像を生成できます。

それと、Kindle 第七世代は300PPI、横600X縦792ピクセルっぽいので生成する画像サイズを間違えていた。

PillowでPNG画像生成スクリプト

matplotlibよりもPillowを使ったほうが良いみたいなのでスクリプト変更。

Pillowインストール

su
pip install pillow

ModuleNotFoundError: No module named ‘dateutil’が表示されたら以下をインストール

pip install python-dateutil

PNG画像生成スクリプト

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import datetime
from PIL import Image, ImageDraw, ImageFont
from influxdb import InfluxDBClient
import pytz
from dateutil.parser import parse

font_path = '/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc'
font100 = ImageFont.truetype(font_path, 100)
font80 = ImageFont.truetype(font_path, 80)
font60 = ImageFont.truetype(font_path, 60)
font20 = ImageFont.truetype(font_path, 20)

#influxDB
client = InfluxDBClient(host='192.168.31.53', port=8086, username='root', password='Pass', database='sensor')
#日本時間に時刻合わせ(InfluxDBClientがUTCに合わせちゃうので修正)
utc = pytz.utc
jst = pytz.timezone('Asia/Tokyo')
measurement = 'air5'

hosts = ['WxBeacon2', 'Raspi3B', 'raspi3B+', 'ESP32-plant']
names = ['室外', '部屋', '寝室', 'Hot']

img = Image.new('L', (600, 792), color = 255)
d = ImageDraw.Draw(img)
for i, (host, name) in enumerate(zip(hosts, names)):
    host_in_query = f'"{host}"' if ' ' in host else f"'{host}'"
    query = f'SELECT "temp", "humi" FROM "air5" WHERE host = {host_in_query} ORDER BY time DESC LIMIT 1'
    result = client.query(query)
    points = list(result.get_points())
    if points:
        for point in points:
            time_str = point['time']
            time = parse(time_str)
            time = time.astimezone(jst)
            print(f"{name}: Time: {time.strftime('%Y-%m-%d  %H:%M:%S')}, 温度: {point['temp']}, 湿度: {point['humi']}")
            d.text((3,180*i), f"{name}", fill=0, font=font60)
            d.text((10,45+180*i), f"{point['temp']}", fill=0, font=font100)
            d.text((275,140+180*i), f"°C", fill=0, font=font20)
            d.text((350,70+180*i), f"{point['humi']}", fill=0, font=font80)
            d.text((570,135+180*i), f"%", fill=0, font=font20)
            d.text((380,160+180*i), f"{time.strftime('%Y-%m-%d  %H:%M:%S')}", fill=0, font=font20)

now = datetime.datetime.now()
d.text((340,10), now.strftime('更新 %Y-%m-%d  %H:%M:%S'), fill=0, font=font20)
img.save('/home/go/script/kindle.png')

PNG画像の保存は/home/go/script/kindle.pngに保存しました。

Hotは植物用のホットカーペットの温度です。

生成したPNG画像kindlesize.pngは↑こんな感じになってうまくいった。(湿度の下にある日付時刻はそれぞれのセンサーがInfluxDBにデータを送った時刻)

一番下の更新はPNG画像を生成した時刻。

KindleにPNG画像を定期的に送る

ラズパイ4でPNG画像を生成できたので、最後にPNG画像をKindleに送る設定をしていきます。

paramiko インストール

paramikoはPythonでSSH接続してコマンド操作できるライブラリ。

ラズパイ4のrootで操作するのでrootになってからインストールする。

su
pip install paramiko

フレームワークとスリープ停止

Kindleを操作する必要がなくなるので、両方停止する。

ラズパイ4から以下のように操作。

ssh root@192.168.31.40 'initctl stop powerd'
ssh root@192.168.31.40 'initctl stop framework'

Kindleを再起動するとGUI(フレームワーク)もスリープも復活して使えるようになる。

でも画像を送りつけると?スクリーンセーバーは復活しないかな?電源ボタンを押しても反応しなくなる。

KindleへPNG画像送信スクリプト 無限ループ版

上で紹介したスクリプトkindle_influx.pyでPNG画像を生成して以下↓のスクリプトでKindleに画像を定期的に送信しています。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#python kindle_send.py
#WifiSSHを有効にする。(電源を切るごとに1,2をrootで実行する)
#1,rm /root/.ssh/known_hosts
#2,Kindleの検索で「;un」を実行する。
#テスト表示: ssh root@192.168.31.40 '/usr/sbin/eips -g /mnt/us/kindlesize.png'

import paramiko
import subprocess
import time
import os

KINDLE_IP   = '192.168.31.40'
UPDATE_SEC  = 300
REFRESH     = 180
private_key_path = "/root/.ssh/id_rsa"

mykey = paramiko.RSAKey(filename=private_key_path)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(KINDLE_IP, username='root', pkey=mykey)

ssh.exec_command('initctl stop powerd')
ssh.exec_command('initctl stop framework')

sftp = ssh.open_sftp()
i = 0
while True:
  proc = subprocess.Popen(['python' , '/home/go/script/kindle_influx.py'])
  out, err = proc.communicate()
  if proc.returncode != 0:
    print(f"kindle_influx.py failed with error: {err}")
    break

  if os.path.exists('/home/go/script/kindle.png'):
    sftp.put('/home/go/script/kindle.png', '/mnt/us/kindle.png')
    ssh.exec_command('eips %s -g /mnt/us/kindle.png' % ('-f' if (i % REFRESH) == 0 else ''))
  else:
    print("kindlesize.png does not exist or is not accessible")

  time.sleep(UPDATE_SEC)
  i += 1

sftp.close()
ssh.close()

上記スクリプトはkindle_send.pyとして保存してcronで起動時に1回だけ実行するようにしました。

InfluxDBが稼働しているJetson nanoが非力でInfluxDBに頻繁にアクセスするとJetson nanoのUSBについているWifiドングルが切断してしまうので、UPDATE_SECを長めの5分にしてあります。

(早くRaspberry Pi 5が普及し始めてほしいところ。)

最後にCronでPythonスクリプトkindle_send.pyをラズパイ4起動時に実行するように設定します。

su
crontab -e 以下入力
@reboot sleep 60; /usr/bin/python /home/go/script/kindle_send.py
reboot

KindleへPNG画像送信スクリプト cronで定期的に実行版

無限ループよりもCronで定期的に実行するほうがいいかな?

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import paramiko
import subprocess
import os

KINDLE_IP   = '192.168.31.40'

private_key_path = "/root/.ssh/id_rsa"

mykey = paramiko.RSAKey(filename=private_key_path)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(KINDLE_IP, username='root', pkey=mykey)

ssh.exec_command('initctl stop powerd')
ssh.exec_command('initctl stop framework')

sftp = ssh.open_sftp()

proc = subprocess.run(['python' , '/home/go/script/kindle_influx.py'], capture_output=True, text=True)
if proc.returncode != 0:
  print(f"kindle_influx.py failed with error: {proc.stderr}")

if os.path.exists('/home/go/script/kindle.png'):
  sftp.put('/home/go/script/kindle.png', '/mnt/us/kindle.png')
  ssh.exec_command('eips -f -g /mnt/us/kindle.png')
else:
  print("kindle.png does not exist or is not accessible")

sftp.close()
ssh.close()

こちらは5分おきにcronで実行するPythonスクリプト

su
crontab -e
*/5 * * * * /usr/bin/python /home/go/script/kindle_send.py

完成です♪

植物を育ててると温湿度が気になる

ここ3・4年は趣味として植物を育てているので冬や真夏は温度と湿度が気になります。

なので、外の気温を含めた室内の気温を大きめのE-paperで表示するのにはピッタリ。

20代のころは必ず枯らしていたティランジアも育てられるようになって、アガベも水やりのコツをやっと分かってきた初心者。(パキポディウムの実生は未だに2,3株しかうまくいってない。難しい・・・)

古いKindleのプロジェクトなのでお役に立てるかどうか、分かりませんがE-paper好きな方はぜひチャレンジしてみてくださいね。

この記事は複数のページに別れています

コメント

  1. 三沢 祐一郎 より:

    警告が出てしまうのでHTTPSに対応してほしいです。

    • GO より:

      コメントありがとうございます。
      ありがとうございます!SSLが効いてませんでした。修正しておきました。