あっきぃ日誌

鉄道ブログのような技術系ブログのようななにか

CircuitPython自作キーでPCのスリープの時にスクリプトがコケてしまうやつの対処

MacにTinyPicoKeyを繋ぎっぱなしにしていたら、スリープあけに使えなくなる現象が起きて、しばらく不便していました。

TinyPicoTrioもできたしと重い腰をあげて調べてみたらなんのことはなく、キーボード(あるいはマウス)を初期化する時に、初期化に成功するまで再試行してやればいいだけでした。

import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
from adafruit_hid.mouse import Mouse

keyboard = 0
while not keyboard:
    try:
        keyboard = Keyboard(usb_hid.devices)
    except:
        pass
    sleep(1)

たぶん、スリープ中か復帰前後のどこかで、デバイスとしては切断しているけれど、単に電源が供給されるタイミングがあるのかもしれません。まあ、このくらいのループで解決するなら良かった。

逆に、初期化に失敗したら再試行せずに、デバイスとしてじゃなくても遊べるモードみたいなのもあったら楽しいかなーと思って、カーソルがランダム移動するだけの拙作クソアプリことうろうろマウスのCircuitPython+Tiny2040版でやってみました。

github.com

バイスとして認識したときは、ボタンを押すとPC上のマウスカーソルがうろつきながら、Tiny2040のLEDもRGB適当に光るのですが、単に電源だけ供給したときでもLEDが光るやつだけはできるようになりました。これで、外でモバイルバッテリーとかにつないで無駄にビカビカ光らして遊べるようになりましたね。

social.mikutter.hachune.net

そんなことするか???

RV3028 RTCモジュールをCircuitPythonで動かす

PimoroniのBreakout Gardenで唯一のRTCであるRV3028モジュールをついに買ってしまいました。しかしこれはついでに買ったもので、本命は最新アイテムのVL53L5CXモジュールでした。でもブログの本題はRV3028です。ややこしいですね。

VL53L5CXモジュールはToFセンサーですが、8x8のアレイになっているものです。レーザーで距離を測るやつが縦横8x8の64個ぶんできるというわけです。楽しそうですね。ひとまずはサンプルを動かして満足しました。何かすぐに使いたいわけではないので、いつか思いついたら使うことになると思います。そう言って引き出しの肥やしになるかと思いきや、なぜか仕事で使うことがたまに発生するようになってしまっているので恐ろしいところ。


RV3028モジュールでOTP表示機をスマートにしたい

RV3028モジュールの方はすぐに使いたいやつで、前に作ったOTP表示機に使っているRTCモジュールが不格好なのでスマートにしたいという動機があります。

akkiesoft.hatenablog.jp

再掲。やばすぎる。ボタンもヤバいのですが、これは後日どうにかすることにしつつ、今回はRTCを置き換えます。

RV3028は、あらかじめRaspberry Piで時刻をセットしました。

RV3028とCircuitPython

RV3028モジュールのCircuitPython用ライブラリは……実は存在しておらず、普通のPython用しかありませんでした。Pimoroni版MicroPythonならサポートされていますが、CircuitPythonのサポートがないのを忘れたまま買ってしまいました。

github.com

しかし、I2Cで通信してるんだから最悪自力で移植できるだろうと思って読み解いたところ、rv3028のライブラリがPimoroni作のi2cdeviceライブラリで書かれており、i2cdeviceライブラリはSMBusを呼び出して読み書きの2つができればOKということがわかりました。

github.com

さらに調べると、SMBusの読み書きをいい感じにCircuitPython向けに変換してくれるアダプターを、やはりPimoroniが書いていました。最高。

github.com

というわけで、このアダプターを使えば以下のスクリプトで動くはずです。

from pimoroni_circuitpython_adapter import not_SMBus as SMBus
import board
import rv3028

i2c = SMBus(SDA = board.GP4, SCL = board.GP5)
rtc = rv3028.RV3028(i2c_dev = i2c)

rtc_time = rtc.get_time_and_date()
print("{:02d}/{:02d}/{:02d} {:02d}:{:02d}:{:02d}".format(rtc_time.year, rtc_time.month, rtc_time.day, rtc_time.hour, rtc_time.minute, rtc_time.second))

しかし、いくつかCircuitPython(MicroPython)の制約などで動かない部分があったので、手直しが必要でした。

i2cdeviceの修正

i2cdeviceで使われている__dict__が、CircuitPython(MicroPython)では取得しかできず、設定はできないらしいので、代わりにsetattrで記述しました。

