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
iabdalkader 2022-09-27 12:52:18 +02:00 zatwierdzone przez Damien George
rodzic 52fcb8e4a7
commit 9ee02576cb
22 zmienionych plików z 1829 dodań i 0 usunięć

Wyświetl plik

@ -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.

Wyświetl plik

@ -0,0 +1 @@
theme: jekyll-theme-slate

Wyświetl plik

@ -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

Wyświetl plik

@ -0,0 +1,8 @@
# senml_base Module
## senml_base.SenmlBase Objects
the base class for all senml objects.

Wyświetl plik

@ -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)
```

Wyświetl plik

@ -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

Wyświetl plik

@ -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`

Wyświetl plik

@ -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)

Wyświetl plik

@ -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())

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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())

Wyświetl plik

@ -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)

Wyświetl plik

@ -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"}]'
)

Wyświetl plik

@ -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)

Wyświetl plik

@ -0,0 +1,5 @@
metadata(version="0.1.0")
require("cbor2")
package("senml")

Wyświetl plik

@ -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

Wyświetl plik

@ -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.
"""

Wyświetl plik

@ -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 = []

Wyświetl plik

@ -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)

Wyświetl plik

@ -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",
)