Raspberry Pi Pico W というマイコンは内臓クロックを持っていないので、単体駆動するとそのままでは現在時刻が取れません。
ただ、無線通信チップを搭載しているのでネットワークに接続できれば、NTP(Network Time Protocol)サーバーから時刻を取ってこれます。
こんな感じです。
開発環境の設定は以下参照
Pi PicoにMicroPythonをセットアップして実行してみる(メモ)
必要な機能は以下の通り
●NTPサーバーに接続して時刻変数を取得
NTPサーバーはいろいろあります、好きなのをお選びください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
import usocket as socket try: import ustruct as struct except: import struct def time(): NTP_DELTA = 2208988800 # NTPサーバー ntp_host = "ntp.nict.jp" #ntp_host = "time-c.nist.gov" #ntp_host = "time.cloudflare.com" #ntp_host = "time.google.com" NTP_QUERY = bytearray(48) NTP_QUERY[0] = 0x1b addr = socket.getaddrinfo(ntp_host, 123)[0][-1] s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # s.settimeout(1) res = s.sendto(NTP_QUERY, addr) msg = s.recv(48) s.close() val = struct.unpack("!I", msg[40:44])[0] return val - NTP_DELTA |
ntp.nict.jpは日本で公開されているサーバーです。
NTPサーバからは1900年1月1日00:00:00(UTC)からの経過秒数が送られてきますが、時刻関連のライブラリの関数はUNIXエポックと呼ばれる1970年1月1日00:00:00(UTC)からの経過秒数を使います。そこで補正するための定数がNTP_DELTA(2208988800秒)です。
●上記のntptime.pyを読み込んで時刻変数を取得して、曜日も含めて返す関数を定義。Micropythonはzfill関数を持っていないので別途定義して数字をゼロパディングして表示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
import ntptime import utime import time wday = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'] def zfill(s, width): if len(s) < width: return ("0" * (width - len(s))) + s else: return s def get_now(): t = ntptime.time() t = t + 9*60*60 #print(t) datetimetuple = time.gmtime(t) year = str(datetimetuple[0]) month = zfill(str(datetimetuple[1]),2) mday = zfill(str(datetimetuple[2]),2) hour = zfill(str(datetimetuple[3]),2) minute = zfill(str(datetimetuple[4]),2) seconds = zfill(str(datetimetuple[5]),2) wd_index = datetimetuple[6] datetime = year + "/" + month + "/" + mday + " " + wday[wd_index] + " " + hour + ":" + minute + ":" + seconds return datetime |
日本標準時はサーバーの時刻より先に進んでいます、9時間プラス。
t = t + 9*60*60 は補正秒数です。
datetimetupleは8つの要素を持っていますが、最後のdatetimetuple[7]は経過日数です、今回は使いません。
●Wi-Fi ネットワーク接続
SSIDやパスワードは各自の環境ので置き換えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
import time import network ssid = '<SSID>' password = '<パスワード>' wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(ssid, password) max_wait = 10 while max_wait > 0: if wlan.status() < 0 or wlan.status() >= 3: break max_wait -= 1 print('waiting for connection...') time.sleep(1) if wlan.status() != 3: raise RuntimeError('network connection failed') else: print('connected') status = wlan.ifconfig() print('ip = ' + status[0]) |
●表示用有機ELディスプレイ
接続やライブラリ等は以下を参照(日本語表記は今回は使わず)
Pi Pico (W)で有機ELディスプレイに日本語表示(メモ)
|
import machine import ssd1306 #oled sda = machine.Pin(0) scl = machine.Pin(1) i2c = machine.I2C(0,sda=sda, scl=scl, freq=400000) oled = ssd1306.SSD1306_I2C(128, 64, i2c) def write_oled(text): oled.fill(0) oled.text(text, 0, 5) oled.show() |
●Lチカ
|
#LED led = machine.Pin("LED", machine.Pin.OUT) led.value(1) led.value(0) |
まとめるとこんな感じです。main.py のSSIDとパスワードは書き直してください。
電源投入ー>LED点灯ー>ネット接続ー>完了ー>LED消灯ー>5秒間隔でNTPサーバーから時刻取得ー>有機ELディスプレイに表示
【ntptime.py】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
import usocket as socket try: import ustruct as struct except: import struct def time(): NTP_DELTA = 2208988800 # ntp server #ntp_host = "ntp.nict.jp" #ntp_host = "time-c.nist.gov" #ntp_host = "time.cloudflare.com" ntp_host = "time.google.com" NTP_QUERY = bytearray(48) NTP_QUERY[0] = 0x1b addr = socket.getaddrinfo(ntp_host, 123)[0][-1] s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # s.settimeout(1) res = s.sendto(NTP_QUERY, addr) msg = s.recv(48) s.close() val = struct.unpack("!I", msg[40:44])[0] return val - NTP_DELTA |
【main.py】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
|
import ntptime import utime import time import network import machine import ssd1306 #LED led = machine.Pin("LED", machine.Pin.OUT) #oled sda = machine.Pin(0) scl = machine.Pin(1) i2c = machine.I2C(0,sda=sda, scl=scl, freq=400000) oled = ssd1306.SSD1306_I2C(128, 64, i2c) wday = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'] def zfill(s, width): if len(s) < width: return ("0" * (width - len(s))) + s else: return s def get_now(): t=ntptime.time() t = t + 9*60*60 #print(t) datetimetuple = time.gmtime(t) year = str(datetimetuple[0]) month = zfill(str(datetimetuple[1]),2) mday = zfill(str(datetimetuple[2]),2) hour = zfill(str(datetimetuple[3]),2) minute = zfill(str(datetimetuple[4]),2) seconds = zfill(str(datetimetuple[5]),2) wd_index = datetimetuple[6] #日付と時刻を分けるデリミター("|")を付加 datetime = year + "/" + month + "/" + mday + " " + wday[wd_index] + "|" + hour + ":" + minute + ":" + seconds return datetime led.value(1) ssid = '<SSID>' password = '<パスワード>' wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(ssid, password) max_wait = 10 while max_wait > 0: if wlan.status() < 0 or wlan.status() >= 3: break max_wait -= 1 print('waiting for connection...') time.sleep(1) if wlan.status() != 3: raise RuntimeError('network connection failed') else: print('connected') status = wlan.ifconfig() print('ip = ' + status[0]) led.value(0) #datetime = get_now() #print(datetime) while True: oled.fill(0) now = get_now() #日付と時刻は2行に分けて表示 now_array = now.split("|") oled.text(now_array[0], 0, 5) oled.text(now_array[1], 0, 15) oled.show() utime.sleep(5) |
Pico は1.8V~5.5Vの範囲内なら乾電池やモバイルバッテリーでも3.3Vに昇降圧して起動します。
リチュウムイオン・モバイルバッテリの場合、途中で給電が停止するタイプもあるので注意が必要です。
Leave a Reply