--- i2cdevice-python-0.0.7/library/i2cdevice/__init__.py	2020-07-09 20:32:41.000000000 +0900
+++ __init__.py	2022-06-10 23:05:32.000000000 +0900
@@ -169,7 +169,8 @@
             self.locked[register.name] = False
             self.values[register.name] = 0
             self.registers[register.name] = register
-            self.__dict__[register.name] = _RegisterProxy(self, register)
+            setattr(self, register.name, _RegisterProxy(self, register))
 
     def lock_register(self, name):
         self.locked[name] = True

rv3028の修正

datetimeモジュールはCircuitPythonに存在しないので、adafruit_datetimeモジュールで代用します。

--- rv3028-python-0.0.5/library/rv3028/__init__.py	2019-11-01 18:23:19.000000000 +0900
+++ __init__.py	2022-06-10 22:49:48.000000000 +0900
@@ -1,7 +1,7 @@
 import time
 from i2cdevice import Device, Register, BitField
 from i2cdevice.adapter import Adapter, LookupAdapter, U16ByteSwapAdapter
-import datetime
+import adafruit_datetime as datetime
 
 __version__ = '0.0.5'

rtcモジュールのrtc.set_time_source()で使うために、RV3028クラスの中にdatetimeプロパティが必要らしいので、適当に実装しました。後ろから3つのパラメータは適当に埋めたので必要な人は適宜実装してください……。ただ、動かしてみた感じでは、後述のスクリプト実行例の通り、特に問題なさそうに見えました。

    @property
    def datetime(self):
        return time.struct_time((
            self._rv3028.get('YEAR').year + 2000,
            self._rv3028.get('MONTH').month,
            self._rv3028.get('DATE').date,
            self._rv3028.get('HOURS').t24hours,
            self._rv3028.get('MINUTES').minutes,
            self._rv3028.get('SECONDS').seconds,
            self._rv3028.get('WEEKDAY').weekday,
            0, # tm-ydayの実装が面倒なので省略
            -1
        ))

動かす

先ほどのスクリプトを実行して、時刻が返ってくることを確認します。

>>> (省略)
>>> print("{:02d}/{:02d}/{:02d} {:02d}:{:02d}:{:02d}".format(rtc_time.year, rtc_time.month, rtc_time.day, rtc_time.hour, rtc_time.minute, rtc_time.second))
2022/06/10 16:32:28

rtcモジュールのset_time_source()を使う時はこんな感じ。

from pimoroni_circuitpython_adapter import not_SMBus as SMBus
import board
from rv3028 import RV3028
import rtc
import time

i2c = SMBus(SDA = board.GP4, SCL = board.GP5)
rv3028 = RV3028(i2c_dev = i2c)
rtc.set_time_source(rv3028)

time.localtime()

こちらもこんな感じで返ってきました。

>>> time.localtime()
struct_time(tm_year=2022, tm_mon=6, tm_mday=10, tm_hour=16, tm_min=36, tm_sec=2, tm_wday=4, tm_yday=161, tm_isdst=-1)

そうしたらあとはOTP表示機のスクリプトをRV3028仕様に変更したら完成です。


まとめ

OTP表示機のRTCモジュールをRV3028に差し替えて、Breakout Gardenなモジュールでまとめることができました。いや、まだボタンがまとまっていませんでした。それでも見た目はだいぶおとなしくなりました。よかった。

ボタンはですが、なんと自作Breakout Gardenモジュール「ボタン」を作ってしまいました。一昨日発送されたので、再来週くらいには届くんじゃないかなあ……?と思います。ボタンのスイッチはButton SHIMと同じものが保守部品として余っているのでそれを採用できるように設計してみましたが、もろもろ寸法が合うかどうかは届いてのお楽しみ状態です。一応頑張って寸法を測ったり調べたりはしましたが……。

TinyPicoTrio

昨年、TinyPicoKeyを3つ並べられるTinyPicoTrioを手作りしました。

akkiesoft.hatenablog.jp

これをいよいよ基板設計して、今朝到着しました。

形状は凸っぽい感じになりました。そのまま凸にしても良かったのですが、なんとなくカーブを付けて遊びたくなったのでこんな形状になっています。あと、キー数をもっと増やしてみても良いかなとも思いましたが、今回は3キーのままとしました。もっと欲しくなったらまた作るだけですね。

さっそく組み立て。TinyPicoKeyは律儀に8ピンx2列の穴を用意していましたが、キー自体は2ピンしか使わないので、TinyPicoTrioでは四隅2ピンずつの8ピンだけ穴を用意して、必要なピンソケットの数を削減しました。ピンソケットは意外といいお値段しますしね。

