@@ -1629,99 +1629,54 @@ We are going to build a Bluetooth® LE temperature monitor that using the __nRF
16291629For this Bluetooth® LE application example, we are going to emulate the temperature sensor. Below you will find the complete sketch.
16301630
16311631``` python
1632+ from micropython import const
1633+ import uasyncio as asyncio
1634+ import aioble
16321635import bluetooth
16331636import random
16341637import struct
1635- import time
1636- from ble_advertising import advertising_payload
1637- from machine import LED
1638- from micropython import const
1639-
1640- _IRQ_CENTRAL_CONNECT = const(1 )
1641- _IRQ_CENTRAL_DISCONNECT = const(2 )
1642- _IRQ_GATTS_INDICATE_DONE = const(20 )
1643-
1644- _FLAG_READ = const(0x 0002 )
1645- _FLAG_NOTIFY = const(0x 0010 )
1646- _FLAG_INDICATE = const(0x 0020 )
1647-
16481638# org.bluetooth.service.environmental_sensing
16491639_ENV_SENSE_UUID = bluetooth.UUID(0x 181A )
16501640# org.bluetooth.characteristic.temperature
1651- _TEMP_CHAR = (
1652- bluetooth.UUID(0x 2A6E ),
1653- _FLAG_READ | _FLAG_NOTIFY | _FLAG_INDICATE ,
1654- )
1655- _ENV_SENSE_SERVICE = (
1656- _ENV_SENSE_UUID ,
1657- (_TEMP_CHAR ,),
1658- )
1659-
1641+ _ENV_SENSE_TEMP_UUID = bluetooth.UUID(0x 2A6E )
16601642# org.bluetooth.characteristic.gap.appearance.xml
16611643_ADV_APPEARANCE_GENERIC_THERMOMETER = const(768 )
1662-
1663-
1664- class BLETemperature :
1665- def __init__ (self , ble , name = " Py Temp Sensor" ):
1666- self ._ble = ble
1667- self ._ble.active(True )
1668- self ._ble.irq(self ._irq)
1669- ((self ._handle,),) = self ._ble.gatts_register_services((_ENV_SENSE_SERVICE ,))
1670- self ._connections = set ()
1671- self ._payload = advertising_payload(
1672- name = name,
1673- services = [_ENV_SENSE_UUID ],
1674- appearance = _ADV_APPEARANCE_GENERIC_THERMOMETER ,
1675- )
1676- self ._advertise()
1677- self .led = LED(" LED_BLUE" )
1678-
1679- def _irq (self , event , data ):
1680- # Track connections so we can send notifications.
1681- if event == _IRQ_CENTRAL_CONNECT :
1682- conn_handle, _, _ = data
1683- self ._connections.add(conn_handle)
1684- self .led.on()
1685- elif event == _IRQ_CENTRAL_DISCONNECT :
1686- conn_handle, _, _ = data
1687- self ._connections.remove(conn_handle)
1688- # Start advertising again to allow a new connection.
1689- self ._advertise()
1690- self .led.off()
1691- elif event == _IRQ_GATTS_INDICATE_DONE :
1692- conn_handle, value_handle, status = data
1693-
1694- def set_temperature (self , temp_deg_c , notify = False , indicate = False ):
1695- # Data is sint16 in degrees Celsius with a resolution of 0.01 degrees Celsius.
1696- # Write the local value, ready for a central to read.
1697- self ._ble.gatts_write(self ._handle, struct.pack(" <h" , int (temp_deg_c * 100 )))
1698- if notify or indicate:
1699- for conn_handle in self ._connections:
1700- if notify:
1701- # Notify connected centrals.
1702- self ._ble.gatts_notify(conn_handle, self ._handle)
1703- if indicate:
1704- # Indicate connected centrals.
1705- self ._ble.gatts_indicate(conn_handle, self ._handle)
1706-
1707- def _advertise (self , interval_us = 500000 ):
1708- self ._ble.gap_advertise(interval_us, adv_data = self ._payload)
1709-
1710-
1711- if __name__ == " __main__" :
1712- ble = bluetooth.BLE()
1713- temp = BLETemperature(ble)
1714-
1715- t = 25
1716- i = 0
1717-
1644+ # How frequently to send advertising beacons.
1645+ _ADV_INTERVAL_MS = 250_000
1646+ # Register GATT server.
1647+ temp_service = aioble.Service(_ENV_SENSE_UUID )
1648+ temp_characteristic = aioble.Characteristic(
1649+ temp_service, _ENV_SENSE_TEMP_UUID , read = True , notify = True
1650+ )
1651+ aioble.register_services(temp_service)
1652+ # Helper to encode the temperature characteristic encoding (sint16, hundredths of a degree).
1653+ def _encode_temperature (temp_deg_c ):
1654+ return struct.pack(" <h" , int (temp_deg_c * 100 ))
1655+ # This would be periodically polling a hardware sensor.
1656+ async def sensor_task ():
1657+ t = 24.5
17181658 while True :
1719- # Write every second, notify every 10 seconds.
1720- i = (i + 1 ) % 10
1721- temp.set_temperature(t, notify = i == 0 , indicate = False )
1722- # Random walk the temperature.
1659+ temp_characteristic.write(_encode_temperature(t))
17231660 t += random.uniform(- 0.5 , 0.5 )
1724- time.sleep_ms(1000 )
1661+ await asyncio.sleep_ms(1000 )
1662+ # Serially wait for connections. Don't advertise while a central is
1663+ # connected.
1664+ async def peripheral_task ():
1665+ while True :
1666+ async with await aioble.advertise(
1667+ _ADV_INTERVAL_MS ,
1668+ name = " mpy-temp" ,
1669+ services = [_ENV_SENSE_UUID ],
1670+ appearance = _ADV_APPEARANCE_GENERIC_THERMOMETER ,
1671+ ) as connection:
1672+ print (" Connection from" , connection.device)
1673+ await connection.disconnected()
1674+ # Run both tasks.
1675+ async def main ():
1676+ t1 = asyncio.create_task(sensor_task())
1677+ t2 = asyncio.create_task(peripheral_task())
1678+ await asyncio.gather(t1, t2)
1679+ asyncio.run(main())
17251680```
17261681
17271682The example code shown above creates a Bluetooth® Low Energy service and characteristics according to the [ Bluetooth® LE standard] ( https://btprodspecificationrefs.blob.core.windows.net/assigned-numbers/Assigned%20Number%20Types/Assigned_Numbers.pdf ) for transmitting an emulated temperature value.
0 commit comments