@@ -1629,99 +1629,54 @@ We are going to build a Bluetooth® LE temperature monitor that using the __nRF
1629
1629
For this Bluetooth® LE application example, we are going to emulate the temperature sensor. Below you will find the complete sketch.
1630
1630
1631
1631
``` python
1632
+ from micropython import const
1633
+ import uasyncio as asyncio
1634
+ import aioble
1632
1635
import bluetooth
1633
1636
import random
1634
1637
import 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
-
1648
1638
# org.bluetooth.service.environmental_sensing
1649
1639
_ENV_SENSE_UUID = bluetooth.UUID(0x 181A )
1650
1640
# 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 )
1660
1642
# org.bluetooth.characteristic.gap.appearance.xml
1661
1643
_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
1718
1658
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))
1723
1660
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())
1725
1680
```
1726
1681
1727
1682
The 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