CircuitPython 10行プログラミング Step8 (10) BLE float characteristics

 第8回マイコン・ボードSeeed XIAO BLE SenseのI2Cバスに、温湿度センサAHT20を接続しペリフェラルにしました。ここでは、センサの乗っていないSeeed XIAO BLEをセントラルにしました。

 しかし、第9回のようにstreamで実数をうまくハンドリングできませんでした。ここでは、FloatCharacteristicを利用します。

ペリフェラルSensorServiceクラス

 温度と湿度を読み取るfloatのcharacteristics UUIDを用意します。

 次のプログラムをSwitchBot.pyで保存します。streamのimportが残っていますが、使ってはいません


# SPDX-FileCopyrightText: 2020 Mark Raleson
# SPDX-License-Identifier: MIT

from adafruit_ble.uuid import VendorUUID
from adafruit_ble.services import Service
from adafruit_ble.characteristics import Characteristic
from adafruit_ble.characteristics.stream import StreamIn
from adafruit_ble.characteristics.stream import StreamOut
from adafruit_ble.characteristics.float import FloatCharacteristic

class SensorService(Service):

    uuid = VendorUUID("51ad213f-e568-4e35-84e4-67af89c79ef0")

    sensorsT = FloatCharacteristic(
        uuid=VendorUUID("e077bdec-f18b-4944-9e9e-8b3a815162b4"),
        properties=Characteristic.READ | Characteristic.NOTIFY,
    )

    sensorsH = FloatCharacteristic(
        uuid=VendorUUID("528ff74b-fdb8-444c-9c64-3dd5da4135ae"),
        properties=Characteristic.READ | Characteristic.NOTIFY,

    )

    def __init__(self, service=None):
        super().__init__(service=service)
        self.connectable = True

ペリフェラルのプログラム

 センサの読み取った値をそれぞれのcharacteristic UUIDに代入することで送信しています。streamのようにread/writeはありません。


# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

import time
import struct
import board
import adafruit_ahtx0
from SwitchBot import SensorService
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement

# Create BLE radio, custom service, and advertisement.
ble = BLERadio()
sService = SensorService()
advertisement = ProvideServicesAdvertisement(sService)
ble.name = "AHT20 Humidity&Temperature"

# Create sensor object, communicating over the board's default I2C bus
i2c = board.I2C()  # uses board.SCL and board.SDA
sensor = adafruit_ahtx0.AHTx0(i2c)

while True:
    print("Advertise services")
    ble.stop_advertising()  # you need to do this to stop any persistent old advertisement
    ble.start_advertising(advertisement)

    print("Waiting for connection...")
    while not ble.connected:
        pass
    ble.stop_advertising()
    print("Connected")
    while ble.connected:
        print("\nTemperature: %0.1f C" % sensor.temperature)
        print("Humidity: %0.1f %%" % sensor.relative_humidity)
        sService.sensorsT = sensor.temperature
        sService.sensorsH = sensor.relative_humidity
        time.sleep(3)

    print("Disconnected")

セントラルのSensorServiceクラス

 温度と湿度を読み取るfloatのcharacteristics UUIDを用意します。

 次のプログラムをSwitchBot.pyで保存します。ペリフェラルと同じ記述です。


# SPDX-FileCopyrightText: 2020 Mark Raleson
# SPDX-License-Identifier: MIT

from adafruit_ble.uuid import VendorUUID
from adafruit_ble.services import Service
from adafruit_ble.characteristics import Characteristic
from adafruit_ble.characteristics.stream import StreamIn
from adafruit_ble.characteristics.stream import StreamOut
from adafruit_ble.characteristics.float import FloatCharacteristic

class SensorService(Service):

    uuid = VendorUUID("51ad213f-e568-4e35-84e4-67af89c79ef0")

    sensorsT = FloatCharacteristic (
        uuid=VendorUUID("e077bdec-f18b-4944-9e9e-8b3a815162b4"),
        properties=Characteristic.READ | Characteristic.NOTIFY,
    )

    sensorsH = FloatCharacteristic(
        uuid=VendorUUID("528ff74b-fdb8-444c-9c64-3dd5da4135ae"),
        properties=Characteristic.READ | Characteristic.NOTIFY,
    )

    def __init__(self, service=None):
        super().__init__(service=service)
        self.connectable = True

セントラルのプログラム

 少し離れたところで動作しているペリフェラルは、実数で温度と湿度を送っています。フォーマットは不明です。

 start_scanで、アドバタイジングしているペリフェラルを見つけ、その中のservice UUIDがSensorService(Service)なのを見つけたらconnectします。

 そのserviceのなかの温度characteristics UUIDなるsensorsT、同様に湿度sensorsHのオブジェクトを変数RTとRH代入します。送った実数がそのまま入っています。


# SPDX-FileCopyrightText: 2020 Mark Raleson
# SPDX-License-Identifier: MIT

from SwitchBot import SensorService
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
import time
import struct

ble = BLERadio()
connection = None

while True:
    if not connection:
        print("Scanning")
        for adv in ble.start_scan(ProvideServicesAdvertisement):
            addr = adv.address
            s = ProvideServicesAdvertisement.matches
            #address = str(addr)[9:26]
            #print(address, adv)
            if SensorService in adv.services:
                connection = ble.connect(adv)
                print("Connected")
                break
            print(".")
        ble.stop_scan()
        print("stopped scan")
        if connection and connection.connected:
            service = connection[SensorService]
            while connection.connected:
                RT = service.sensorsT
                RH = service.sensorsH
                print("Temp: ", RT)
                print("Humi: ", RH)
                print("")
                time.sleep(3)

 実行中の様子です。