2022
bluetooth Mesh models
a provisioner's perspective
EXTENDING MODELS
Light Lightness Setup Server
Light Lightness Server
Generic Power OnOff Setup Server
Generic Power OnOff Server
Generic Level Server
Generic OnOff Server
Generic Default Transition Time Server
EXTENDING MODELS
Light Lightness Setup Server
Light Lightness Server
Generic Power OnOff Setup Server
Generic Level Server
Generic Default Transition Time Server
Generic OnOff Server
Generic Power OnOff Server
models have separate states and opcodes
order does not matter
this isn't inheritance
STATE BINDING
STATE BINDING
Generic OnOff Server
- Generic OnOff
Generic OnOff = F(Light Lightness Linear)
Generic Level = G(Light Lightness Linear)
Light Lightness Actual = H(Light Lightness Linear)
Light Lightness Linear = F'(Generic OnOff)
Light Lightness Linear = G'(Generic Level)
Light Lightness Linear = H'(Light Lightness Actual)
Light Lightness Server
Generic Level Server
Generic OnOff Server
- Generic Level
- Light Lightness Linear
- Light Lightness Actual
SHARED SUBSCRIPTIONS
Light Lightness Server
Generic Power OnOff Server
Generic Level Server
Generic OnOff Server
Generic Default Transition Time Server
- Subscription List
- Subscription List
- Subscription List
- Subscription List
- Subscription List
implementation detail:
keep lists in the element, identified by root model id
extending models
Light Lightness Server
Generic Power OnOff Server
Generic Level Server
Generic OnOff Server
Generic Default Transition Time Server
Light CTL Server
Light CTL Temperature Server
Generic Level Server
Main
Temperature
Multiple elements
extending models
Multiple elements
https://www.bluetooth.org/errata/errata_view.cfm?errata_id=16366
https://www.bluetooth.org/errata/errata_view.cfm?errata_id=11345
EXTENDING MODELS
Multiple elements
Config Server
Health Server
Generic DTT Server
Scene Server
Scene Setup Server
Generic OnOff Server
Generic Power OnOff Server
Generic Power OnOff Setup Server
Generic Level Server
Light Lightness Server
Light Lightness Setup Server
Light CTL Server
Light CTL Setup Server
Sensor Server
Sensor Setup Server
Generic OnOff Client
Generic Level Client
Light LC Server
Light LC Setup Server
Generic OnOff Server
Sensor Server
Sensor Setup Server
Generic OnOff Client
Generic Level Client
Generic OnOff Server
Sensor Server
Sensor Setup Server
Light CTL Temperature Server
Generic DTT Server
Scene Server
Scene Setup Server
Generic Level Server
Generic OnOff Server
Scene Client
STATE BINDING
Multiple elements
STATE BINDING
Temperature.Generic Level = F(Temperature.Light CTL Temperature)
Temperature.Light CTL Temperature = G(Main.Light CTL)
Temperature.Light CTL Temperature = F'(Temperature.Generic Level)
Main.Light CTL = G'(Temperature.Light CTL Temperature)
Light CTL Server
Light CTL Temperature Server
Generic Level Server
- Light CTL Temperature
- Light CTL
Multiple elements
- Generic Level
Light CTL Server
Main
Temperature
MULTIPLE MODELS
OF THE SAME TYPE
Config Server
Health Server
Generic DTT Server
Scene Server
Scene Setup Server
Generic OnOff Server
Generic Power OnOff Server
Generic Power OnOff Setup Server
Generic Level Server
Light Lightness Server
Light Lightness Setup Server
Light CTL Server
Light CTL Setup Server
Sensor Server
Sensor Setup Server
Generic OnOff Client
Generic Level Client
Light LC Server
Light LC Setup Server
Generic OnOff Server
Sensor Server
Sensor Setup Server
Generic OnOff Client
Generic Level Client
Generic OnOff Server
Sensor Server
Sensor Setup Server
Light CTL Temperature Server
Generic DTT Server
Scene Server
Scene Setup Server
Generic Level Server
Generic OnOff Server
Scene Client
#1
#2
DESIGNING AN API
Node |
---|
uuid: UUID name: String features: Features elements: List<Element> |
Element |
---|
index: Integer models: Map<ModelId, Model> |
Model |
---|
ID: ModelId publication: Publication app_keys: Set<Integer> |
1
*
1
*
STATES
GenericOnOffServer |
---|
generic_on_off: Boolean |
GenericLevelServer |
---|
generic_level: Integer |
LightLightnessServer |
---|
light_lightness: Integer |
DESIGNING AN API
Node |
---|
uuid: UUID name: String features: Features elements: List<Element> |
Element |
---|
index: Integer subscription_lists: Map<ModelId, Set<int>> models: Map<ModelId, Model> |
Model |
---|
ID: ModelId publication: Publication app_keys: Set<Integer> subscriptions: Set<int> |
1
*
1
*
SUBSCRIPTION LISTS
GenericOnOffServer |
---|
generic_on_off: Boolean |
GenericLevelServer |
---|
generic_level: Integer |
LightLightnessServer |
---|
light_lightness: Integer |
DESIGNING AN API
Node |
---|
uuid: UUID name: String features: Features elements: List<Element> |
Element |
---|
index: Integer subscription_lists: Map<ModelId, Set<int>> models: Map<ModelId, Model> |
Model |
---|
ID: ModelId publication: Publication app_keys: Set<Integer> subscriptions: Set<int> ELEMENT: ModelElement EXTEND: Map<ModelElement, Set<ModelId>> |
corresponding(ModelId, ModelElement): Model |
1
*
1
*
EXTENDING
ModelElement |
---|
MAIN TEMPERATURE HUE SATURATION LIGHT_LC OLC ... |
DESIGNING AN API
EXTENDING
class LightLCServer(Model):
ID = ModelId(None, 0x130F)
ELEMENT = ModelElement.LIGHT_LC
EXTEND = {
ModelElement.LIGHT_LC: (GenericOnOffServer,),
}
class LightLightnessServer(Model):
ID = ModelId(None, 0x1300)
ELEMENT = ModelElement.MAIN
EXTEND = {
ModelElement.MAIN: (GenericPowerOnOffServer, GenericLevelServer),
ModelElement.LIGHT_LC: (LightLCServer,),
}
light_lightness is light_lc.corresponding(LightLightnessServer, ModelElement.MAIN)
light_lc is light_lightness.corresponding(LightLCServer, ModelElement.LIGHT_LC)
DESIGNING AN API
STATE BINDING
You Ain't Gonna Need It ?
DESIGNING AN API
SCENES
watch out for the next episode!
DESIGNING AN API
generating configuration
def diff(lhs_model, rhs_model):
assert type(lhs_model) == type(rhs_model)
# only if we own the subscription list
if lhs_model.root:
for missing_subscription in (
lhs_model.subscriptions - rhs_model.subscriptions
):
yield (StateAction.ADD, "subscriptions", missing_subscription)
for extra_subscription in rhs_model.subscriptions - lhs_model.subscriptions:
yield (StateAction.DEL, "subscriptions", missing_subscription)
if lhs_model.publication != rhs_model.publication:
yield (StateAction.SET, "publication", lhs_model.publication)
for missing_bind in lhs_model.app_keys - rhs_model.app_keys:
yield (StateAction.ADD, "app_keys", missing_bind)
for extra_bind in rhs_model.app_keys - lhs_model.app_keys:
yield (StateAction.DEL, "app_keys", extra_bind)
for attribute in lhs_model.__attrs__:
lhs_value = getattr(lhs_model, attribute.name)
rhs_value = getattr(rhs_model, attribute.name)
if lhs_value != rhs_value:
yield (StateAction.SET, attribute.name, lhs_value)
DESIGNING AN API
generating configuration
def diff(lhs_element, rhs_element):
for lhs_model, rhs_model in zip(
sorted(lhs_element.models.values()), sorted(rhs_element.models.values())
):
for (action, state, value) in lhs_model - rhs_model:
yield Diff(lhs_element.index, type(lhs_model),
state, action, value)
def diff(lhs_node, rhs_node):
for lhs_element, rhs_element in zip(lhs_node.elements, rhs_node.elements):
yield from lhs_element.diff(rhs_element)
Diff(element=0, model=GenericLevelClient, state='app_keys',
action=ADD', value=1)
Diff(element=0, model=GenericLevelClient, state='publication',
action=SET, value=Publication(publish_address=49154, app_key_index=1, ...))
Diff(element=0, model=LightLightnessServer, state='app_keys',
action=ADD, value=1)
Diff(element=0, model=LightLightnessSetupServer, state='subscriptions',
action=ADD, value=49152)
Diff(element=0, model=LightLightnessSetupServer, state='subscriptions',
action=ADD, value=49154)
Diff(element=1, model=GenericLevelClient, state='app_keys',
action=ADD, value=1)
Diff(element=1, model=GenericLevelClient, state='publication',
action='SET', value=Publication(publish_address=49156, app_key_index=1, ...)
Diff(element=1, model=LightCTLTemperatureServer, state='app_keys',
action=ADD, value=1)
Diff(element=1, model=LightCTLTemperatureServer, state='subscriptions',
action=ADD, value=49156)
2022
bluetooth Mesh models
a provisioner's perspective
Mesh models: provisioner perspective
By Michał Lowas-Rzechonek
Mesh models: provisioner perspective
- 266