Skip to content
59 changes: 59 additions & 0 deletions adafruit_ble/characteristics/json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# SPDX-FileCopyrightText: 2022 Mark Raleson
#
# SPDX-License-Identifier: MIT

"""
`json`
====================================================

This module provides a JSON characteristic for reading/writing JSON serializable Python values.

"""

import json
from . import Attribute
from . import Characteristic

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BLE.git"


class JSONCharacteristic(Characteristic):
"""JSON string characteristic for JSON serializable values of a limited size (max_length)."""

def __init__(
self,
*,
uuid=None,
properties=Characteristic.READ,
read_perm=Attribute.OPEN,
write_perm=Attribute.OPEN,
initial_value=None,
):
super().__init__(
uuid=uuid,
properties=properties,
read_perm=read_perm,
write_perm=write_perm,
max_length=512,
fixed_length=False,
initial_value=self.pack(initial_value),
)

@staticmethod
def pack(value):
"""Converts a JSON serializable python value into a utf-8 encoded JSON string."""
return json.dumps(value).encode("utf-8")

@staticmethod
def unpack(value):
"""Converts a utf-8 encoded JSON string into a python value."""
return json.loads(str(value, "utf-8"))

def __get__(self, obj, cls=None):
if obj is None:
return self
return self.unpack(super().__get__(obj, cls))

def __set__(self, obj, value):
super().__set__(obj, self.pack(value))
30 changes: 30 additions & 0 deletions examples/ble_json_central.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# SPDX-FileCopyrightText: 2020 Mark Raleson
#
# SPDX-License-Identifier: MIT

# Read sensor readings from peripheral BLE device using a JSON characteristic.

from ble_json_service import SensorService
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement


ble = BLERadio()
connection = None

while True:

if not connection:
print("Scanning for BLE device advertising our sensor service...")
for adv in ble.start_scan(ProvideServicesAdvertisement):
if SensorService in adv.services:
connection = ble.connect(adv)
print("Connected")
break
ble.stop_scan()

if connection and connection.connected:
service = connection[SensorService]
service.settings = {"unit": "celsius"} # 'fahrenheit'
while connection.connected:
print("Sensors: ", service.sensors)
47 changes: 47 additions & 0 deletions examples/ble_json_peripheral.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# SPDX-FileCopyrightText: 2020 Mark Raleson
#
# SPDX-License-Identifier: MIT

# Provide readable sensor values and writable settings to connected devices via JSON characteristic.

import time
import random
from ble_json_service import SensorService
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement


# Create BLE radio, custom service, and advertisement.
ble = BLERadio()
service = SensorService()
advertisement = ProvideServicesAdvertisement(service)

# Function to get some fake weather sensor readings for this example in the desired unit.
def measure(unit):
temperature = random.uniform(0.0, 10.0)
humidity = random.uniform(0.0, 100.0)
if unit == "fahrenheit":
temperature = (temperature * 9.0 / 5.0) + 32.0
return {"temperature": temperature, "humidity": humidity}


# Advertise until another device connects, when a device connects, provide sensor data.
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

print("Connected")
while ble.connected:
settings = service.settings
measurement = measure(settings.get("unit", "celsius"))
service.sensors = measurement
print("Settings: ", settings)
print("Sensors: ", measurement)
time.sleep(0.25)

print("Disconnected")
36 changes: 36 additions & 0 deletions examples/ble_json_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# SPDX-FileCopyrightText: 2020 Mark Raleson
#
# SPDX-License-Identifier: MIT

# Read sensor readings from peripheral BLE device using a JSON characteristic.

from adafruit_ble.uuid import VendorUUID
from adafruit_ble.services import Service
from adafruit_ble.characteristics import Characteristic
from adafruit_ble.characteristics.json import JSONCharacteristic


# A custom service with two JSON characteristics for this device. The "sensors" characteristic
# provides updated sensor values for any connected device to read. The "settings" characteristic
# can be changed by any connected device to update the peripheral's settings. The UUID of your
# service can be any valid random uuid (some BLE UUID's are reserved).
# NOTE: JSON data is limited by characteristic max_length of 512 byes.
class SensorService(Service):
# pylint: disable=too-few-public-methods

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

settings = JSONCharacteristic(
uuid=VendorUUID("e077bdec-f18b-4944-9e9e-8b3a815162b4"),
properties=Characteristic.READ | Characteristic.WRITE,
initial_value={"unit": "celsius"},
)

sensors = JSONCharacteristic(
uuid=VendorUUID("528ff74b-fdb8-444c-9c64-3dd5da4135ae"),
properties=Characteristic.READ,
)

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