-
Notifications
You must be signed in to change notification settings - Fork 56
Add JSON characteristic #162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
cb33c86
0360598
25255d5
65f350b
5eb2b5b
35308ae
da66228
1bb93f9
b12e8ae
2497a62
7d15574
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 Json characteristic. | ||||||
|
||||||
""" | ||||||
|
||||||
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): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you make this a subclass of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did this initially, but because of the packing/unpacking of initial_value in init and also in the setter getter inheriting from StringCharacteristic it ended up not really saving any typing. It also added an additional inheritance layer that hid attributes like max_length. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's use
Suggested change
|
||||||
"""Json string characteristic for JSON serializable values of a limited size (max_length).""" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
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)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# SPDX-FileCopyrightText: 2020 Mark Raleson | ||
# | ||
# SPDX-License-Identifier: MIT | ||
|
||
# Read sensor readings from peripheral BLE device using JSON characteristic. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix grammar -> "a JSON characteristic" , or similar. |
||
|
||
from adafruit_ble import BLERadio | ||
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement | ||
from ble_json_service import SensorService | ||
|
||
|
||
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) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# 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 adafruit_ble import BLERadio | ||
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement | ||
from ble_json_service import SensorService | ||
|
||
|
||
# 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(.25) | ||
|
||
print('Disconnected') |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
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 | ||
dhalbert marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
# A custom service with two Json characteristics for this device. The "sensors" characteristic | ||
dhalbert marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# 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. | ||
dhalbert marked this conversation as resolved.
Show resolved
Hide resolved
|
||
class SensorService(Service): | ||
uuid = VendorUUID("51ad213f-e568-4e35-84e4-67af89c79ef0") | ||
|
||
settings = JsonCharacteristic( | ||
dhalbert marked this conversation as resolved.
Show resolved
Hide resolved
|
||
uuid=VendorUUID("e077bdec-f18b-4944-9e9e-8b3a815162b4"), | ||
properties=Characteristic.READ | Characteristic.WRITE, | ||
initial_value={ | ||
'unit': 'celsius' | ||
} | ||
) | ||
|
||
sensors = JsonCharacteristic( | ||
dhalbert marked this conversation as resolved.
Show resolved
Hide resolved
|
||
uuid=VendorUUID("528ff74b-fdb8-444c-9c64-3dd5da4135ae"), | ||
properties=Characteristic.READ, | ||
) | ||
|
||
def __init__(self, service=None): | ||
super().__init__(service=service) | ||
self.connectable = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make this grammatical, and expand on what is going on a bit more.