Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: convert BACnet units to unit symbols (use SI where possible) #16

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions helper_scripts/check_bacnet_units.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# metricq-source-bacnet
# Copyright (C) 2022 ZIH, Technische Universitaet Dresden, Federal Republic of Germany
#
# All rights reserved.
#
# This file is part of metricq-source-bacnet.
#
# metricq-source-bacnet is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# metricq-source-bacnet is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with metricq-source-bacnet. If not, see <http://www.gnu.org/licenses/>.
import click

from bacpypes.basetypes import EngineeringUnits
from metricq_source_bacnet.bacnet.constants import BACNET_TO_SI_UNITS

@click.command()
@click.option("--as-code/--no-as-code", default=False)
@click.option("--all/--no-all", default=False)
def main(all, as_code):
if not as_code:
print(f"{'#': <4} | {'BACnet': <32} | {'source-bacnet': <15}")
print(f"{'-'*4}-+-{'-'*32}-+-{'-'*15}")

for unit, int_value in EngineeringUnits.enumerations.items():
if int_value not in BACNET_TO_SI_UNITS:
if as_code:
print(f"{int_value}: \"{unit}\",")
else:
print(f"{int_value: <4} | {unit: <32} | {'-': <15}")
elif all:
if as_code:
print(f"{int_value}: \"{unit}\", # {BACNET_TO_SI_UNITS[int_value]}")
else:
print(f"{int_value: <4} | {unit: <32} | {BACNET_TO_SI_UNITS[int_value]: <15}")



if __name__ == "__main__":
main()
189 changes: 189 additions & 0 deletions metricq_source_bacnet/bacnet/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# metricq-source-bacnet
# Copyright (C) 2022 ZIH, Technische Universitaet Dresden, Federal Republic of Germany
#
# All rights reserved.
#
# This file is part of metricq-source-bacnet.
#
# metricq-source-bacnet is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# metricq-source-bacnet is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with metricq-source-bacnet. If not, see <http://www.gnu.org/licenses/>.

