#概要
元は M5Stack で現在時刻を取得する方法として NTP ではなく BLE で取得する方法を探していたところ Current Time Service というのがありました。とりあえず Pythonista で試し返ってくる時刻データの内容を確認するためのサンプルプログラムです。
これでできるなら M5Stack/M5StickC でも同様にできるだろう、と始めたのですが、1週間ほど格闘することになりました。結果的に取得はできたので、それについてはこちら。
iPhoneからBLEのCurrent Time Serviceで現在時刻を取得する(M5StickC編)
##環境
- Pythonista3 v3.2
- iPhone 6 iOS 12.4.2 (BLE Server)
- iPad mini 4 iOS 13.1.2 (BLE Client)
##実行例
iPad上でPythonistaを実行し、iPhoneの時刻をBLE Current Time Serviceで取得
Pythonista実行時コンソール出力
Scanning for peripherals...
Discovered peripheral: MyiPhone (..........)
Connected: MyiPhone
Discovering services...
CTS Service found: 1805
CTS Characteristics found: 2A2B
2019-10-04 19:02:36.281 (Fri) Adjust Reason: 2
2019-10-04 19:02:37.300 (Fri) Adjust Reason: 2
2019-10-04 19:02:38.292 (Fri) Adjust Reason: 2
2019-10-04 19:02:39.312 (Fri) Adjust Reason: 2
2019-10-04 19:02:40.300 (Fri) Adjust Reason: 2
2019-10-04 19:02:41.320 (Fri) Adjust Reason: 2
2019-10-04 19:02:42.312 (Fri) Adjust Reason: 2
: : :
#Pythonista3プログラム
iPhoneの前後左右の傾きに応じて、左右の車輪を動かすための指示をBLE経由で送信する仕組みです。
BLE_Current_Time_Service.py
import time
import cb
import struct
CTS_DEVICE_NAME = 'MyiPhone'
CTS_SERVICE_UUID = '1805'
CTS_CHARACTERISTIC_UUID = '2A2B'
DAY_OF_WEEK = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
class MyCentralManagerDelegate (object):
def __init__(self):
self.peripheral = None
self.characteristic = None
def did_discover_peripheral(self, p):
if p.name and CTS_DEVICE_NAME in p.name and not self.peripheral:
# Keep a reference to the peripheral, so it doesn't get garbage-collected:
print('Discovered peripheral: %s (%s)' % (p.name, p.uuid))
self.peripheral = p
cb.connect_peripheral(self.peripheral)
cb.stop_scan()
def did_connect_peripheral(self, p):
print('Connected: %s' % p.name)
print('Discovering services...')
p.discover_services()
def did_fail_to_connect_peripheral(self, p, error):
print('Failed to connect: %s' % (error,))
def did_disconnect_peripheral(self, p, error):
print('Disconnected, error: %s' % (error,))
self.peripheral = None
self.characteristic = None
cb.scan_for_peripherals()
def did_discover_services(self, p, error):
for s in p.services:
if CTS_SERVICE_UUID in s.uuid:
print('CTS Service found: %s' % (s.uuid,))
p.discover_characteristics(s)
def did_discover_characteristics(self, s, error):
if CTS_SERVICE_UUID in s.uuid:
for c in s.characteristics:
if CTS_CHARACTERISTIC_UUID in c.uuid:
print('CTS Characteristics found: %s' % (c.uuid,))
self.characteristic = c
def did_update_value(self, c, error):
if CTS_CHARACTERISTIC_UUID == c.uuid:
# 10 byte data
# byte 0,1 Year (byte1*256+byte0)
# byte 2 Month
# byte 3 Day
# byte 4 Hours
# byte 5 Minutes
# byte 6 Seconds
# byte 7 Day of Week (Monday = 1, ... Sunday = 7)
# byte 8 1/256th of a second (milliseconds = byte8*1000/256)
# byte 9 Adjust Reason
# bit 0: Manual time update
# bit 1: External reference time update
# bit 2: Change of time zone
# bit 3: Change of DST (daylight savings time)
data = struct.unpack('HBBBBBBBB', c.value)
print('{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d} ({:s}) Adjust Reason: {:d}'.format(
*data[:6], int(data[7]*1000/256), DAY_OF_WEEK[data[6]-1], data[8]))
def get_current_time(self):
if self.peripheral is not None and self.characteristic is not None:
self.peripheral.read_characteristic_value(self.characteristic)
return True
return False
cb_delegate = MyCentralManagerDelegate()
print('Scanning for peripherals...')
cb.set_central_delegate(cb_delegate)
cb.scan_for_peripherals()
# Keep the connection alive until the 'Stop' button is pressed:
try:
while True:
cb_delegate.get_current_time()
time.sleep(1)
except KeyboardInterrupt:
# Disconnect everything:
cb.reset()