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

Added Async BACnet Connector #1607

Merged
merged 4 commits into from
Dec 3, 2024
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2022. ThingsBoard
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2022. ThingsBoard
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
36 changes: 21 additions & 15 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,28 @@
long_description_content_type="text/markdown",
include_package_data=True,
python_requires=">=3.7",
packages=['thingsboard_gateway', 'thingsboard_gateway.gateway', 'thingsboard_gateway.gateway.proto', 'thingsboard_gateway.gateway.grpc_service',
'thingsboard_gateway.storage', 'thingsboard_gateway.storage.memory', 'thingsboard_gateway.gateway.shell', 'thingsboard_gateway.gateway.report_strategy',
'thingsboard_gateway.storage.file', 'thingsboard_gateway.storage.sqlite', 'thingsboard_gateway.gateway.entities',
'thingsboard_gateway.connectors', 'thingsboard_gateway.connectors.ble', 'thingsboard_gateway.connectors.socket',
'thingsboard_gateway.connectors.mqtt', 'thingsboard_gateway.connectors.xmpp', 'thingsboard_gateway.connectors.modbus_async',
'thingsboard_gateway.connectors.opcua', 'thingsboard_gateway.connectors.request', 'thingsboard_gateway.connectors.ocpp',
'thingsboard_gateway.connectors.modbus', 'thingsboard_gateway.connectors.can', 'thingsboard_gateway.connectors.bacnet',
'thingsboard_gateway.connectors.bacnet.bacnet_utilities', 'thingsboard_gateway.connectors.odbc',
'thingsboard_gateway.connectors.rest', 'thingsboard_gateway.connectors.snmp', 'thingsboard_gateway.connectors.ftp',
packages=['thingsboard_gateway', 'thingsboard_gateway.gateway', 'thingsboard_gateway.gateway.proto',
'thingsboard_gateway.gateway.grpc_service', 'thingsboard_gateway.storage', 'thingsboard_gateway.storage.memory',
'thingsboard_gateway.gateway.shell', 'thingsboard_gateway.gateway.report_strategy', 'thingsboard_gateway.storage.file',
'thingsboard_gateway.storage.sqlite', 'thingsboard_gateway.gateway.entities', 'thingsboard_gateway.connectors',
'thingsboard_gateway.connectors.ble', 'thingsboard_gateway.extensions.ble',
'thingsboard_gateway.connectors.socket', 'thingsboard_gateway.extensions.socket',
'thingsboard_gateway.connectors.mqtt', 'thingsboard_gateway.extensions.mqtt',
'thingsboard_gateway.connectors.xmpp', 'thingsboard_gateway.extensions.xmpp',
'thingsboard_gateway.connectors.modbus', 'thingsboard_gateway.extensions.modbus',
'thingsboard_gateway.connectors.modbus_old', 'thingsboard_gateway.connectors.modbus_old',
'thingsboard_gateway.connectors.opcua', 'thingsboard_gateway.extensions.opcua',
'thingsboard_gateway.connectors.request', 'thingsboard_gateway.extensions.request',
'thingsboard_gateway.connectors.ocpp', 'thingsboard_gateway.extensions.ocpp',
'thingsboard_gateway.connectors.can', 'thingsboard_gateway.extensions.can',
'thingsboard_gateway.connectors.bacnet_old', 'thingsboard_gateway.connectors.bacnet_old.bacnet_utilities', 'thingsboard_gateway.extensions.bacnet_old',
'thingsboard_gateway.connectors.odbc', 'thingsboard_gateway.extensions.odbc',
'thingsboard_gateway.connectors.bacnet', 'thingsboard_gateway.extensions.bacnet',
'thingsboard_gateway.connectors.rest', 'thingsboard_gateway.extensions.rest',
'thingsboard_gateway.connectors.snmp', 'thingsboard_gateway.extensions.snmp',
'thingsboard_gateway.connectors.ftp', 'thingsboard_gateway.extensions.ftp',
'thingsboard_gateway.tb_utility', 'thingsboard_gateway.extensions',
'thingsboard_gateway.extensions.mqtt', 'thingsboard_gateway.extensions.modbus', 'thingsboard_gateway.extensions.opcua',
'thingsboard_gateway.extensions.ocpp', 'thingsboard_gateway.extensions.ble',
'thingsboard_gateway.extensions.serial', 'thingsboard_gateway.extensions.request',
'thingsboard_gateway.extensions.can', 'thingsboard_gateway.extensions.bacnet', 'thingsboard_gateway.extensions.odbc',
'thingsboard_gateway.extensions.rest', 'thingsboard_gateway.extensions.snmp', 'thingsboard_gateway.extensions.ftp',
'thingsboard_gateway.extensions.socket', 'thingsboard_gateway.extensions.xmpp', 'thingsboard_gateway.gateway.statistics'
'thingsboard_gateway.extensions.serial', 'thingsboard_gateway.gateway.statistics'
],
install_requires=[
'setuptools',
Expand Down
43 changes: 28 additions & 15 deletions thingsboard_gateway/config/bacnet.json
Original file line number Diff line number Diff line change
@@ -1,39 +1,50 @@
{
"general": {
"application": {
"objectName": "TB_gateway",
"address": "0.0.0.0:47808",
"address": "0.0.0.0",
"objectIdentifier": 599,
"maxApduLengthAccepted": 1476,
"segmentationSupported": "segmentedBoth",
"vendorIdentifier": 15
"vendorIdentifier": 15,
"deviceDiscoveryTimeoutInSec": 5
},
"devices": [
{
"deviceName": "BACnet Device ${objectName}",
"deviceType": "default",
"address": "192.168.2.110:47808",
"deviceInfo": {
"deviceNameExpressionSource": "expression",
"deviceNameExpression": "BACnet Device ${objectName}",
"deviceProfileExpressionSource": "constant",
"deviceProfileExpression": "default"
},
"address": "192.168.1.160:49644",
"pollPeriod": 10000,
"attributes": [
{
"key": "temperature",
"type": "string",
"objectId": "analogOutput:1",
"objectType": "analogInput",
"objectId": "0",
"propertyId": "presentValue"
}
],
"timeseries": [
{
"key": "state",
"type": "bool",
"objectId": "binaryValue:1",
"key": "water_temp",
"objectType": "analogInput",
"objectId": "1",
"propertyId": "presentValue"
},
{
"key": "temp_outdoor",
"objectType": "analogInput",
"objectId": "2",
"propertyId": "presentValue"
}
],
"attributeUpdates": [
{
"key": "brightness",
"requestType": "writeProperty",
"objectId": "analogOutput:1",
"objectType": "analogInput",
"objectId": "1",
"propertyId": "presentValue"
}
],
Expand All @@ -42,14 +53,16 @@
"method": "set_state",
"requestType": "writeProperty",
"requestTimeout": 10000,
"objectId": "binaryOutput:1",
"objectType": "binaryOutput",
"objectId": "1",
"propertyId": "presentValue"
},
{
"method": "get_state",
"requestType": "readProperty",
"requestTimeout": 10000,
"objectId": "binaryOutput:1",
"objectType": "analogInput",
"objectId": "0",
"propertyId": "presentValue"
}
]
Expand Down
40 changes: 40 additions & 0 deletions thingsboard_gateway/connectors/bacnet/application.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2024. ThingsBoard
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from bacpypes3.ipv4.app import NormalApplication as App
from bacpypes3.local.device import DeviceObject
from bacpypes3.pdu import Address

from thingsboard_gateway.connectors.bacnet.entities.device_object_config import DeviceObjectConfig


class Application(App):
def __init__(self, device_object_config: DeviceObjectConfig, indication_callback, logger):
self.__device_object_config = device_object_config
self.__device_object = DeviceObject(**self.__device_object_config.device_object_config)
super().__init__(self.__device_object, Address(self.__device_object_config.address))

self.__log = logger
self.__indication_callback = indication_callback

async def indication(self, apdu) -> None:
self.__log.debug(f"(indication) Received APDU: {apdu}")
await super().indication(apdu)
self.__indication_callback(apdu)

async def do_who_is(self, device_address):
devices = await self.who_is(address=Address(device_address),
timeout=self.__device_object_config.device_discovery_timeout)
if len(devices):
return devices[0]
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Copyright 2024. ThingsBoard
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from copy import deepcopy


class BackwardCompatibilityAdapter:
def __init__(self, config, logger):
self.__log = logger
self.__config = deepcopy(config)

def convert(self):
try:
self.__convert_application_section()
self.__convert_device_section()
except Exception as e:
self.__log.error('Error converting old config: %s', e)

return self.__config


def __convert_application_section(self):
general_section = self.__config.pop('general', {})
self.__config['application'] = general_section

def __convert_device_section(self):
for device in self.__config.get('devices', []):
self.__convert_device_info_section(device)

for section in ('attributes', 'timeseries'):
for item_config in device.get(section, []):
self.__convert_object_id(item_config)

for attr_update_config in device.get('attributeUpdates', []):
self.__convert_object_id(attr_update_config)

for rpc_config in device.get('rpc', []):
self.__convert_object_id(rpc_config)

@staticmethod
def __convert_device_info_section(old_device_config):
device_name = old_device_config.pop('deviceName')
device_type = old_device_config.pop('deviceType', 'default')

old_device_config['deviceInfo'] = {
'deviceNameExpressionSource': 'expression',
'deviceProfileExpressionSource': 'expression',
'deviceNameExpression': device_name,
'deviceProfileExpression': device_type
}

@staticmethod
def __convert_object_id(old_item_config):
old_object_id = old_item_config.pop('objectId')
(object_type, object_id) = old_object_id.split(':')
old_item_config['objectType'] = object_type
old_item_config['objectId'] = object_id

@staticmethod
def is_old_config(config):
if config.get('general'):
return True
Loading
Loading