mirror of
https://github.com/thingsboard/thingsboard-gateway
synced 2025-10-26 22:31:42 +08:00
Merge branch 'develop/2.4-python' of https://github.com/thingsboard/thingsboard-gateway into feature/ODBC-connector
This commit is contained in:
6
setup.py
6
setup.py
@@ -52,17 +52,13 @@ setup(
|
||||
'pip',
|
||||
'jsonschema==3.1.1',
|
||||
'lxml',
|
||||
'opcua',
|
||||
'paho-mqtt',
|
||||
'pymodbus>=2.3.0',
|
||||
'pyserial',
|
||||
'pytz',
|
||||
'PyYAML',
|
||||
'simplejson',
|
||||
'pyrsistent',
|
||||
'requests',
|
||||
'python-can',
|
||||
'bacpypes>=0.18.0'
|
||||
'requests'
|
||||
],
|
||||
download_url='https://github.com/thingsboard/thingsboard-gateway/archive/%s.tar.gz' % VERSION,
|
||||
entry_points={
|
||||
|
||||
@@ -136,14 +136,14 @@
|
||||
"rpc": [
|
||||
{
|
||||
"tag": "setValue",
|
||||
"type": "bit",
|
||||
"type": "bits",
|
||||
"functionCode": 5,
|
||||
"objectsCount": 1,
|
||||
"address": 31
|
||||
},
|
||||
{
|
||||
"tag": "getValue",
|
||||
"type": "bit",
|
||||
"type": "bits",
|
||||
"functionCode": 1,
|
||||
"objectsCount": 1,
|
||||
"address": 31
|
||||
|
||||
@@ -12,16 +12,24 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from copy import deepcopy
|
||||
from random import choice
|
||||
from threading import Thread
|
||||
from time import time, sleep
|
||||
from string import ascii_lowercase
|
||||
from bacpypes.core import run, stop
|
||||
|
||||
from thingsboard_gateway.tb_utility.tb_utility import TBUtility
|
||||
|
||||
try:
|
||||
from bacpypes.core import run, stop
|
||||
except ImportError:
|
||||
print("BACnet library not found - installing...")
|
||||
TBUtility.install_package("bacpypes", ">=0.18.0")
|
||||
from bacpypes.core import run, stop
|
||||
|
||||
from bacpypes.pdu import Address, GlobalBroadcast, LocalBroadcast, LocalStation, RemoteStation
|
||||
|
||||
from thingsboard_gateway.connectors.connector import Connector, log
|
||||
from thingsboard_gateway.connectors.bacnet.bacnet_utilities.tb_gateway_bacnet_application import TBBACnetApplication
|
||||
from thingsboard_gateway.tb_utility.tb_utility import TBUtility
|
||||
|
||||
|
||||
class BACnetConnector(Thread, Connector):
|
||||
|
||||
@@ -15,16 +15,22 @@
|
||||
import re
|
||||
import sched
|
||||
import time
|
||||
from threading import Thread
|
||||
from copy import copy
|
||||
from random import choice
|
||||
from string import ascii_lowercase
|
||||
from can import Notifier, BufferedReader, Message, CanError, ThreadSafeBus
|
||||
from threading import Thread
|
||||
|
||||
from thingsboard_gateway.tb_utility.tb_utility import TBUtility
|
||||
try:
|
||||
from can import Notifier, BufferedReader, Message, CanError, ThreadSafeBus
|
||||
except ImportError:
|
||||
print("CAN library not found - installing...")
|
||||
TBUtility.install_package("python-can")
|
||||
from can import Notifier, BufferedReader, Message, CanError, ThreadSafeBus
|
||||
|
||||
from thingsboard_gateway.connectors.can.bytes_can_downlink_converter import BytesCanDownlinkConverter
|
||||
from thingsboard_gateway.connectors.can.bytes_can_uplink_converter import BytesCanUplinkConverter
|
||||
from thingsboard_gateway.connectors.connector import Connector, log
|
||||
from thingsboard_gateway.tb_utility.tb_utility import TBUtility
|
||||
|
||||
|
||||
class CanConnector(Connector, Thread):
|
||||
|
||||
@@ -62,14 +62,15 @@ class BytesModbusDownlinkConverter(ModbusConverter):
|
||||
lower_type = str(variable_size) + "float"
|
||||
assert builder_functions.get(lower_type) is not None
|
||||
builder_functions[lower_type](value)
|
||||
elif lower_type in ["coil", "bits"]:
|
||||
elif lower_type in ["coil", "bits", "coils", "bit"]:
|
||||
assert builder_functions.get("bits") is not None
|
||||
builder_functions["bits"](value)
|
||||
if variable_size/8 > 1.0:
|
||||
builder_functions["bits"](value)
|
||||
else:
|
||||
return bytes(bool(int(value)))
|
||||
elif lower_type in ["string"]:
|
||||
assert builder_functions.get("string") is not None
|
||||
builder_functions[lower_type](value)
|
||||
elif lower_type in ["bit"]:
|
||||
return bytes(bool(int(value)))
|
||||
elif lower_type in builder_functions:
|
||||
builder_functions[lower_type](value)
|
||||
else:
|
||||
|
||||
@@ -36,8 +36,8 @@ class BytesModbusUplinkConverter(ModbusConverter):
|
||||
try:
|
||||
configuration = data[config_data][tag]["data_sent"]
|
||||
response = data[config_data][tag]["input_data"]
|
||||
if config.get("byteOrder"):
|
||||
byte_order = config["byteOrder"]
|
||||
if configuration.get("byteOrder") is not None:
|
||||
byte_order = configuration["byteOrder"]
|
||||
else:
|
||||
byte_order = configuration.get("byteOrder", "LITTLE")
|
||||
endian_order = Endian.Little if byte_order.upper() == "LITTLE" else Endian.Big
|
||||
@@ -47,9 +47,9 @@ class BytesModbusUplinkConverter(ModbusConverter):
|
||||
result = response.bits
|
||||
result = result if byte_order.upper() == 'LITTLE' else result[::-1]
|
||||
log.debug(result)
|
||||
if configuration["type"].lower() == "bit":
|
||||
if configuration["type"].lower() == "bits":
|
||||
decoded_data = result[:configuration.get("objectsCount", configuration.get("registersCount", configuration.get("registerCount", 1)))]
|
||||
if len(decoded_data) == 1:
|
||||
if len(decoded_data) == 1 and isinstance(decoded_data, list):
|
||||
decoded_data = decoded_data[0]
|
||||
else:
|
||||
decoded_data = result[0]
|
||||
@@ -127,10 +127,6 @@ class BytesModbusUplinkConverter(ModbusConverter):
|
||||
assert decoder_functions.get(type_) is not None
|
||||
decoded = decoder_functions[type_]()
|
||||
|
||||
elif lower_type == 'bit':
|
||||
bit_address = configuration["bit"]
|
||||
decoded = decoder_functions[type_]()[bit_address]
|
||||
|
||||
else:
|
||||
log.error("Unknown type: %s", type_)
|
||||
|
||||
@@ -141,7 +137,7 @@ class BytesModbusUplinkConverter(ModbusConverter):
|
||||
elif isinstance(decoded, bytes) and lower_type == "bytes":
|
||||
result_data = decoded
|
||||
elif isinstance(decoded, list):
|
||||
result_data = str(decoded)
|
||||
result_data = decoded
|
||||
elif isinstance(decoded, float):
|
||||
result_data = decoded
|
||||
elif decoded is not None:
|
||||
|
||||
@@ -17,7 +17,15 @@ import threading
|
||||
from random import choice
|
||||
from string import ascii_lowercase
|
||||
|
||||
from pymodbus.constants import Defaults
|
||||
from thingsboard_gateway.tb_utility.tb_utility import TBUtility
|
||||
# Try import Pymodbus library or install it and import
|
||||
try:
|
||||
from pymodbus.constants import Defaults
|
||||
except ImportError:
|
||||
print("Modbus library not found - installing...")
|
||||
TBUtility.install_package("pymodbus", ">=2.3.0")
|
||||
from pymodbus.constants import Defaults
|
||||
|
||||
from pymodbus.client.sync import ModbusTcpClient, ModbusUdpClient, ModbusSerialClient, ModbusRtuFramer, ModbusSocketFramer
|
||||
from pymodbus.bit_write_message import WriteSingleCoilResponse, WriteMultipleCoilsResponse
|
||||
from pymodbus.register_write_message import WriteMultipleRegistersResponse, \
|
||||
@@ -26,7 +34,6 @@ from pymodbus.register_read_message import ReadRegistersResponseBase
|
||||
from pymodbus.bit_read_message import ReadBitsResponseBase
|
||||
from pymodbus.exceptions import ConnectionException
|
||||
|
||||
from thingsboard_gateway.tb_utility.tb_utility import TBUtility
|
||||
from thingsboard_gateway.connectors.connector import Connector, log
|
||||
from thingsboard_gateway.connectors.modbus.bytes_modbus_uplink_converter import BytesModbusUplinkConverter
|
||||
from thingsboard_gateway.connectors.modbus.bytes_modbus_downlink_converter import BytesModbusDownlinkConverter
|
||||
@@ -185,7 +192,20 @@ class ModbusConnector(Connector, threading.Thread):
|
||||
log.exception(e)
|
||||
|
||||
def on_attributes_update(self, content):
|
||||
pass
|
||||
try:
|
||||
for attribute_updates_command_config in self.__devices[content["device"]]["config"]["attributeUpdates"]:
|
||||
for attribute_updated in content["data"]:
|
||||
if attribute_updates_command_config["tag"] == attribute_updated:
|
||||
to_process = {
|
||||
"device": content["device"],
|
||||
"data": {
|
||||
"method": attribute_updated,
|
||||
"params": content["data"][attribute_updated]
|
||||
}
|
||||
}
|
||||
self.__process_rpc_request(to_process, attribute_updates_command_config)
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
|
||||
def __configure_master(self):
|
||||
host = self.__config.get("host", "localhost")
|
||||
@@ -246,6 +266,7 @@ class ModbusConnector(Connector, threading.Thread):
|
||||
def server_side_rpc_handler(self, content):
|
||||
try:
|
||||
if content.get("device") is not None:
|
||||
|
||||
log.debug("Modbus connector received rpc request for %s with content: %s", content["device"], content)
|
||||
if isinstance(self.__devices[content["device"]]["config"]["rpc"], dict):
|
||||
rpc_command_config = self.__devices[content["device"]]["config"]["rpc"].get(content["data"]["method"])
|
||||
@@ -255,6 +276,7 @@ class ModbusConnector(Connector, threading.Thread):
|
||||
for rpc_command_config in self.__devices[content["device"]]["config"]["rpc"]:
|
||||
if rpc_command_config["tag"] == content["data"]["method"]:
|
||||
self.__process_rpc_request(content, rpc_command_config)
|
||||
break
|
||||
else:
|
||||
log.error("Received rpc request, but method %s not found in config for %s.",
|
||||
content["data"].get("method"),
|
||||
@@ -293,12 +315,13 @@ class ModbusConnector(Connector, threading.Thread):
|
||||
WriteSingleRegisterResponse)):
|
||||
log.debug("Write %r", str(response))
|
||||
response = {"success": True}
|
||||
if isinstance(response, Exception):
|
||||
self.__gateway.send_rpc_reply(content["device"],
|
||||
content["data"]["id"],
|
||||
{content["data"]["method"]: str(response)})
|
||||
else:
|
||||
self.__gateway.send_rpc_reply(content["device"],
|
||||
content["data"]["id"],
|
||||
response)
|
||||
if content.get("id") or (content.get("data") is not None and content["data"].get("id")):
|
||||
if isinstance(response, Exception):
|
||||
self.__gateway.send_rpc_reply(content["device"],
|
||||
content["data"]["id"],
|
||||
{content["data"]["method"]: str(response)})
|
||||
else:
|
||||
self.__gateway.send_rpc_reply(content["device"],
|
||||
content["data"]["id"],
|
||||
response)
|
||||
log.debug("%r", response)
|
||||
|
||||
@@ -175,7 +175,7 @@ class MqttConnector(Connector, Thread):
|
||||
self._client.loop_start()
|
||||
if not self._connected:
|
||||
time.sleep(1)
|
||||
except Exception as e:
|
||||
except ConnectionRefusedError as e:
|
||||
self.__log.exception(e)
|
||||
time.sleep(10)
|
||||
|
||||
|
||||
@@ -20,9 +20,14 @@ from random import choice
|
||||
from threading import Thread
|
||||
from string import ascii_lowercase
|
||||
import regex
|
||||
from opcua import Client, ua
|
||||
from simplejson import dumps
|
||||
from thingsboard_gateway.tb_utility.tb_utility import TBUtility
|
||||
try:
|
||||
from opcua import Client, ua
|
||||
except ImportError:
|
||||
print("OPC-UA library not found")
|
||||
TBUtility.install_package("opcua")
|
||||
from opcua import Client, ua
|
||||
from thingsboard_gateway.connectors.connector import Connector, log
|
||||
from thingsboard_gateway.connectors.opcua.opcua_uplink_converter import OpcUaUplinkConverter
|
||||
|
||||
|
||||
@@ -19,12 +19,18 @@ from string import ascii_lowercase
|
||||
from time import sleep, time
|
||||
from re import fullmatch
|
||||
|
||||
import requests
|
||||
from requests import Timeout
|
||||
# import requests
|
||||
from thingsboard_gateway.tb_utility.tb_utility import TBUtility
|
||||
try:
|
||||
from requests import Timeout, request
|
||||
except ImportError:
|
||||
print("Requests library not found - installing...")
|
||||
TBUtility.install_package("requests")
|
||||
from requests import Timeout, request
|
||||
|
||||
from requests.auth import HTTPBasicAuth
|
||||
from requests.exceptions import RequestException
|
||||
|
||||
from thingsboard_gateway.tb_utility.tb_utility import TBUtility
|
||||
from thingsboard_gateway.connectors.connector import Connector, log
|
||||
from thingsboard_gateway.connectors.request.json_request_uplink_converter import JsonRequestUplinkConverter
|
||||
from thingsboard_gateway.connectors.request.json_request_downlink_converter import JsonRequestDownlinkConverter
|
||||
@@ -80,7 +86,7 @@ class RequestConnector(Connector, Thread):
|
||||
response_queue = Queue(1)
|
||||
request_dict = {"config": {**attribute_request,
|
||||
**converted_data},
|
||||
"request": requests.request}
|
||||
"request": request}
|
||||
attribute_update_request_thread = Thread(target=self.__send_request,
|
||||
args=(request_dict, response_queue, log),
|
||||
daemon=True,
|
||||
@@ -102,7 +108,7 @@ class RequestConnector(Connector, Thread):
|
||||
response_queue = Queue(1)
|
||||
request_dict = {"config": {**rpc_request,
|
||||
**converted_data},
|
||||
"request": requests.request}
|
||||
"request": request}
|
||||
request_dict["config"].get("uplink_converter")
|
||||
rpc_request_thread = Thread(target=self.__send_request,
|
||||
args=(request_dict, response_queue, log),
|
||||
@@ -138,7 +144,7 @@ class RequestConnector(Connector, Thread):
|
||||
self.__requests_in_progress.append({"config": endpoint,
|
||||
"converter": converter,
|
||||
"next_time": time(),
|
||||
"request": requests.request})
|
||||
"request": request})
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
|
||||
|
||||
@@ -464,6 +464,7 @@ class TBGatewayService:
|
||||
result = self.__gateway_rpc_methods[method_to_call]()
|
||||
else:
|
||||
result = self.__gateway_rpc_methods[method_to_call]()
|
||||
log.debug(result)
|
||||
return result
|
||||
|
||||
def __rpc_ping(self, *args):
|
||||
|
||||
@@ -166,7 +166,7 @@ class EventStorageReader:
|
||||
def delete_read_file(self, current_file: EventStorageReaderPointer):
|
||||
try:
|
||||
data_files = self.files.get_data_files()
|
||||
if exists(self.settings.get_data_folder_path() + current_file.file):
|
||||
if exists(self.settings.get_data_folder_path() + current_file.file) and len(data_files) > 1:
|
||||
remove(self.settings.get_data_folder_path() + current_file.file)
|
||||
data_files.remove(current_file.file)
|
||||
log.info("FileStorage_reader -- Cleanup old data file: %s%s!", self.settings.get_data_folder_path(), current_file.file)
|
||||
|
||||
@@ -47,7 +47,10 @@ class TBUtility:
|
||||
error = 'No telemetry and attributes in data: '
|
||||
if error is not None:
|
||||
json_data = dumps(data)
|
||||
log.error(error+json_data.decode("UTF-8"))
|
||||
if isinstance(json_data, bytes):
|
||||
log.error(error+json_data.decode("UTF-8"))
|
||||
else:
|
||||
log.error(error + json_data)
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -137,3 +140,12 @@ class TBUtility:
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
return full_value
|
||||
|
||||
@staticmethod
|
||||
def install_package(package, version="upgrade"):
|
||||
from sys import executable
|
||||
from subprocess import check_call
|
||||
if version.lower() == "upgrade":
|
||||
check_call([executable, "-m", "pip", "install", package, "--upgrade", "--user"])
|
||||
else:
|
||||
check_call([executable, "-m", "pip", "install", package + version, "--user"])
|
||||
|
||||
Reference in New Issue
Block a user