TinyPicoKeyとTiny2040を搭載するとこんなかんじ。裏面は適当にゴム足を貼り付けましたが、将来的にケースを作りたくなった時とかを想定して、基板に3ヶ所穴を用意してあります。

配線はGP4〜GP6にして、GP6は1キーとして使うときと共通としました。ボタンを押したまま接続して、boot.pyでストレージ無効化を阻止する動作がどちらの場合でもできるので、便利かなと思っています。

ちょっと遊んでみた要素として、キーをひっくり返して搭載することが可能です。写真では真ん中をひっくり返していますが、左右のキーも同じ用にひっくり返せます。指の置き方に合わせて好きな向きにできます。

半年ちょっとぶりにKiCadを触ったので色々忘れていてアレでしたけど、思い出したあとはサクサクと作れた感があります。が、シルク印刷の代わりに文字をソルダーペーストにしてキラキラにさせようと欲張ってみたら、やり方をわかっておらず、基板の地の色になってしまい、やや失敗しました……。MaskとCuを重ねて配置するのが正解だったっぽいです。続けて別の基板を作っていた時に気づきました。こっちの基板も届いたらまたブログにしたいと思います。

Bルートサービスに申し込んで自宅の電力を取ってみた

セルフお誕生日プレゼントに、スマートメーターの情報が読めるあのドングルを買いました。1万ちょっとです。絶対に元が取れるネタじゃないですけど、やりたかったんだもんしょうがない。あと買い逃すとなかなか次が入荷しないらしいのも「ウッ!ポチりたい!!」という気持ちになったので、良くないね……!

で、Bルートの利用には申込みが必要なので、ポチったと同時に申し込みをします。が、メニューのリンクがアイコンに無いと思ったらテキストにしか振られてないじゃん、なんなの。

www.tepco.co.jp

ゴールデンウィークをはさんで、ユーザー名とパスワードが書面とEメールに分かれて届いたらさっそく実験です。

ドングルはシリアルデバイスとして認識するので、screenコマンドとかで開いてコマンドをポチポチ打ち込むとデータが取れるようです。Raspberry Piでももちろん動くので、自宅の常時稼働のやつに差し込みました。そして、コマンドの仕様とかを読もうかなと思いながら、もうやってる人のスクリプトをググって引っ張ってきたら動いて満足してしまったので、結局仕様は読みませんでした。だらしねえ。

qiita.com

上記のスクリプトからいらない出力を削り、得られたデータをZabbixに放り投げて終了するように書き換えました。

適当にデータを取り溜めたらグラフを眺めてニヤニヤしたり、普段はしないところまで節電に気を使ってみたりしてみましょう。夕飯の時に電子レンジを動かしたりなんだりしてるのが取れているあたりは良いですね。

このデータは……何に使えるんやろな……??

あとはなんか違う値が取れるかとか、Bルート以外で何か遊べるのかとかの研究はTODOです。Bルート以外で遊べたらなんか元が取れそうだけれど🤔

メダカメラのカメラのリプリース

メダカメラに使っていたカメラがここ最近の暴風雨でいよいよ壊れてしまいました。冬季の休止中も屋外放置して1年と少々でした。

敗因は言わずもな雨とかによる腐食だったのですが、ベランダは台風とかでなければそこまで雨は入りこまないので、軽めでやってみることにしてビニールテープを上から張っただけという雑な運用で、ここまでもったなら逆に十分と言えるかもしれません。カメラが死んだ日も台風かよみたいな暴風雨の日でした。

というわけでカメラを交換です。V1の正規カメラの代わりに、今度はAliExpressで買った300円のV1のパチモンカメラを採用しました。こっちならいくら壊れても痛くもかゆくもないですね。ですが、今度はもうちょっと雨に耐えられるようにしたいなと思ったので、ガチャポンのカプセルで上を覆ってみました。

下の方は相変わらずノーガード戦法なので、雨がカーブを描いてカメラめがけて上に吹き込んでくるようなことがあれば死にます。が、そんな魔球みたいな雨が降り始めたらさすがに地球が終わるのでは。しらんけど。

正直そもそもメダカ飼育がこんなに続くとか、こんな大所帯になるとか思ってもみなかったので、カメラのほうが先に逝くかーって感じでしたw

最近のメダカは、外の連中は減りもせず毎日元気に卵を産んでは食べてるみたいです。家の中で飼育しているチビ勢も卵を産み始める年頃になりましたが、最近になって数匹死んでベランダ菜園の肥料になりました。あと、適当に避けた水草からうっかりハリコが発生していて悲鳴を上げましたが、もう次の世代は育てるつもりはさすがに無いので、勝手に育てば育ったくらいの放置でどうなるかみてみようと思っています。。