PimoroniのBreakout Gardenで唯一のRTCであるRV3028モジュールをついに買ってしまいました。しかしこれはついでに買ったもので、本命は最新アイテムのVL53L5CXモジュールでした。でもブログの本題はRV3028です。ややこしいですね。
VL53L5CXモジュールはToFセンサーですが、8x8のアレイになっているものです。レーザーで距離を測るやつが縦横8x8の64個ぶんできるというわけです。楽しそうですね。ひとまずはサンプルを動かして満足しました。何かすぐに使いたいわけではないので、いつか思いついたら使うことになると思います。そう言って引き出しの肥やしになるかと思いきや、なぜか仕事で使うことがたまに発生するようになってしまっているので恐ろしいところ。
RV3028モジュールでOTP表示機をスマートにしたい
RV3028モジュールの方はすぐに使いたいやつで、前に作ったOTP表示機に使っているRTCモジュールが不格好なのでスマートにしたいという動機があります。
再掲。やばすぎる。ボタンもヤバいのですが、これは後日どうにかすることにしつつ、今回はRTCを置き換えます。
RV3028は、あらかじめRaspberry Piで時刻をセットしました。
RV3028とCircuitPython
RV3028モジュールのCircuitPython用ライブラリは……実は存在しておらず、普通のPython用しかありませんでした。Pimoroni版MicroPythonならサポートされていますが、CircuitPythonのサポートがないのを忘れたまま買ってしまいました。
しかし、I2Cで通信してるんだから最悪自力で移植できるだろうと思って読み解いたところ、rv3028のライブラリがPimoroni作のi2cdeviceライブラリで書かれており、i2cdeviceライブラリはSMBusを呼び出して読み書きの2つができればOKということがわかりました。
さらに調べると、SMBusの読み書きをいい感じにCircuitPython向けに変換してくれるアダプターを、やはりPimoroniが書いていました。最高。
というわけで、このアダプターを使えば以下のスクリプトで動くはずです。
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と同じものが保守部品として余っているのでそれを採用できるように設計してみましたが、もろもろ寸法が合うかどうかは届いてのお楽しみ状態です。一応頑張って寸法を測ったり調べたりはしましたが……。