How to: CBOR
CHESTER uses CBOR to encode and decode transmitted data. Thanks to CBOR, you can describe how the transmitted data will look like using the YAML file, then in your C code, you use the keys from this YAML file. Finally, you upload the same YAML file to the HARDWARIO Cloud, which will automatically decode the received data and convert them to JSON.
To use CBOR with CHESTER you need to:
- Create a
codec\cbor-decoder.yaml
file in your application folder that describes the JSON attributes. - Upload the YAML file to the HARDWARIO Cloud using
hardwario cloud
CLI tool. - Header file
msg_key.h
is automatically generated whenwest build
is called. - Use these definitions in
app_cbor.c
and add the needed data.
You can see more practical examples in CHESTER SDK in the catalog applications chester/applications/*
folder or in the chester/samples/lte_cbor
sample.
YAML
In the YAML you define the name of the keys that will later be used in decoded JSON. However, the YAML file can define other things:
- Modificators
- Enumerators
- Time series data, periodical (TSP) or with time offset (TSO)
Modificators
Modificators are:
add
sub
mul
div
fpp
- floating point decimal places in JSONkey
- rename the JSON key
The example below creates a key with name temperature
. In CHESTER you need to multiply value by 100, then in HARDWARIO Cloud it is automatically divided by 100, and in the final JSON, the number has two decimal places.
- temperature:
- div: 100
- fpp: 2
The CHESTER C code will look like this:
zcbor_uint32_put(zs, MSG_KEY_TEMPERATURE);
zcbor_int32_put(zs, g_app_data.therm_temperature * 100.f);
Output JSON will be:
"temperature": 21.75
Enumerators
Define string values and send them efficiently as an integer.
- backup_state:
- enum:
- inactive
- active
The CHESTER C code will look like this:
zcbor_uint32_put(zs, MSG_KEY_BACKUP_STATE);
zcbor_uint32_put(zs, g_app_data.backup.line_present ? 1 : 0);
Output JSON will be:
"backup_state": "active"
Time Series Period
Time Series Period (TSP) efficiently encodes value or multiple values with the timestamps. In the CHESTER, you only send reference timestamp, period and values. The decoder automatically adds an absolute timestamp to each value.
- measurements_val:
- tsp:
- avg:
- mdn:
The CHESTER C code will look like this:
zcbor_uint32_put(zs, MSG_KEY_MEASUREMENTS_VAL);
{
zcbor_list_start_encode(zs, ZCBOR_VALUE_IS_INDEFINITE_LENGTH);
zcbor_uint64_put(zs, g_app_data.counter.timestamp); // unix timestamp 1679321760
zcbor_uint32_put(zs, g_app_config.counter_interval_aggreg); // 30 seconds
for (int i = 0; i < g_app_data.counter.measurement_count; i++) {
zcbor_uint64_put(zs, g_app_data.counter.measurements[i].avg);
zcbor_uint64_put(zs, g_app_data.counter.measurements[i].mdn);
}
zcbor_list_end_encode(zs, ZCBOR_VALUE_IS_INDEFINITE_LENGTH);
}
Output JSON will be:
measurements_val:
[
{
"timestamp": 1679321760,
"avg": 123,
"mdn": 456
},
{
"timestamp": 1679321790,
"avg": 123,
"mdn": 456
},
...
]
Notice that in the JSON the timestamp for each sample is absolute. It is computed from the reference timestamp 1679321760 of the first sample; then next sample has a timestamp bigger by 30 seconds 1679321790.
Time Series Offset
Time Series Offset (TSO) is similar to the previous Time Series Period (TSP). However, the time between samples is not periodic, and every sample has its own offset relative to the previous one.
This code also shows how you can combine modificators inside the TSO.
- trigger_events:
- key: "events"
- tso:
- type:
- enum:
- deactivated
- activated
The CHESTER C code will look like this:
int64_t timestamp_abs = g_app_data.trigger.events[0].timestamp;
zcbor_uint32_put(zs, MSG_KEY_TRIGGER_EVENTS);
{
zcbor_list_start_encode(zs, ZCBOR_VALUE_IS_INDEFINITE_LENGTH);
/* TSO absolute timestamp */
zcbor_int64_put(zs, timestamp_abs);
for (int i = 0; i < g_app_data.trigger.event_count; i++) {
/* TSO offset timestamp */
zcbor_int64_put(zs, g_app_data.trigger.events[i].timestamp - timestamp_abs);
zcbor_uint32_put(zs, g_app_data.trigger.events[i].is_active ? 1 : 0);
}
zcbor_list_end_encode(zs, ZCBOR_VALUE_IS_INDEFINITE_LENGTH);
}
Output JSON will be:
events:
[
{
"timestamp": 1679321760,
"event": "activated"
},
{
"timestamp": 1679321765,
"event": "deactivated"
},
{
"timestamp": 1679321780,
"event": "activated"
},
...
]