LoginSignup
3
1

More than 3 years have passed since last update.

iPhoneからBLEのCurrent Time Serviceで現在時刻を取得する(Pythonista編)

Last updated at Posted at 2019-10-04

概要

元は 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()
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1