Thanks for sharing this, Vaibhav! I’ll try to make a few comments based on the interaction between Nexus Channel and AIrlink, and maybe ask a few questions along the way. In general, it looks like (correct me if I’m off here) that Airlink is built around sort of ‘bundled’ resources, that is, a number of distinct, conceptually separate resource types (client info, PAYG credit, device status, etc) are exposed together as ‘one’ Bluetooth service. That makes sense, if I’m reading the first part correctly here! I think it would be great to capture any new info/actions that can be shared between devices (client info related, or OpenPaygo Token Entry, for example) as distinct resource types, and add them to the resource type registry:
Then, they’d potentially be able to be used in multimode (a gateway supporting both Airlink devices and OpenPaygo Link devices simultaneously, for instance) or non-Airlink integrations (OpenPaygo Link only) as well. That might also simplify the Airlink spec a bit, by allowing you to specify what resource types (and what attributes of those resource types) are exposed on each service, rather than writing back out individual attributes in the spec.
I’m going to go a bit deeper on a few aspects of the spec here:
Advertising Packet
The constraint on size for this packet does make the ‘custom format’ pretty important - I understand the preference here to not publish the keys for resource properties in the packet each time (e.g. you’re able to parse the value of ‘adf’ by position only, no need to send the key ‘adf’ as well). The note about the gateway expanding this out into a ‘proper’ resource (with key names for each property value) makes sense in that context, to me at least. Related to this, I’m not sure that an ‘rtr’ is necessary in the advertising packet – this isn’t exposing a valid resource (or collection of resources), as there are only values, no property keys here (however, the ‘decompressed’ representation of the resource that the gateway creates might have an rtr?).
Without making ‘adf’ (or an equivalent version field) mandatory in the packet, it may become difficult to coordinate parser versions for the advertising packet over time. Specifically, if the ‘adf’ isn’t mandatory, it might be difficult to figure out what ‘version’ of the advertising packet that different devices using different iterations of Airlink are sending. Suggest making the ‘adf’ field mandatory, and maintaining an ‘official’ Airlink list of packet contents for each ‘adf’ version that you end up defining (e…g ‘adf=1 exposes these properties from resource type A, these properties from resource type B, etc).
Consider making this advertising packet a fully-compliant CBOR array, so that the data can be parsed with standard CBOR parsers. Consider restructuring the packet so that the version/format identifier (‘adf’) come first, so that a parser can always interpret the first two bytes as ‘adf’ version, and pass the remaining packet data to an ‘adf’ version-specific parser as needed. Related to this, you could consider using the integer representation of timestamps (based on the Linux epoch in UTC), which doesn’t introduce any MySQL dependence, and take up less space than the MySQL representation.
For example, here is an annotated version of the advertising packet that can be read by a CBOR parser directly, that has all of the information currently specified in the “PUE Advertisement”, and is 23 bytes long:
Diagnostic format:
[54321, 4210818301, 21, 55, 129, 1629830325, 65340, 15]
Raw Bytes/CBOR encoded (23 bytes):
88 # array(8)
19 D431 # unsigned(54321) - first element = adf
1A FAFBFCFD # unsigned(4210818301) - 'did' (4-byte/uint32 device ID
15 # unsigned(21) - 'err' device error
18 37 # unsigned(55) - 'ds' device status
18 81 # unsigned(129) - 'fv' firmware version
1A 61253CB5 # unsigned(1629830325) - 'pts' in seconds since the epoch
19 FF3C # unsigned(65340) - 're' (cr) PAYG credit remaining
0F # unsigned(15) - 'un' PAYG credit units
I understand the need to keep advertising packets as short as practical to keep power consumption lower - so the cost of having to write a custom parser for that is arguably worth it if it keeps from needing to use extended advertising packets. The above is just an attempt to see what it would take to use a ‘standard’ CBOR array of values, so the parser only needs to know how to read CBOR (and how to interpret the adf), but the spec might already be there and I’m misreading it.
Related Question: Can devices that are not using PAYG enforcement use AirLink, or is it required that AirLink devices have some form of PAYG enforcement? I’m trying to understand whether it would be permissible to have an AirLink device in an installation which has no PAYG metering, but simply reports its own usage data (but maybe there are other PAYG devices connected to the same gateway). Depending on what your vision is and how tightly you want to scope the protocol, you might want to consider making some of the PAYG attributes optional on this advertising resource.
Another way to ask that question is - in addition to the current ‘adf’ format (which makes the PAYG-related attributes ‘mandatory’), do you think its feasible to consider future development/expansion of a new ‘non-metered’ advertising packet ‘adf’ (which would tell the parser to not look for PAYG attributes in the advertising packet) that a non-metered, non-PAYG device could use to participate in the same AirLink network? Even for PAYG devices, do you feel that sending this info in every advertisement is necessary, compared to simply querying the non-gateway devices when needed to check their PAYG credit (assuming that the gateway can determine whether they support PAYG credit or not by looking at nx/res).
Services and resource models
Looking over the existing Bluetooth services (PUE Use Service, Device Config Service, Device Discovery Services), it looks like these are essentially composed of multiple Nexus Channel ‘resources’ put together in a single resource (as the AirLink spec mentions, the OCF bridging guidelines also suggest this).
To separate concerns, how do you feel about filing those individual resources for addition to the Nexus Channel resource registry (giving them “Resource Type” IDs/rtrs) as well as filing for new ‘combined’ Airlink specific resource types (that are special resources made up of 2 or more ‘individual’ resources?). I know that OCF also has Composite Resource Types (Section 5.7), but I don’t want to suggest adding more overhead than necessary to the AirLink system - and the ‘composite’ approach would likely lead to an additional round-trip of data (e.g. one round trip to “GET” the composite resource, then another round-trip to “GET” the subresource), whereas defining AirLink specific ‘combined’ resources that take on all of the attributes of separate ‘individual’ resources can reduce the roundtrips.
I am not proposing making different characteristics or services than what the spec currently defines, I’m just seeing how you feel about trying to capture some of the separate groups of properties here as individual Nexus Channel resource types, to improve reusability and allow other developers to compose the pieces they might want/need for other use cases in the future.
Specifically, I’d suggest considering the following as resource types that might be added to the Nexus Channel Core Resource Registry, and assigning individual new RTRs to each of these device resources. Note that only GET and POST are ‘supported’ by Nexus Channel (based on the fact that existing OCF resources appear to avoid PUT for idempotent updates), but that really only matters for the Nexus Channel resource model definitions here, I think.
Separate Resource Types currently in Use by Airlink (as far as I can tell)
-
New resource type - “Client Provisioning”
-
[Required for POST, required on GET] Customer name (‘cn’)
-
[Required for POST, required on GET] Customer phone (‘cp’)
-
Sidenote: Does this need to exist on the device as a resource? It seems like something a backend would manage, not something that is ever pushed down to the device (e.g. at registration, a backend associates device A with client B). You might be able to eliminate this entirely unless the non-gateway device itself needs to store this info to make some decisions (rather than a backend simply storing an association between that client and the device).
-
New resource type - “Device Provisioning”
-
[Required] 6-Byte Device ID
-
[Required] Provisioning Status (‘pst’)
-
[Optional] IoT Backend Type (int enum, e.g. ThingsBoard, etc)
-
[Optional] IoT Backend Auth Token (‘sat’)
-
New resource type -“OpenPaygo Token Entry”
-
[Required] Token String
-
[Required] Last token received - note, you might consider using ‘seconds since last token entered’, to avoid needing to keep track of / sync actual clock time across devices.
-
(required) ‘lcr’ last added PAYG credit (this is not applicable to general PAYG use cases, as credit is not always added, it might be subtracted or directly ‘set’ to a value - but this might be a good property of this new ‘OpenPaygo Token Entry’ resource if its something you need)
-
New resource type - “Device Health/Status” , to capture the error data mentioned in the spec.
-
Device error (err)
-
Device erd
-
PAYG Credit Resource
-
Consider using the existing draft PAYG resource type model, but further constrain it in AirLink to only certain units and ranges (e.g. AirLink will not report PAYG credit units > 65535, e.g.). Existing resource model draft has PAYG units and PAYG credit remaining as ‘required’ fields.
-
If the existing draft resource model won’t work, consider extending it with AirLink specific optional properties, or creating a new resource model if the paradigm is too different
-
Some fields in the Airlink spec are specific to OpenPaygo Token or token PAYG credit management in general, and would be better added to the new ‘OpenPaygo Token Entry” resource, rather than the general PAYG resource (e.g. starting code, last entered token, last entered token value, etc)
-
Power Used/Consumed - Consider reusing or revising the energy consumption resource type to accommodate the relevant info provided by PUE timeseries resource
-
Power Generated - Consider reusing or revising the energy generation resource type to accommodate the relevant info provided by PUE timeseries resource
-
Productive Use Info - Consider a resource that provides this info, but also consider - would it be possible to separate this into something more specific, e.g. a ‘pump’ resource that indicates flow? If not, it might make sense for the productive use metric to include units/productive use machine type.
-
Battery - Consider using the existing battery resource type fields besides ‘vb’ and ‘cp’. For example, if ‘ft’ (fault) is insufficient to meet the use case you see for ‘bh’ (battery health), suggest extending/improving the existing battery resource to have a new optional ‘bh’ field. Similar for ‘pmax’,‘pmin’, and ‘tchg’ (consider extending the existing battery model with these properties).
-
Consider using ‘ss’ (‘seconds since’) instead of ‘ts’ (absolute/UTC timestamp): This might depend on the Airlink device capabilities, but as specified, the assumption appears to be that Airlink devices all have a fairly accurate notion of the global wall-clock time. More constrained devices won’t always have an accurate wall clock, but can generally keep track of elapsed real time (seconds) in smaller increments (minutes/hours at a time). By specifying sample times in ‘seconds since sampled’ rather than timestamps, you would reduce the transmitted size (from 6 bytes down to just 1 byte, for samples taken in the last few minutes), and also support more constrained devices. Of course, the gateway device could still easily convert the ‘seconds since sampled’ into a wall-clock sample time (assuming there is fairly small, e.g. under a few seconds latency, between gateway requesting data from a non-gateway device, and the non-gateway device responding).
Related question - is the notion here that ‘ts’ represents the timestamp of all information in the PUE resource, so the measurements must all be taken at the exact same time?
-
Location - consider introducing a new Nexus Channel resource type in the registry that has lat/long/accuracy, with room for that ‘array’ (for historical values?) mentioned in the Airlink spec.
-
Historical time series data - There is an existing resource type draft (‘samplelog’) that provides one way to expose a series of sampled data as a Nexus Channel resource. However, its just a draft - I’d suggest we try to use it here, or update the resource type to meet your exact needs.
If the above understanding of ‘separate’ resource types is correct (check me on that), then is it correct to say that the PUE resources are composed as follows?
PUE Timeseries Resource Type, contained subtypes
- (existing) Battery
- (new) Location
- (existing) Power Generation
- (existing) Power Consumption
- (new) Productive Use
- (new) Device Health/Status
PUE PAYG Resource Type, contained subtypes
-
(new) OpenPaygo Token Resource
-
(new) Device Provisioning Resource
-
(Existing) PAYG credit resource
PUE Provisioning Resource Type, contained subtypes
- (new) Client Provisioning
- (new) Device Provisioning
- (new) OpenPaygo Token resource
Security and PAYG Credit Management - Sidenote
The approach to transmit credit via tokens to each individual device is possible (e.g. OpenPaygo Token Entry resource type), but there is another approach that lets you push updates (PAYG or otherwise) to the devices without needing to send tokens, while still remaining secure against replay and MITM attacks. This is the functionality provided by Nexus Channel Links. Basically, these provide application layer security between devices by using a secure key negotiation mechanism (secure as in no keys or cryptographically sensitive data are transmitted between the devices), after which two devices have a derived shared secret ‘link’ key (unique to the link between those two specific devices). That key is used to secure request/response messages (by providing a monotonically increasing nonce, and generating/appending a MAC generated using that nonce, the message payload, and the CoAP type code). The secure link is established between two devices when a ‘controller’ device receives a specific ‘origin command’ (a token keyed specifically to that controller, with information that also lets it authenticate to the specific targeted ‘accessory’ to link to). The controller then initiates the link handshake process, and the target connected accessory to link either accepts/validates it, or does not. One the link is established, both devices use the newly derived (but never exposed on the wire) secret key to secure CoAP messages sent between them.
It doesn’t require any special manufacturer authorization/steps/process to set up the link compared to generating a PAYG keycode - the same 16-byte symmetric keys provisioned inside for token acceptance (OpenPaygo Token, Nexus Keycode, etc) can be used to enable accepting/validating origin commands to establish a link.
This security is independent of any lower-level transport security (or Bluetooth pairing), and ensures that two ‘linked’ devices can securely communicate regardless of their connectivity mode (OpenPaygo Link, AirLink, CAN, etc).
You can see this in action with two dev boards here: Nexus Channel Link Security Hardware Demo - YouTube , although the code shown there hasn’t been pushed to the public repository yet (we’re looking to coordinate it with another release).
That video (and the reference code) demonstrate using Nexus Channel links to send secured request messages from a controller device to accessory devices, and handle secured responses sent back - specifically, the accessory devices are configured to only accept secured POST requests to their PAYG credit resource (ignoring unsecured ones).
So, you might want to consider reusing that functionality, and only keeping the OpenPaygo Token entry on the gateway device if you need it for a backup to deliver credit if the gateway internet access is out - or just skipping PAYG credit token support entirely if you can rely on pushing credit updates for each device from the backend to the gateway. As long as the gateway has secure links established to each other Airlink device (which is done via interaction between the ‘link handshake’ resource of the gateway/controller and each downstream ‘accessory’ device), you can rely on MITM and replay-resistant control of PAYG credit to each downstream device with no token entry needed.