Skip to content

Commit 13c5292

Browse files
authored
Merge pull request #162 from mraleson/json-characteristic
Add JSON characteristic
2 parents 24bf561 + 7d15574 commit 13c5292

File tree

4 files changed

+172
-0
lines changed

4 files changed

+172
-0
lines changed

adafruit_ble/characteristics/json.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# SPDX-FileCopyrightText: 2022 Mark Raleson
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
"""
6+
`json`
7+
====================================================
8+
9+
This module provides a JSON characteristic for reading/writing JSON serializable Python values.
10+
11+
"""
12+
13+
import json
14+
from . import Attribute
15+
from . import Characteristic
16+
17+
__version__ = "0.0.0-auto.0"
18+
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BLE.git"
19+
20+
21+
class JSONCharacteristic(Characteristic):
22+
"""JSON string characteristic for JSON serializable values of a limited size (max_length)."""
23+
24+
def __init__(
25+
self,
26+
*,
27+
uuid=None,
28+
properties=Characteristic.READ,
29+
read_perm=Attribute.OPEN,
30+
write_perm=Attribute.OPEN,
31+
initial_value=None,
32+
):
33+
super().__init__(
34+
uuid=uuid,
35+
properties=properties,
36+
read_perm=read_perm,
37+
write_perm=write_perm,
38+
max_length=512,
39+
fixed_length=False,
40+
initial_value=self.pack(initial_value),
41+
)
42+
43+
@staticmethod
44+
def pack(value):
45+
"""Converts a JSON serializable python value into a utf-8 encoded JSON string."""
46+
return json.dumps(value).encode("utf-8")
47+
48+
@staticmethod
49+
def unpack(value):
50+
"""Converts a utf-8 encoded JSON string into a python value."""
51+
return json.loads(str(value, "utf-8"))
52+
53+
def __get__(self, obj, cls=None):
54+
if obj is None:
55+
return self
56+
return self.unpack(super().__get__(obj, cls))
57+
58+
def __set__(self, obj, value):
59+
super().__set__(obj, self.pack(value))

examples/ble_json_central.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# SPDX-FileCopyrightText: 2020 Mark Raleson
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
# Read sensor readings from peripheral BLE device using a JSON characteristic.
6+
7+
from ble_json_service import SensorService
8+
from adafruit_ble import BLERadio
9+
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
10+
11+
12+
ble = BLERadio()
13+
connection = None
14+
15+
while True:
16+
17+
if not connection:
18+
print("Scanning for BLE device advertising our sensor service...")
19+
for adv in ble.start_scan(ProvideServicesAdvertisement):
20+
if SensorService in adv.services:
21+
connection = ble.connect(adv)
22+
print("Connected")
23+
break
24+
ble.stop_scan()
25+
26+
if connection and connection.connected:
27+
service = connection[SensorService]
28+
service.settings = {"unit": "celsius"} # 'fahrenheit'
29+
while connection.connected:
30+
print("Sensors: ", service.sensors)

examples/ble_json_peripheral.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# SPDX-FileCopyrightText: 2020 Mark Raleson
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
# Provide readable sensor values and writable settings to connected devices via JSON characteristic.
6+
7+
import time
8+
import random
9+
from ble_json_service import SensorService
10+
from adafruit_ble import BLERadio
11+
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
12+
13+
14+
# Create BLE radio, custom service, and advertisement.
15+
ble = BLERadio()
16+
service = SensorService()
17+
advertisement = ProvideServicesAdvertisement(service)
18+
19+
# Function to get some fake weather sensor readings for this example in the desired unit.
20+
def measure(unit):
21+
temperature = random.uniform(0.0, 10.0)
22+
humidity = random.uniform(0.0, 100.0)
23+
if unit == "fahrenheit":
24+
temperature = (temperature * 9.0 / 5.0) + 32.0
25+
return {"temperature": temperature, "humidity": humidity}
26+
27+
28+
# Advertise until another device connects, when a device connects, provide sensor data.
29+
while True:
30+
print("Advertise services")
31+
ble.stop_advertising() # you need to do this to stop any persistent old advertisement
32+
ble.start_advertising(advertisement)
33+
34+
print("Waiting for connection...")
35+
while not ble.connected:
36+
pass
37+
38+
print("Connected")
39+
while ble.connected:
40+
settings = service.settings
41+
measurement = measure(settings.get("unit", "celsius"))
42+
service.sensors = measurement
43+
print("Settings: ", settings)
44+
print("Sensors: ", measurement)
45+
time.sleep(0.25)
46+
47+
print("Disconnected")

examples/ble_json_service.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# SPDX-FileCopyrightText: 2020 Mark Raleson
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
# Read sensor readings from peripheral BLE device using a JSON characteristic.
6+
7+
from adafruit_ble.uuid import VendorUUID
8+
from adafruit_ble.services import Service
9+
from adafruit_ble.characteristics import Characteristic
10+
from adafruit_ble.characteristics.json import JSONCharacteristic
11+
12+
13+
# A custom service with two JSON characteristics for this device. The "sensors" characteristic
14+
# provides updated sensor values for any connected device to read. The "settings" characteristic
15+
# can be changed by any connected device to update the peripheral's settings. The UUID of your
16+
# service can be any valid random uuid (some BLE UUID's are reserved).
17+
# NOTE: JSON data is limited by characteristic max_length of 512 byes.
18+
class SensorService(Service):
19+
# pylint: disable=too-few-public-methods
20+
21+
uuid = VendorUUID("51ad213f-e568-4e35-84e4-67af89c79ef0")
22+
23+
settings = JSONCharacteristic(
24+
uuid=VendorUUID("e077bdec-f18b-4944-9e9e-8b3a815162b4"),
25+
properties=Characteristic.READ | Characteristic.WRITE,
26+
initial_value={"unit": "celsius"},
27+
)
28+
29+
sensors = JSONCharacteristic(
30+
uuid=VendorUUID("528ff74b-fdb8-444c-9c64-3dd5da4135ae"),
31+
properties=Characteristic.READ,
32+
)
33+
34+
def __init__(self, service=None):
35+
super().__init__(service=service)
36+
self.connectable = True

0 commit comments

Comments
 (0)