kopia lustrzana https://github.com/micropython/micropython-lib
senml: Add SenML library.
This is a new library that doesn't follow any existing API. The library is originally from https://github.com/kpn-iot/senml-micropython-library.pull/541/head
rodzic
52fcb8e4a7
commit
9ee02576cb
|
@ -0,0 +1,12 @@
|
|||
# Introduction
|
||||
|
||||
The SenML library helps you create and parse [senml documents](https://tools.ietf.org/html/draft-ietf-core-senml-13)
|
||||
in both json and cbor format.
|
||||
|
||||
# key features
|
||||
|
||||
- Object oriented design.
|
||||
- built in support for [senml's unit registry](https://tools.ietf.org/html/draft-ietf-core-senml-12#section-12.1)
|
||||
- extensible for new data types
|
||||
- direct support to read/write in json and cbor format.
|
||||
- automatically adjusts record data with respect to base time, base value & base sum.
|
|
@ -0,0 +1 @@
|
|||
theme: jekyll-theme-slate
|
|
@ -0,0 +1,13 @@
|
|||
Welcome to the API documet site for the micro-python SenML library.
|
||||
|
||||
The following api sections are available:
|
||||
|
||||
- [senml-base](./senml_base): the base class for all senml objects.
|
||||
- [senml-pack](./senml_pack): the class that represents root documents.
|
||||
- [senml-record](./senml_record): the class that stores sensor measurements
|
||||
- [senml-unit](./senml_unit): the list of all unit names that can be used.
|
||||
|
||||
|
||||
|
||||
Copyright (c) 2018 KPN
|
||||
Copyright (c) 2023 MicroPython
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
# senml_base Module
|
||||
|
||||
|
||||
## senml_base.SenmlBase Objects
|
||||
|
||||
|
||||
the base class for all senml objects.
|
|
@ -0,0 +1,216 @@
|
|||
|
||||
# senml_pack Module
|
||||
|
||||
|
||||
## senml_pack.SenmlPack Objects
|
||||
|
||||
|
||||
represents a senml pack object. This can contain multiple records but also other (child) pack objects.
|
||||
When the pack object only contains records, it represents the data of a device.
|
||||
If the pack object has child pack objects, then it represents a gateway
|
||||
|
||||
### __enter__
|
||||
|
||||
```Python
|
||||
__enter__(self)
|
||||
```
|
||||
|
||||
for supporting the 'with' statement
|
||||
|
||||
|
||||
_returns_: self
|
||||
|
||||
### __exit__
|
||||
|
||||
```Python
|
||||
__exit__(self, exc_type, exc_val, exc_tb)
|
||||
```
|
||||
|
||||
when destroyed in a 'with' statement, make certain that the item is removed from the parent list.
|
||||
|
||||
|
||||
_returns_: None
|
||||
|
||||
### __init__
|
||||
|
||||
```Python
|
||||
__init__(self, name, callback=None)
|
||||
```
|
||||
|
||||
initialize the object
|
||||
|
||||
_parameters:_
|
||||
|
||||
- `name:` {string} the name of the pack
|
||||
|
||||
### __iter__
|
||||
|
||||
```Python
|
||||
__iter__(self)
|
||||
```
|
||||
|
||||
|
||||
|
||||
### add
|
||||
|
||||
```Python
|
||||
adds the item to the list of records
|
||||
```
|
||||
|
||||
|
||||
_parameters:_
|
||||
|
||||
- `item:` {SenmlRecord} the item that needs to be added to the pack
|
||||
|
||||
|
||||
_returns_: None
|
||||
|
||||
### base_sum
|
||||
|
||||
the base sum of the pack.
|
||||
|
||||
|
||||
_returns_: a number
|
||||
|
||||
### base_time
|
||||
|
||||
Get the base time assigned to this pack object.
|
||||
While rendering, this value will be subtracted from the value of the records.
|
||||
|
||||
|
||||
_returns_: unix time stamp representing the base time
|
||||
|
||||
### base_value
|
||||
|
||||
the base value of the pack. The value of the records will be subtracted by this value during rendering.
|
||||
While parsing, this value is added to the value of the records.
|
||||
|
||||
|
||||
_returns_: a number
|
||||
|
||||
### clear
|
||||
|
||||
```Python
|
||||
clear(self)
|
||||
```
|
||||
clear the list of the pack
|
||||
|
||||
|
||||
|
||||
_returns_: None
|
||||
|
||||
### do_actuate
|
||||
|
||||
```Python
|
||||
do_actuate(self, raw, naming_map, device=None)
|
||||
```
|
||||
|
||||
called while parsing incoming data for a record that is not yet part of this pack object.
|
||||
adds a new record and raises the actuate callback of the pack with the newly created record as argument
|
||||
|
||||
_parameters:_
|
||||
|
||||
- naming_map:
|
||||
- `device:` optional: if the device was not found
|
||||
- `raw:` the raw record definition, as found in the json structure. this still has invalid labels.
|
||||
|
||||
|
||||
_returns_: None
|
||||
|
||||
### from_cbor
|
||||
|
||||
```Python
|
||||
from_cbor(self, data)
|
||||
```
|
||||
|
||||
parse a cbor data byte array to a senml pack structure.
|
||||
|
||||
_parameters:_
|
||||
|
||||
- `data:` a byte array.
|
||||
|
||||
|
||||
_returns_: None
|
||||
|
||||
### from_json
|
||||
|
||||
```Python
|
||||
from_json(self, data)
|
||||
```
|
||||
|
||||
parse a json string and convert it to a senml pack structure
|
||||
|
||||
_parameters:_
|
||||
|
||||
- `data:` a string containing json data.
|
||||
|
||||
|
||||
_returns_: None, will call the appropriate callback functions.
|
||||
|
||||
|
||||
|
||||
### remove
|
||||
|
||||
```Python
|
||||
remove(self, item)
|
||||
```
|
||||
removes the item from the pack
|
||||
|
||||
|
||||
_parameters:_
|
||||
|
||||
- `item:` {SenmlRecord} the item that needs to be removed
|
||||
|
||||
|
||||
_returns_: None
|
||||
|
||||
### to_cbor
|
||||
|
||||
```Python
|
||||
to_cbor(self)
|
||||
```
|
||||
|
||||
render the content of this object to a cbor byte array
|
||||
|
||||
|
||||
_returns_: a byte array
|
||||
|
||||
### to_json
|
||||
|
||||
```Python
|
||||
to_json(self)
|
||||
```
|
||||
|
||||
render the content of this object to a string.
|
||||
|
||||
|
||||
_returns_: a string representing the senml pack object
|
||||
|
||||
## senml_pack.SenmlPackIterator Objects
|
||||
|
||||
|
||||
an iterator to walk over all records in a pack
|
||||
|
||||
### __init__
|
||||
|
||||
```Python
|
||||
__init__(self, list)
|
||||
```
|
||||
|
||||
|
||||
|
||||
### __iter__
|
||||
|
||||
```Python
|
||||
__iter__(self)
|
||||
```
|
||||
|
||||
|
||||
|
||||
### __next__
|
||||
|
||||
```Python
|
||||
__next__(self)
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
|
||||
# senml_record Module
|
||||
|
||||
|
||||
## senml_record.SenmlRecord Objects
|
||||
|
||||
|
||||
represents a single value in a senml pack object
|
||||
|
||||
### __enter__
|
||||
|
||||
```Python
|
||||
__enter__(self)
|
||||
```
|
||||
|
||||
for supporting the 'with' statement
|
||||
|
||||
|
||||
_returns_: self
|
||||
|
||||
### __exit__
|
||||
|
||||
```Python
|
||||
__exit__(self, exc_type, exc_val, exc_tb)
|
||||
```
|
||||
|
||||
when destroyed in a 'with' statement, make certain that the item is removed from the parent list.
|
||||
|
||||
|
||||
_returns_: None
|
||||
|
||||
### __init__
|
||||
|
||||
```Python
|
||||
__init__(self, name, **kwargs)
|
||||
```
|
||||
|
||||
create a new senml record
|
||||
|
||||
_parameters:_
|
||||
|
||||
- `kwargs:` optional parameters:
|
||||
- value: the value to store in the record
|
||||
- time: the timestamp to use (when was the value measured)
|
||||
- name: the name of hte record
|
||||
- unit: unit value
|
||||
- sum: sum value
|
||||
- update_time: max time before sensor will provide an updated reading
|
||||
- callback: a callback function taht will be called when actuator data has been found. Expects no params
|
||||
|
||||
### do_actuate
|
||||
|
||||
```Python
|
||||
do_actuate(self, raw, naming_map)
|
||||
```
|
||||
|
||||
called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it.
|
||||
|
||||
_parameters:_
|
||||
|
||||
- `raw:` raw senml object
|
||||
|
||||
|
||||
_returns_: None
|
||||
|
||||
### sum
|
||||
|
||||
|
||||
|
||||
### time
|
||||
|
||||
get the time at which the measurement for the record was taken.
|
||||
|
||||
|
||||
_returns_: a unix time stamp. This is the absolute value, not adjusted to the base time of the pack.
|
||||
|
||||
### update_time
|
||||
|
||||
get the time at which the next measurement is expected to be taken for this record.
|
||||
|
||||
|
||||
_returns_: a unix time stamp. This is the absolute value, not adjusted to the base time of the pack.
|
||||
|
||||
### value
|
||||
|
||||
get the value currently assigned to the object
|
|
@ -0,0 +1,183 @@
|
|||
|
||||
# senml_unit Module
|
||||
|
||||
|
||||
## Functions
|
||||
|
||||
|
||||
|
||||
## senml_unit.SenmlUnits Objects
|
||||
|
||||
|
||||
|
||||
|
||||
##### `SENML_UNIT_ACCELERATION`
|
||||
|
||||
|
||||
##### `SENML_UNIT_AMPERE`
|
||||
|
||||
|
||||
##### `SENML_UNIT_BEATS`
|
||||
|
||||
|
||||
##### `SENML_UNIT_BECQUEREL`
|
||||
|
||||
|
||||
##### `SENML_UNIT_BEL`
|
||||
|
||||
|
||||
##### `SENML_UNIT_BIT`
|
||||
|
||||
|
||||
##### `SENML_UNIT_BIT_PER_SECOND`
|
||||
|
||||
|
||||
##### `SENML_UNIT_BPM`
|
||||
|
||||
|
||||
##### `SENML_UNIT_CANDELA`
|
||||
|
||||
|
||||
##### `SENML_UNIT_CANDELA_PER_SQUARE_METER`
|
||||
|
||||
|
||||
##### `SENML_UNIT_COULOMB`
|
||||
|
||||
|
||||
##### `SENML_UNIT_COUNTER`
|
||||
|
||||
|
||||
##### `SENML_UNIT_CUBIC_METER`
|
||||
|
||||
|
||||
##### `SENML_UNIT_CUBIC_METER_PER_SECOND`
|
||||
|
||||
|
||||
##### `SENML_UNIT_DECIBEL`
|
||||
|
||||
|
||||
##### `SENML_UNIT_DECIBEL_RELATIVE_TO_1_W`
|
||||
|
||||
|
||||
##### `SENML_UNIT_DEGREES_CELSIUS`
|
||||
|
||||
|
||||
##### `SENML_UNIT_DEGREES_LATITUDE`
|
||||
|
||||
|
||||
##### `SENML_UNIT_DEGREES_LONGITUDE`
|
||||
|
||||
|
||||
##### `SENML_UNIT_EVENT_RATE_PER_MINUTE`
|
||||
|
||||
|
||||
##### `SENML_UNIT_EVENT_RATE_PER_SECOND`
|
||||
|
||||
|
||||
##### `SENML_UNIT_FARAD`
|
||||
|
||||
|
||||
##### `SENML_UNIT_GRAM`
|
||||
|
||||
|
||||
##### `SENML_UNIT_GRAY`
|
||||
|
||||
|
||||
##### `SENML_UNIT_HENRY`
|
||||
|
||||
|
||||
##### `SENML_UNIT_HERTZ`
|
||||
|
||||
|
||||
##### `SENML_UNIT_JOULE`
|
||||
|
||||
|
||||
##### `SENML_UNIT_KATAL`
|
||||
|
||||
|
||||
##### `SENML_UNIT_KELVIN`
|
||||
|
||||
|
||||
##### `SENML_UNIT_KILOGRAM`
|
||||
|
||||
|
||||
##### `SENML_UNIT_LITER`
|
||||
|
||||
|
||||
##### `SENML_UNIT_LITER_PER_SECOND`
|
||||
|
||||
|
||||
##### `SENML_UNIT_LUMEN`
|
||||
|
||||
|
||||
##### `SENML_UNIT_LUX`
|
||||
|
||||
|
||||
##### `SENML_UNIT_METER`
|
||||
|
||||
|
||||
##### `SENML_UNIT_MOLE`
|
||||
|
||||
|
||||
##### `SENML_UNIT_NEWTON`
|
||||
|
||||
|
||||
##### `SENML_UNIT_OHM`
|
||||
|
||||
|
||||
##### `SENML_UNIT_PASCAL`
|
||||
|
||||
|
||||
##### `SENML_UNIT_PERCENTAGE_REMAINING_BATTERY_LEVEL`
|
||||
|
||||
|
||||
##### `SENML_UNIT_PH`
|
||||
|
||||
|
||||
##### `SENML_UNIT_RADIAN`
|
||||
|
||||
|
||||
##### `SENML_UNIT_RATIO`
|
||||
|
||||
|
||||
##### `SENML_UNIT_RELATIVE_HUMIDITY`
|
||||
|
||||
|
||||
##### `SENML_UNIT_SECOND`
|
||||
|
||||
|
||||
##### `SENML_UNIT_SECONDS_REMAINING_BATTERY_LEVEL`
|
||||
|
||||
|
||||
##### `SENML_UNIT_SIEMENS`
|
||||
|
||||
|
||||
##### `SENML_UNIT_SIEMENS_PER_METER`
|
||||
|
||||
|
||||
##### `SENML_UNIT_SIEVERT`
|
||||
|
||||
|
||||
##### `SENML_UNIT_SQUARE_METER`
|
||||
|
||||
|
||||
##### `SENML_UNIT_STERADIAN`
|
||||
|
||||
|
||||
##### `SENML_UNIT_TESLA`
|
||||
|
||||
|
||||
##### `SENML_UNIT_VELOCITY`
|
||||
|
||||
|
||||
##### `SENML_UNIT_VOLT`
|
||||
|
||||
|
||||
##### `SENML_UNIT_WATT`
|
||||
|
||||
|
||||
##### `SENML_UNIT_WATT_PER_SQUARE_METER`
|
||||
|
||||
|
||||
##### `SENML_UNIT_WEBER`
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
from senml import *
|
||||
|
||||
|
||||
def do_actuate(record):
|
||||
"""
|
||||
called when actuate_me receives a value.
|
||||
:return: None
|
||||
"""
|
||||
print(record.value)
|
||||
|
||||
|
||||
def generic_callback(record, **kwargs):
|
||||
"""
|
||||
a generic callback, attached to the device. Called when a record is found that has not yet been registered
|
||||
in the pack. When this callback is called, the record will already be added to the pack.
|
||||
:param record: the newly found record.
|
||||
:return: None
|
||||
"""
|
||||
print("found record: " + record.name)
|
||||
print("with value: " + str(record.value))
|
||||
|
||||
|
||||
pack = SenmlPack("device_name", generic_callback)
|
||||
actuate_me = SenmlRecord("actuator", callback=do_actuate)
|
||||
|
||||
pack.add(actuate_me)
|
||||
|
||||
json_data = '[{"bn": "device_name", "n":"actuator", "v": 10 }]'
|
||||
print(json_data)
|
||||
pack.from_json(json_data)
|
||||
|
||||
json_data = (
|
||||
'[{"bn": "device_name", "n":"actuator", "v": 20 }, {"n": "another_actuator", "vs": "a value"}]'
|
||||
)
|
||||
print(json_data)
|
||||
pack.from_json(json_data)
|
||||
|
||||
print('[{"bn": "device_name", "n":"temp", "v": 20, "u": "Cel" }]')
|
||||
# this represents the cbor json struct: [{-2: "device_name", 0: "temp", 1: "Cel", 2: 20}]
|
||||
cbor_data = bytes.fromhex("81A4216B6465766963655F6E616D65006474656D70016343656C0214")
|
||||
pack.from_cbor(cbor_data)
|
|
@ -0,0 +1,47 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
from senml import *
|
||||
import utime as time
|
||||
|
||||
|
||||
pack = SenmlPack("device_name")
|
||||
temp = SenmlRecord("temperature", unit=SenmlUnits.SENML_UNIT_DEGREES_CELSIUS, value=23.5)
|
||||
door_pos = SenmlRecord("doorPos", update_time=20, value=True)
|
||||
int_val = SenmlRecord("int_val", sum=100)
|
||||
|
||||
pack.add(temp)
|
||||
pack.add(door_pos)
|
||||
pack.add(int_val)
|
||||
|
||||
pack.base_time = time.time()
|
||||
pack.base_value = 5
|
||||
pack.base_sum = 50
|
||||
time.sleep(2)
|
||||
temp.time = time.time()
|
||||
|
||||
|
||||
print(pack.to_json())
|
|
@ -0,0 +1,39 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
from senml import *
|
||||
import utime as time
|
||||
|
||||
|
||||
pack = SenmlPack("device")
|
||||
|
||||
while True:
|
||||
with SenmlRecord(
|
||||
"test", value=1
|
||||
) as rec: # use a with statement to automatically remove the item from the list when it goes out of scope
|
||||
pack.add(rec)
|
||||
print(pack.to_json())
|
||||
time.sleep(1)
|
|
@ -0,0 +1,45 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
from senml import *
|
||||
import utime as time
|
||||
|
||||
|
||||
pack = SenmlPack("device_name")
|
||||
temp = SenmlRecord("temperature", unit=SenmlUnits.SENML_UNIT_DEGREES_CELSIUS, value=23.5)
|
||||
door_pos = SenmlRecord("doorPos", update_time=20, value=True)
|
||||
str_val = SenmlRecord("str val")
|
||||
|
||||
pack.add(temp)
|
||||
pack.add(door_pos)
|
||||
pack.add(str_val)
|
||||
|
||||
while True:
|
||||
temp.value = temp.value + 1.1
|
||||
door_pos.value = not door_pos.value
|
||||
str_val.value = "test"
|
||||
print(pack.to_json())
|
||||
time.sleep(1)
|
|
@ -0,0 +1,42 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
from senml import *
|
||||
import utime as time
|
||||
from cbor2 import decoder
|
||||
|
||||
pack = SenmlPack("device_name")
|
||||
|
||||
while True:
|
||||
with SenmlRecord(
|
||||
"test", value=10
|
||||
) as rec: # use a with statement to automatically remove the item from the list when it goes out of scope, generate a value for the record
|
||||
pack.add(rec)
|
||||
cbor_val = pack.to_cbor()
|
||||
print(cbor_val)
|
||||
print(cbor_val.hex())
|
||||
print(decoder.loads(cbor_val)) # convert to string again so we can print it.
|
||||
time.sleep(1)
|
|
@ -0,0 +1,133 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
from senml import *
|
||||
|
||||
import utime as time
|
||||
|
||||
|
||||
class Coordinates(SenmlRecord):
|
||||
def __init__(self, name, **kwargs):
|
||||
"""overriding the init function so we can initiate the 3 senml records that will represent lat,lon, alt"""
|
||||
self._lat = SenmlRecord(
|
||||
"lattitude", unit=SenmlUnits.SENML_UNIT_DEGREES_LATITUDE
|
||||
) # create these befor calling base constructor so that all can be init correctly from constructor
|
||||
self._lon = SenmlRecord("longitude", unit=SenmlUnits.SENML_UNIT_DEGREES_LONGITUDE)
|
||||
self._alt = SenmlRecord("altitude", unit=SenmlUnits.SENML_UNIT_METER)
|
||||
super(Coordinates, self).__init__(
|
||||
name, **kwargs
|
||||
) # need to call base init, to make certain all is ok.
|
||||
|
||||
def _check_value_type(self, value):
|
||||
"""overriding the check on value type to make certain that only an array with 3 values is assigned: lat,lon/alt"""
|
||||
if not value == None:
|
||||
if not isinstance(value, list):
|
||||
raise Exception("invalid data type: array with 3 elements expected lat, lon, alt")
|
||||
|
||||
def _build_rec_dict(self, naming_map, appendTo):
|
||||
"""
|
||||
override the rendering of the senml data objects. These will be converted to json or cbor
|
||||
:param naming_map: {dictionary} a map that determines the field names, these are different for json vs cbor
|
||||
:param appendTo: {list} the result list
|
||||
:return: None
|
||||
"""
|
||||
self._lat._build_rec_dict(naming_map, appendTo)
|
||||
self._lon._build_rec_dict(naming_map, appendTo)
|
||||
self._alt._build_rec_dict(naming_map, appendTo)
|
||||
|
||||
@SenmlRecord.value.setter
|
||||
def value(self, value):
|
||||
"""set the current value.
|
||||
this is overridden so we can pass on the values to the internal objects. It's also stored in the parent
|
||||
so that a 'get-value' still returns the array.
|
||||
"""
|
||||
self._value = (
|
||||
value # micropython doesn't support calling setter of parent property, do it manually
|
||||
)
|
||||
if value:
|
||||
self._lat.value = value[0]
|
||||
self._lon.value = value[1]
|
||||
self._alt.value = value[2]
|
||||
else:
|
||||
self._lat.value = None
|
||||
self._lon.value = None
|
||||
self._alt.value = None
|
||||
|
||||
@SenmlRecord.time.setter
|
||||
def time(self, value):
|
||||
"""set the time stamp.
|
||||
this is overridden so we can pass on the values to the internal objects.
|
||||
"""
|
||||
self._check_number_type(
|
||||
value, "time"
|
||||
) # micropython doesn't support calling setter of parent property, do it manually
|
||||
self._time = value
|
||||
self._lat.time = value
|
||||
self._lon.time = value
|
||||
self._alt.time = value
|
||||
|
||||
@SenmlRecord.update_time.setter
|
||||
def update_time(self, value):
|
||||
"""set the time stamp.
|
||||
this is overridden so we can pass on the values to the internal objects.
|
||||
"""
|
||||
self._check_number_type(
|
||||
value, "update_time"
|
||||
) # micropython doesn't support calling setter of parent property, do it manually
|
||||
self._update_time = value
|
||||
self._lat.update_time = value
|
||||
self._lon.update_time = value
|
||||
self._alt.update_time = value
|
||||
|
||||
@SenmlRecord._parent.setter
|
||||
def _parent(self, value):
|
||||
"""set the time stamp.
|
||||
this is overridden so we can pass on the values to the internal objects.
|
||||
This is needed so that the child objects can correctly take base time (optionally also base-sum, base-value) into account
|
||||
"""
|
||||
self.__parent = (
|
||||
value # micropython doesn't support calling setter of parent property, do it manually
|
||||
)
|
||||
self._lat._parent = value
|
||||
self._lon._parent = value
|
||||
self._alt._parent = value
|
||||
|
||||
|
||||
pack = SenmlPack("device_name")
|
||||
loc = Coordinates("location")
|
||||
loc2 = Coordinates("location", value=[52.0259, 5.4775, 230])
|
||||
pack.add(loc)
|
||||
pack.add(loc2)
|
||||
|
||||
print(loc._parent.name)
|
||||
|
||||
loc.value = [51.0259, 4.4775, 10]
|
||||
print(pack.to_json())
|
||||
|
||||
pack.base_time = time.time() # set a base time
|
||||
time.sleep(2)
|
||||
loc.time = time.time() # all child objects will receive the time value
|
||||
print(pack.to_json())
|
|
@ -0,0 +1,50 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
from senml import *
|
||||
import utime as time
|
||||
|
||||
gateway_pack = SenmlPack("gateway")
|
||||
|
||||
dev1_pack = SenmlPack("dev1")
|
||||
dev2_pack = SenmlPack("dev2")
|
||||
|
||||
temp = SenmlRecord("temperature", unit=SenmlUnits.SENML_UNIT_DEGREES_CELSIUS, value=23.5)
|
||||
door_pos = SenmlRecord("doorPos", update_time=20, value=True)
|
||||
str_val = SenmlRecord("str val")
|
||||
|
||||
gateway_pack.add(temp)
|
||||
gateway_pack.add(dev1_pack)
|
||||
gateway_pack.add(dev2_pack)
|
||||
dev1_pack.add(door_pos)
|
||||
dev2_pack.add(str_val)
|
||||
|
||||
while True:
|
||||
temp.value = temp.value + 1.1
|
||||
door_pos.value = not door_pos.value
|
||||
str_val.value = "test"
|
||||
print(gateway_pack.to_json())
|
||||
time.sleep(1)
|
|
@ -0,0 +1,75 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
from senml import *
|
||||
|
||||
|
||||
def do_actuate(record):
|
||||
"""
|
||||
called when actuate_me receives a value.
|
||||
:return: None
|
||||
"""
|
||||
print("for known device: ")
|
||||
print(record.value)
|
||||
|
||||
|
||||
def device_callback(record, **kwargs):
|
||||
"""
|
||||
a generic callback, attached to the device. Called when a record is found that has not yet been registered
|
||||
in the pack. When this callback is called, the record will already be added to the pack.
|
||||
:param kwargs: optional extra parameters
|
||||
:param record: the newly found record.
|
||||
:return: None
|
||||
"""
|
||||
print("found record: " + record.name)
|
||||
print("with value: " + record.value)
|
||||
|
||||
|
||||
def gateway_callback(record, **kwargs):
|
||||
"""
|
||||
a generic callback, attached to the device. Called when a record is found that has not yet been registered
|
||||
in the pack. When this callback is called, the record will already be added to the pack.
|
||||
:param record: the newly found record.
|
||||
:param kwargs: optional extra parameters (device can be found here)
|
||||
:return: None
|
||||
"""
|
||||
if "device" in kwargs and kwargs["device"] != None:
|
||||
print("for device: " + kwargs["device"].name)
|
||||
else:
|
||||
print("for gateway: ")
|
||||
print("found record: " + record.name)
|
||||
print("with value: " + str(record.value))
|
||||
|
||||
|
||||
gateway = SenmlPack("gateway_name", gateway_callback)
|
||||
device = SenmlPack("device_name", device_callback)
|
||||
actuate_me = SenmlRecord("actuator", callback=do_actuate)
|
||||
|
||||
gateway.add(device)
|
||||
device.add(actuate_me)
|
||||
gateway.from_json(
|
||||
'[{"bn": "gateway_name", "n":"temp", "v": 22},{"n": "gateway_actuator", "vb": true}, {"bn": "device_name", "n":"actuator", "v": 20 }, {"n": "another_actuator", "vs": "a value"}, {"bn": "device_2", "n":"temp", "v": 20 }, {"n": "actuator2", "vs": "value2"}]'
|
||||
)
|
|
@ -0,0 +1,53 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
from senml import *
|
||||
import utime as time
|
||||
|
||||
pack = SenmlPack("device_name")
|
||||
|
||||
double_val = SenmlRecord("double", value=23.5)
|
||||
int_val = SenmlRecord("int", value=23)
|
||||
bool_val = SenmlRecord("bool", value=True)
|
||||
str_val = SenmlRecord("str val", value="test")
|
||||
bytes_val = SenmlRecord("bytes", value=bytearray(b"00 1e 05 ff"))
|
||||
|
||||
# invalid value
|
||||
try:
|
||||
invalid = SenmlRecord("invalid", value={"a": 1})
|
||||
except Exception as error:
|
||||
print(error)
|
||||
|
||||
|
||||
pack.add(double_val)
|
||||
pack.add(int_val)
|
||||
pack.add(bool_val)
|
||||
pack.add(str_val)
|
||||
pack.add(bytes_val)
|
||||
|
||||
while True:
|
||||
print(pack.to_json())
|
||||
time.sleep(1)
|
|
@ -0,0 +1,5 @@
|
|||
metadata(version="0.1.0")
|
||||
|
||||
require("cbor2")
|
||||
|
||||
package("senml")
|
|
@ -0,0 +1,30 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
from .senml_base import SenmlBase
|
||||
from .senml_pack import SenmlPack
|
||||
from .senml_record import SenmlRecord
|
||||
from .senml_unit import SenmlUnits
|
|
@ -0,0 +1,30 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
class SenmlBase(object):
|
||||
"""
|
||||
the base class for all senml objects.
|
||||
"""
|
|
@ -0,0 +1,360 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
from senml.senml_record import SenmlRecord
|
||||
from senml.senml_base import SenmlBase
|
||||
import ujson
|
||||
from cbor2 import encoder
|
||||
from cbor2 import decoder
|
||||
|
||||
|
||||
class SenmlPackIterator:
|
||||
"""an iterator to walk over all records in a pack"""
|
||||
|
||||
def __init__(self, list):
|
||||
self._list = list
|
||||
self._index = 0
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
if self._index < len(self._list):
|
||||
res = self._list[self._index]
|
||||
self._index += 1
|
||||
return res
|
||||
else:
|
||||
raise StopIteration()
|
||||
|
||||
|
||||
class SenmlPack(SenmlBase):
|
||||
"""
|
||||
represents a sneml pack object. This can contain multiple records but also other (child) pack objects.
|
||||
When the pack object only contains records, it represents the data of a device.
|
||||
If the pack object has child pack objects, then it represents a gateway
|
||||
"""
|
||||
|
||||
json_mappings = {
|
||||
"bn": "bn",
|
||||
"bt": "bt",
|
||||
"bu": "bu",
|
||||
"bv": "bv",
|
||||
"bs": "bs",
|
||||
"n": "n",
|
||||
"u": "u",
|
||||
"v": "v",
|
||||
"vs": "vs",
|
||||
"vb": "vb",
|
||||
"vd": "vd",
|
||||
"s": "s",
|
||||
"t": "t",
|
||||
"ut": "ut",
|
||||
}
|
||||
|
||||
def __init__(self, name, callback=None):
|
||||
"""
|
||||
initialize the object
|
||||
:param name: {string} the name of the pack
|
||||
"""
|
||||
self._data = []
|
||||
self.name = name
|
||||
self._base_value = None
|
||||
self._base_time = None
|
||||
self._base_sum = None
|
||||
self.base_unit = None
|
||||
self._parent = None # a pack can also be the child of another pack.
|
||||
self.actuate = callback # actuate callback function
|
||||
|
||||
def __iter__(self):
|
||||
return SenmlPackIterator(self._data)
|
||||
|
||||
def __enter__(self):
|
||||
"""
|
||||
for supporting the 'with' statement
|
||||
:return: self
|
||||
"""
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"""
|
||||
when destroyed in a 'with' statement, make certain that the item is removed from the parent list.
|
||||
:return: None
|
||||
"""
|
||||
if self._parent:
|
||||
self._parent.remove(self)
|
||||
|
||||
@property
|
||||
def base_value(self):
|
||||
"""
|
||||
the base value of the pack.
|
||||
:return: a number
|
||||
"""
|
||||
return self._base_value
|
||||
|
||||
@base_value.setter
|
||||
def base_value(self, value):
|
||||
"""
|
||||
set the base value.
|
||||
:param value: only number allowed
|
||||
:return:
|
||||
"""
|
||||
self._check_value_type(value, "base_value")
|
||||
self._base_value = value
|
||||
|
||||
@property
|
||||
def base_sum(self):
|
||||
"""
|
||||
the base sum of the pack.
|
||||
:return: a number
|
||||
"""
|
||||
return self._base_sum
|
||||
|
||||
@base_sum.setter
|
||||
def base_sum(self, value):
|
||||
"""
|
||||
set the base value.
|
||||
:param value: only number allowed
|
||||
:return:
|
||||
"""
|
||||
self._check_value_type(value, "base_sum")
|
||||
self._base_sum = value
|
||||
|
||||
@property
|
||||
def base_time(self):
|
||||
return self._base_time
|
||||
|
||||
@base_time.setter
|
||||
def base_time(self, value):
|
||||
self._check_value_type(value, "base_time")
|
||||
self._base_time = value
|
||||
|
||||
def _check_value_type(self, value, field_name):
|
||||
"""
|
||||
checks if the type of value is allowed for senml
|
||||
:return: None, raisee exception if not ok.
|
||||
"""
|
||||
if not value == None:
|
||||
if not (isinstance(value, int) or isinstance(value, float)):
|
||||
raise Exception("invalid type for " + field_name + ", only numbers allowed")
|
||||
|
||||
def from_json(self, data):
|
||||
"""
|
||||
parse a json string and convert it to a senml pack structure
|
||||
:param data: a string containing json data.
|
||||
:return: None, will r
|
||||
"""
|
||||
records = ujson.loads(data) # load the raw senml data
|
||||
self._process_incomming_data(records, SenmlPack.json_mappings)
|
||||
|
||||
def _process_incomming_data(self, records, naming_map):
|
||||
"""
|
||||
generic processor for incomming data (actuators.
|
||||
:param records: the list of raw senml data, parsed from a json or cbor structure
|
||||
:param naming_map: translates cbor to json field names (when needed).
|
||||
:return: None
|
||||
"""
|
||||
cur_pack_el = self
|
||||
new_pack = False
|
||||
for item in records:
|
||||
if naming_map["bn"] in item: # ref to a pack element, either this or a child pack.
|
||||
if item[naming_map["bn"]] != self.name:
|
||||
pack_el = [x for x in self._data if x.name == item[naming_map["bn"]]]
|
||||
else:
|
||||
pack_el = [self]
|
||||
if len(pack_el) > 0:
|
||||
cur_pack_el = pack_el[0]
|
||||
new_pack = False
|
||||
else:
|
||||
device = SenmlPack(item[naming_map["bn"]])
|
||||
self._data.append(device)
|
||||
cur_pack_el = device
|
||||
new_pack = True
|
||||
|
||||
if (
|
||||
naming_map["bv"] in item
|
||||
): # need to copy the base value assigned to the pack element so we can do proper conversion for actuators.
|
||||
cur_pack_el.base_value = item[naming_map["bv"]]
|
||||
|
||||
rec_el = [x for x in cur_pack_el._data if x.name == item[naming_map["n"]]]
|
||||
if len(rec_el) > 0:
|
||||
rec_el[0].do_actuate(item, naming_map)
|
||||
elif new_pack:
|
||||
self.do_actuate(item, naming_map, cur_pack_el)
|
||||
else:
|
||||
cur_pack_el.do_actuate(item, naming_map)
|
||||
else:
|
||||
rec_el = [x for x in self._data if x.name == item[naming_map["n"]]]
|
||||
if len(rec_el) > 0:
|
||||
rec_el[0].do_actuate(item, naming_map)
|
||||
elif new_pack:
|
||||
self.do_actuate(item, naming_map, cur_pack_el)
|
||||
else:
|
||||
cur_pack_el.do_actuate(item, naming_map)
|
||||
|
||||
def do_actuate(self, raw, naming_map, device=None):
|
||||
"""
|
||||
called while parsing incoming data for a record that is not yet part of this pack object.
|
||||
adds a new record and raises the actuate callback of the pack with the newly created record as argument
|
||||
:param naming_map:
|
||||
:param device: optional: if the device was not found
|
||||
:param raw: the raw record definition, as found in the json structure. this still has invalid labels.
|
||||
:return: None
|
||||
"""
|
||||
rec = SenmlRecord(raw[naming_map["n"]])
|
||||
if device:
|
||||
device.add(rec)
|
||||
rec._from_raw(raw, naming_map)
|
||||
if self.actuate:
|
||||
self.actuate(rec, device=device)
|
||||
else:
|
||||
self.add(rec)
|
||||
rec._from_raw(raw, naming_map)
|
||||
if self.actuate:
|
||||
self.actuate(rec, device=None)
|
||||
|
||||
def to_json(self):
|
||||
"""
|
||||
render the content of this object to a string.
|
||||
:return: a string representing the senml pack object
|
||||
"""
|
||||
converted = []
|
||||
self._build_rec_dict(SenmlPack.json_mappings, converted)
|
||||
return ujson.dumps(converted)
|
||||
|
||||
def _build_rec_dict(self, naming_map, appendTo):
|
||||
"""
|
||||
converts the object to a senml object with the proper naming in place.
|
||||
This can be recursive: a pack can contain other packs.
|
||||
:param naming_map: a dictionary used to pick the correct field names for either senml json or senml cbor
|
||||
:return:
|
||||
"""
|
||||
internalList = []
|
||||
for item in self._data:
|
||||
item._build_rec_dict(naming_map, internalList)
|
||||
if len(internalList) > 0:
|
||||
first_rec = internalList[0]
|
||||
else:
|
||||
first_rec = {}
|
||||
internalList.append(first_rec)
|
||||
|
||||
if self.name:
|
||||
first_rec[naming_map["bn"]] = self.name
|
||||
if self.base_value:
|
||||
first_rec[naming_map["bv"]] = self.base_value
|
||||
if self.base_unit:
|
||||
first_rec[naming_map["bu"]] = self.base_unit
|
||||
if self.base_sum:
|
||||
first_rec[naming_map["bs"]] = self.base_sum
|
||||
if self.base_time:
|
||||
first_rec[naming_map["bt"]] = self.base_time
|
||||
appendTo.extend(internalList)
|
||||
|
||||
def from_cbor(self, data):
|
||||
"""
|
||||
parse a cbor data byte array to a senml pack structure.
|
||||
:param data: a byte array.
|
||||
:return: None
|
||||
"""
|
||||
records = decoder.loads(data) # load the raw senml data
|
||||
naming_map = {
|
||||
"bn": -2,
|
||||
"bt": -3,
|
||||
"bu": -4,
|
||||
"bv": -5,
|
||||
"bs": -16,
|
||||
"n": 0,
|
||||
"u": 1,
|
||||
"v": 2,
|
||||
"vs": 3,
|
||||
"vb": 4,
|
||||
"vd": 8,
|
||||
"s": 5,
|
||||
"t": 6,
|
||||
"ut": 7,
|
||||
}
|
||||
self._process_incomming_data(records, naming_map)
|
||||
|
||||
def to_cbor(self):
|
||||
"""
|
||||
render the content of this object to a cbor byte array
|
||||
:return: a byte array
|
||||
"""
|
||||
naming_map = {
|
||||
"bn": -2,
|
||||
"bt": -3,
|
||||
"bu": -4,
|
||||
"bv": -5,
|
||||
"bs": -16,
|
||||
"n": 0,
|
||||
"u": 1,
|
||||
"v": 2,
|
||||
"vs": 3,
|
||||
"vb": 4,
|
||||
"vd": 8,
|
||||
"s": 5,
|
||||
"t": 6,
|
||||
"ut": 7,
|
||||
}
|
||||
converted = []
|
||||
self._build_rec_dict(naming_map, converted)
|
||||
return encoder.dumps(converted)
|
||||
|
||||
def add(self, item):
|
||||
"""
|
||||
adds the item to the list of records
|
||||
:param item: {SenmlRecord} the item that needs to be added to the pack
|
||||
:return: None
|
||||
"""
|
||||
if not (isinstance(item, SenmlBase)):
|
||||
raise Exception("invalid type of param, SenmlRecord or SenmlPack expected")
|
||||
if not item._parent == None:
|
||||
raise Exception("item is already part of a pack")
|
||||
|
||||
self._data.append(item)
|
||||
item._parent = self
|
||||
|
||||
def remove(self, item):
|
||||
"""
|
||||
removes the item from the list of records
|
||||
:param item: {SenmlRecord} the item that needs to be removed
|
||||
:return: None
|
||||
"""
|
||||
if not (isinstance(item, SenmlBase)):
|
||||
raise Exception("invalid type of param, SenmlRecord or SenmlPack expected")
|
||||
if not item._parent == self:
|
||||
raise Exception("item is not part of this pack")
|
||||
|
||||
self._data.remove(item)
|
||||
item._parent = None
|
||||
|
||||
def clear(self):
|
||||
"""
|
||||
clear the list of the pack
|
||||
:return: None
|
||||
"""
|
||||
for item in self._data:
|
||||
item._parent = None
|
||||
self._data = []
|
|
@ -0,0 +1,245 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
import ubinascii
|
||||
from senml.senml_base import SenmlBase
|
||||
|
||||
|
||||
class SenmlRecord(SenmlBase):
|
||||
"""represents a single value in a senml pack object"""
|
||||
|
||||
def __init__(self, name, **kwargs):
|
||||
"""
|
||||
create a new senml record
|
||||
:param kwargs: optional parameters:
|
||||
- value: the value to store in the record
|
||||
- time: the timestamp to use (when was the value measured)
|
||||
- name: the name of hte record
|
||||
- unit: unit value
|
||||
- sum: sum value
|
||||
- update_time: max time before sensor will provide an updated reading
|
||||
- callback: a callback function taht will be called when actuator data has been found. Expects no params
|
||||
"""
|
||||
self.__parent = None # using double __ cause it's a field for an internal property
|
||||
self._unit = None # declare and init internal fields
|
||||
self._value = None
|
||||
self._time = None
|
||||
self._sum = None
|
||||
self._update_time = None
|
||||
|
||||
self._parent = None # internal reference to the parent object
|
||||
self.name = name
|
||||
self.unit = kwargs.get("unit", None)
|
||||
self.value = kwargs.get("value", None)
|
||||
self.time = kwargs.get("time", None)
|
||||
self.sum = kwargs.get("sum", None)
|
||||
self.update_time = kwargs.get("update_time", None)
|
||||
self.actuate = kwargs.get("callback", None) # actuate callback function
|
||||
|
||||
def __enter__(self):
|
||||
"""
|
||||
for supporting the 'with' statement
|
||||
:return: self
|
||||
"""
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"""
|
||||
when destroyed in a 'with' statement, make certain that the item is removed from the parent list.
|
||||
:return: None
|
||||
"""
|
||||
if self._parent:
|
||||
self._parent.remove(self)
|
||||
|
||||
def _check_value_type(self, value):
|
||||
"""
|
||||
checks if the type of value is allowed for senml
|
||||
:return: None, raisee exception if not ok.
|
||||
"""
|
||||
if not value == None:
|
||||
if not (
|
||||
isinstance(value, bool)
|
||||
or isinstance(value, int)
|
||||
or isinstance(value, float)
|
||||
or isinstance(value, bytearray)
|
||||
or isinstance(value, str)
|
||||
):
|
||||
raise Exception(
|
||||
"invalid type for value, only numbers, strings, boolean and byte arrays allowed"
|
||||
)
|
||||
|
||||
def _check_number_type(self, value, field_name):
|
||||
"""
|
||||
checks if the type of value is allowed for senml
|
||||
:return: None, raisee exception if not ok.
|
||||
"""
|
||||
if not value == None:
|
||||
if not (isinstance(value, int) or isinstance(value, float)):
|
||||
raise Exception("invalid type for " + field_name + ", only numbers allowed")
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
"""get the value currently assigned to the object"""
|
||||
return self._value
|
||||
|
||||
@value.setter
|
||||
def value(self, value):
|
||||
"""set the current value. Will not automatically update the time stamp. This has to be done seperatly for more
|
||||
finegrained control
|
||||
Note: when the value is a float, you can control rounding in the rendered output by using the function
|
||||
round() while assigning the value. ex: record.value = round(12.2 / 1.5423, 2)
|
||||
"""
|
||||
self._check_value_type(value)
|
||||
self._value = value
|
||||
|
||||
@property
|
||||
def time(self):
|
||||
return self._time
|
||||
|
||||
@time.setter
|
||||
def time(self, value):
|
||||
self._check_number_type(value, "time")
|
||||
self._time = value
|
||||
|
||||
@property
|
||||
def update_time(self):
|
||||
return self._update_time
|
||||
|
||||
@update_time.setter
|
||||
def update_time(self, value):
|
||||
self._check_number_type(value, "update_time")
|
||||
self._update_time = value
|
||||
|
||||
@property
|
||||
def sum(self):
|
||||
return self._sum
|
||||
|
||||
@sum.setter
|
||||
def sum(self, value):
|
||||
self._check_number_type(value, "sum")
|
||||
self._sum = value
|
||||
|
||||
@property
|
||||
def _parent(self):
|
||||
"""
|
||||
the parent pack object for this record. This is a property so that inheriters can override and do custom
|
||||
actions when the parent is set (like passing it on to their children
|
||||
:return:
|
||||
"""
|
||||
return self.__parent
|
||||
|
||||
@_parent.setter
|
||||
def _parent(self, value):
|
||||
"""
|
||||
the parent pack object for this record. This is a property so that inheriters can override and do custom
|
||||
actions when the parent is set (like passing it on to their children
|
||||
:return:
|
||||
"""
|
||||
self.__parent = value
|
||||
|
||||
def _build_rec_dict(self, naming_map, appendTo):
|
||||
"""
|
||||
converts the object to a dictionary that can be rendered to senml.
|
||||
:param naming_map: a dictionary that maps the field names to senml json or senml cbor. keys are in the
|
||||
form 'n', 'v',... values for 'n' are either 'n' or 0 (number is for cbor)
|
||||
:return: a senml dictionary representation of the record
|
||||
"""
|
||||
result = {}
|
||||
|
||||
if self.name:
|
||||
result[naming_map["n"]] = self.name
|
||||
|
||||
if self._sum:
|
||||
if self._parent and self._parent.base_sum:
|
||||
result[naming_map["s"]] = self._sum - self._parent.base_sum
|
||||
else:
|
||||
result[naming_map["s"]] = self._sum
|
||||
elif isinstance(self._value, bool):
|
||||
result[naming_map["vb"]] = self._value
|
||||
elif isinstance(self._value, int) or isinstance(self._value, float):
|
||||
if self._parent and self._parent.base_value:
|
||||
result[naming_map["v"]] = self._value - self._parent.base_value
|
||||
else:
|
||||
result[naming_map["v"]] = self._value
|
||||
elif isinstance(self._value, str):
|
||||
result[naming_map["vs"]] = self._value
|
||||
elif isinstance(self._value, bytearray):
|
||||
if (
|
||||
naming_map["vd"] == "vd"
|
||||
): # neeed to make a distinction between json (needs base64) and cbor (needs binary)
|
||||
result[naming_map["vd"]] = base64.b64encode(self._value)
|
||||
else:
|
||||
result[naming_map["vd"]] = self._value
|
||||
else:
|
||||
raise Exception("sum or value of type bootl, number, string or byte-array is required")
|
||||
|
||||
if self._time:
|
||||
if self._parent and self._parent.base_time:
|
||||
result[naming_map["t"]] = self._time - self._parent.base_time
|
||||
else:
|
||||
result[naming_map["t"]] = self._time
|
||||
|
||||
if self.unit:
|
||||
result[naming_map["u"]] = self.unit
|
||||
|
||||
if self._update_time:
|
||||
if self._parent and self._parent.base_time:
|
||||
result[naming_map["ut"]] = self._update_time - self._parent.base_time
|
||||
else:
|
||||
result[naming_map["ut"]] = self._update_time
|
||||
|
||||
appendTo.append(result)
|
||||
|
||||
def _from_raw(self, raw, naming_map):
|
||||
"""
|
||||
extracts te data from the raw record. Used during parsing of incoming data.
|
||||
:param raw: a raw senml record which still contains the original field names
|
||||
:param naming_map: used to map cbor names to json field names
|
||||
:return:
|
||||
"""
|
||||
if naming_map["v"] in raw:
|
||||
val = raw[naming_map["v"]]
|
||||
if self._parent and self._parent.base_value:
|
||||
val += self._parent.base_value
|
||||
elif naming_map["vs"] in raw:
|
||||
val = raw[naming_map["vs"]]
|
||||
elif naming_map["vb"] in raw:
|
||||
val = raw[naming_map["vb"]]
|
||||
elif naming_map["vd"] in raw:
|
||||
val = ubinascii.a2b_base64(raw[naming_map["vb"]])
|
||||
else:
|
||||
val = None
|
||||
self.value = val
|
||||
|
||||
def do_actuate(self, raw, naming_map):
|
||||
"""
|
||||
called when a raw senml record was found for this object. Stores the data and if there is a callback, calls it.
|
||||
:param raw: raw senml object
|
||||
:return: None
|
||||
"""
|
||||
self._from_raw(raw, naming_map)
|
||||
if self.actuate:
|
||||
self.actuate(self)
|
|
@ -0,0 +1,89 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
Copyright (c) 2018 KPN (Jan Bogaerts)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
def enum(**enums):
|
||||
return type("Enum", (), enums)
|
||||
|
||||
|
||||
SenmlUnits = enum(
|
||||
SENML_UNIT_METER="m",
|
||||
SENML_UNIT_KILOGRAM="kg",
|
||||
SENML_UNIT_GRAM="g",
|
||||
SENML_UNIT_SECOND="s",
|
||||
SENML_UNIT_AMPERE="A",
|
||||
SENML_UNIT_KELVIN="K",
|
||||
SENML_UNIT_CANDELA="cd",
|
||||
SENML_UNIT_MOLE="mol",
|
||||
SENML_UNIT_HERTZ="Hz",
|
||||
SENML_UNIT_RADIAN="rad",
|
||||
SENML_UNIT_STERADIAN="sr",
|
||||
SENML_UNIT_NEWTON="N",
|
||||
SENML_UNIT_PASCAL="Pa",
|
||||
SENML_UNIT_JOULE="J",
|
||||
SENML_UNIT_WATT="W",
|
||||
SENML_UNIT_COULOMB="C",
|
||||
SENML_UNIT_VOLT="V",
|
||||
SENML_UNIT_FARAD="F",
|
||||
SENML_UNIT_OHM="Ohm",
|
||||
SENML_UNIT_SIEMENS="S",
|
||||
SENML_UNIT_WEBER="Wb",
|
||||
SENML_UNIT_TESLA="T",
|
||||
SENML_UNIT_HENRY="H",
|
||||
SENML_UNIT_DEGREES_CELSIUS="Cel",
|
||||
SENML_UNIT_LUMEN="lm",
|
||||
SENML_UNIT_LUX="lx",
|
||||
SENML_UNIT_BECQUEREL="Bq",
|
||||
SENML_UNIT_GRAY="Gy",
|
||||
SENML_UNIT_SIEVERT="Sv",
|
||||
SENML_UNIT_KATAL="kat",
|
||||
SENML_UNIT_SQUARE_METER="m2",
|
||||
SENML_UNIT_CUBIC_METER="m3",
|
||||
SENML_UNIT_LITER="l",
|
||||
SENML_UNIT_VELOCITY="m/s",
|
||||
SENML_UNIT_ACCELERATION="m/s2",
|
||||
SENML_UNIT_CUBIC_METER_PER_SECOND="m3/s",
|
||||
SENML_UNIT_LITER_PER_SECOND="l/s",
|
||||
SENML_UNIT_WATT_PER_SQUARE_METER="W/m2",
|
||||
SENML_UNIT_CANDELA_PER_SQUARE_METER="cd/m2",
|
||||
SENML_UNIT_BIT="bit",
|
||||
SENML_UNIT_BIT_PER_SECOND="bit/s",
|
||||
SENML_UNIT_DEGREES_LATITUDE="lat",
|
||||
SENML_UNIT_DEGREES_LONGITUDE="lon",
|
||||
SENML_UNIT_PH="pH",
|
||||
SENML_UNIT_DECIBEL="db",
|
||||
SENML_UNIT_DECIBEL_RELATIVE_TO_1_W="dBW",
|
||||
SENML_UNIT_BEL="Bspl",
|
||||
SENML_UNIT_COUNTER="count",
|
||||
SENML_UNIT_RATIO="//",
|
||||
SENML_UNIT_RELATIVE_HUMIDITY="%RH",
|
||||
SENML_UNIT_PERCENTAGE_REMAINING_BATTERY_LEVEL="%EL",
|
||||
SENML_UNIT_SECONDS_REMAINING_BATTERY_LEVEL="EL",
|
||||
SENML_UNIT_EVENT_RATE_PER_SECOND="1/s",
|
||||
SENML_UNIT_EVENT_RATE_PER_MINUTE="1/min",
|
||||
SENML_UNIT_BPM="beat/min",
|
||||
SENML_UNIT_BEATS="beats",
|
||||
SENML_UNIT_SIEMENS_PER_METER="S/m",
|
||||
)
|
Ładowanie…
Reference in New Issue