BACNET_TO_SI_UNITS = {
166: "m/s²",
0: "m²",
116: "cm²",
2: "mA",
3: "A",
167: "A/m",
168: "A/m²",
169: "A m²",
199: "dB",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dB is explicitly a non-SI with the following remark:

In using these units it is important that the nature of the quantity be specified, and that any
reference value used be specified. These units are not SI units, but they have been accepted by
the CIPM for use with the SI.

200: "dBmV",
201: "dBV",
Comment on lines +31 to +32
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That may even be "acceptable non-SI" but parsing hell...

170: "F",
171: "H",
4: "Ω",
172: "Ω m",
237: "Ω m m⁻²",
145: "mΩ",
122: "kΩ",
123: "MΩ",
190: "µS",
202: "mS",
173: "S",
174: "S/m",
175: "T",
5: "V",
124: "mV",
6: "kV",
7: "MV",
8: "V A",
9: "kV A",
10: "MV A",
238: "A s",
246: "A h²",
239: "V A h",
240: "kV A h",
241: "MV A h",
11: "var",
12: "kvar",
13: "Mvar",
176: "V/K",
177: "V/m",
245: "V h²",
178: "Wb",
16: "J",
17: "kJ",
125: "kJ/kg",
126: "MJ",
247: "J/h",
18: "W h",
19: "kW h",
146: "MW h",
127: "J/K",
151: "kJ/K",
152: "MJ/K",
128: "J kg⁻¹ K⁻¹",
153: "N",
27: "Hz",
129: "kHz",
130: "MHz",
131: "h⁻¹",
194: "µm",
30: "mm",
118: "cm",
193: "km",
31: "m",
179: "cd",
180: "cd/m²",
35: "W/m²",
36: "lm",
37: "lx",
196: "mg",
195: "g",
39: "kg",
41: "t",
154: "g/s",
155: "g/min",
42: "kg/s",
43: "kg/min",
44: "kg/h",
156: "t/h",
132: "mW",
47: "W",
48: "kW",
49: "MW",
53: "Pa",
133: "hPa",
54: "kPa",
253: "Pa s",
134: "mbar",
55: "bar",
62: "°C",
63: "K",
181: "K/h",
182: "K/min",
70: "d",
71: "h",
72: "min",
73: "s",
158: "cs",
159: "ms",
160: "N m",
161: "mm/s",
162: "mm/min",
74: "m/s",
163: "m/min",
164: "m/h",
75: "km/h",
80: "m³",
249: "m³/d",
197: "ml",
82: "l",
85: "m³/s",
165: "m³/min",
135: "m³/h",
198: "ml/s",
87: "l/s",
88: "l/min",
136: "l/h",
91: "°C/h",
92: "°C/min",
183: "J s",
186: "kg/m³",
137: "kW h m⁻²",
139: "MJ/m²",
187: "N s",
188: "N/m",
96: "ppm",
97: "ppb",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The terms “parts per billion”, and “parts per trillion”, and their respective abbreviations “ppb”,
and “ppt”, are also used, but their meanings are language dependent. For this reason
the terms ppb and ppt are best avoided. (In English-speaking countries, a billion is
now generally taken to be 10^9 and a trillion to be 10^12; however, a billion may still
sometimes be interpreted as 10^12 and a trillion as 10^18. The abbreviation ppt is also
sometimes read as parts per thousand, adding further confusion.)

98: "%",
99: "%/s",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... maybe ....

100: "min⁻¹",
101: "s⁻¹",
103: "rad",
184: "rad/s",
185: "m²/N",
189: "W m⁻¹ K⁻¹",
141: "W m⁻² K⁻¹",
207: "‰",
208: "g/g",
209: "kg/kg",
210: "g/kg",
211: "mg/g",
212: "mg/kg",
213: "g/ml",
214: "g/l",
215: "mg/l",
216: "µg/l",
217: "g /m³",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
217: "g /m³",
217: "g/m³",

218: "mg/m³",
219: "µg/m³",
220: "ng/m³",
221: "g/cm³",
250: "W h/m³",
251: "J/m³",
222: "Bq",
223: "kBq",
224: "MBq",
225: "Gy",
226: "mGy",
227: "µGy",
228: "Sv",
229: "mSv",
230: "µSv",
231: "µSv/h",
234: "pH",
Copy link

@tilsche tilsche Apr 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless that is picoHenry - the pH value is dimensionless.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we need an empty unit here otherwise the BACnet unit name (pH) is used

235: "g/m²",
236: "min/K",
}
10 changes: 9 additions & 1 deletion metricq_source_bacnet/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@
from typing import Dict, List, Optional, Tuple, Union, Set

from bacpypes.pdu import Address
from bacpypes.basetypes import EngineeringUnits
from metricq import Source, Timedelta, Timestamp, get_logger, rpc_handler
from metricq_source_bacnet.bacnet.application import BACnetMetricQReader
from metricq_source_bacnet.bacnet.object_types import register_extended_object_types
from metricq_source_bacnet.bacnet.constants import BACNET_TO_SI_UNITS

logger = get_logger(__name__)

Expand Down Expand Up @@ -457,7 +459,13 @@ async def _worker_task(self, object_group, worker_task_stop_future):
description, self._object_description_vendor_specific_substitutions
)
if "units" in object_info:
metadata["unit"] = object_info["units"]
# convert BACnet unit to SI
unit = object_info["units"]
if unit_int := EngineeringUnits.enumerations.get(unit):
if unit_int in BACNET_TO_SI_UNITS:
unit = BACNET_TO_SI_UNITS.get(unit_int)
Comment on lines +465 to +466
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why you'd combine if / get. Could use get(unit_id, unit) or try / except KeyError


metadata["unit"] = unit

metrics[metric_id] = metadata

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
name="metricq_source_bacnet",
version="0.1",
author="TU Dresden",
python_requires=">=3.6",
python_requires=">=3.8",
packages=find_packages(),
scripts=[],
entry_points="""
Expand Down