added thingsboard gateway files
This commit is contained in:
42
Thingsboard Gateway/ethernetip.json
Normal file
42
Thingsboard Gateway/ethernetip.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "EthernetIP connector",
|
||||
"publishInterval": 600,
|
||||
"devices": [
|
||||
{
|
||||
"name": "Big Test Boi",
|
||||
"type": "plcpond",
|
||||
"ip": "192.168.2.158",
|
||||
"converter": "EthernetIPConverter",
|
||||
"telemetry": {
|
||||
"pond1Height":{"key": "pond1height"},
|
||||
"pond1Volume":{"key": "pond1volume"},
|
||||
"pond2Height":{"key": "pond2height"},
|
||||
"pond2Volume":{"key": "pond2volume"},
|
||||
"pond3Height":{"key": "pond3height"},
|
||||
"pond3Volume":{"key": "pond3volume"},
|
||||
"pond4Height":{"key": "pond4height"},
|
||||
"pond4Volume":{"key": "pond4volume"},
|
||||
"cfgNumberOfPonds":{"key": "numPonds"}
|
||||
},
|
||||
"attributes": {}
|
||||
},
|
||||
{
|
||||
"name": "Big Test Boi",
|
||||
"type": "plcpond",
|
||||
"ip": "166.252.175.224",
|
||||
"converter": "EthernetIPConverter",
|
||||
"telemetry": {
|
||||
"pond1Height":{"key": "pond1height"},
|
||||
"pond1Volume":{"key": "pond1volume"},
|
||||
"pond2Height":{"key": "pond2height"},
|
||||
"pond2Volume":{"key": "pond2volume"},
|
||||
"pond3Height":{"key": "pond3height"},
|
||||
"pond3Volume":{"key": "pond3volume"},
|
||||
"pond4Height":{"key": "pond4height"},
|
||||
"pond4Volume":{"key": "pond4volume"},
|
||||
"cfgNumberOfPonds":{"key": "numPonds"}
|
||||
},
|
||||
"attributes": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
140
Thingsboard Gateway/ethernetip_connector.py
Normal file
140
Thingsboard Gateway/ethernetip_connector.py
Normal file
@@ -0,0 +1,140 @@
|
||||
from pycomm3 import LogixDriver, CommError
|
||||
from datetime import datetime as dt
|
||||
from time import sleep
|
||||
from random import choice
|
||||
from string import ascii_lowercase
|
||||
|
||||
from threading import Thread
|
||||
from thingsboard_gateway.connectors.connector import Connector, log
|
||||
from thingsboard_gateway.tb_utility.tb_utility import TBUtility
|
||||
from thingsboard_gateway.tb_utility.tb_loader import TBModuleLoader
|
||||
|
||||
|
||||
class EthernetIPConnector(Thread, Connector):
|
||||
def __init__(self, gateway, config, connector_type):
|
||||
super().__init__()
|
||||
self.statistics = {'MessagesReceived': 0,
|
||||
'MessagesSent': 0} # Dictionary, will save information about count received and sent messages.
|
||||
self.__config = config # Save configuration from the configuration file.
|
||||
self.__gateway = gateway # Save gateway object, we will use some gateway methods for adding devices and saving data from them.
|
||||
self.setName(self.__config.get("name","%s connector " % self.get_name() + ''.join(choice(ascii_lowercase) for _ in range(5)))) # get from the configuration or create name for logs.
|
||||
log.info("Starting Custom %s connector", self.get_name()) # Send message to logger
|
||||
self.daemon = True # Set self thread as daemon
|
||||
self.stopped = True # Service variable for check state
|
||||
self.__connected = False # Service variable for check connection to device
|
||||
self.__devices = {} # Dictionary with devices, will contain devices configurations, converters for devices and serial port objects
|
||||
self.__load_converters(connector_type) # Call function to load converters and save it into devices dictionary
|
||||
self.__connect_to_devices() # Call function for connect to devices
|
||||
self._connector_type = connector_type
|
||||
self.utilities = TBModuleLoader.import_module(self._connector_type, "Utilities")
|
||||
log.info('Custom connector %s initialization success.', self.get_name()) # Message to logger
|
||||
log.info("Devices in configuration file found: %s ", '\n'.join(device for device in self.__devices)) # Message to logger
|
||||
|
||||
def __connect_to_devices(self):
|
||||
for device in self.__devices:
|
||||
try:
|
||||
log.debug(self.__devices[device]["device_config"]["ip"])
|
||||
self.__devices[device]["logixdriver"] = LogixDriver(self.__devices[device]["device_config"]["ip"])
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
else:
|
||||
self.__gateway.add_device(self.__devices[device]["device_config"]["name"], {"connector": self}, self.__devices[device]["device_config"]["type"])
|
||||
self.__connected = True
|
||||
|
||||
def get_name(self):
|
||||
return self.name #self.__config["name"]
|
||||
|
||||
def is_connected(self):
|
||||
return self.__connected
|
||||
|
||||
def __load_converters(self, connector_type):
|
||||
devices_config = self.__config.get('devices')
|
||||
try:
|
||||
|
||||
if devices_config is not None:
|
||||
for device_config in devices_config:
|
||||
if device_config.get('converter') is not None:
|
||||
log.debug(device_config)
|
||||
converter = TBModuleLoader.import_module(connector_type, device_config['converter'])
|
||||
self.__devices[device_config['name']] = {'converter': converter(device_config),
|
||||
'device_config': device_config}
|
||||
else:
|
||||
log.error('Converter configuration for the custom connector %s -- not found, please check your configuration file.', self.get_name())
|
||||
else:
|
||||
log.error('Section "devices" in the configuration not found. A custom connector %s has being stopped.', self.get_name())
|
||||
self.close()
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
while True:
|
||||
if int(dt.timestamp(dt.now())) % self.__config["publishInterval"] == 0:
|
||||
log.debug("Publish Interval: %s" % dt.now())
|
||||
for device in self.__devices:
|
||||
try:
|
||||
tags = list(self.__devices[device]["device_config"]["telemetry"].keys())
|
||||
with self.__devices[device]["logixdriver"] as driver:
|
||||
data_from_device = driver.read(*tags)
|
||||
log.debug(data_from_device)
|
||||
converted_data = self.__devices[device]['converter'].convert(self.__devices[device]['device_config'], data_from_device)
|
||||
log.debug(converted_data)
|
||||
self.__gateway.send_to_storage(self.get_name(), converted_data)
|
||||
except CommError as ce:
|
||||
log.error("Error connecting to PLC")
|
||||
log.error(ce)
|
||||
except Exception as e:
|
||||
log.error("Error in for loop of run()")
|
||||
log.error(e)
|
||||
sleep(1)
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
def open(self):
|
||||
log.info("Starting EthernetIP Connector")
|
||||
self.stopped = False
|
||||
self.start()
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def on_attributes_update(self, content):
|
||||
log.info(content)
|
||||
if self.__devices.get(content["device"]) is not None:
|
||||
device_config = self.__devices[content["device"]].get("device_config")
|
||||
if device_config is not None and device_config.get("attributeUpdates") is not None:
|
||||
requests = device_config["attributeUpdates"]
|
||||
for request in requests:
|
||||
attribute = request.get("attributeOnThingsBoard")
|
||||
log.debug(attribute)
|
||||
if attribute is not None and attribute in content["data"]:
|
||||
try:
|
||||
value = content["data"][attribute]
|
||||
str_to_send = str(request["stringToDevice"].replace("${" + attribute + "}", str(value))).encode("UTF-8")
|
||||
self.__devices[content["device"]]["serial"].write(str_to_send)
|
||||
log.debug("Attribute update request to device %s : %s", content["device"], str_to_send)
|
||||
time.sleep(.01)
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
|
||||
def server_side_rpc_handler(self, content):
|
||||
log.debug(content)
|
||||
method_split = content["method"].split('_')
|
||||
method = None
|
||||
if len(method_split) > 0:
|
||||
method = "_".join(method_split[1:])
|
||||
|
||||
commands = {
|
||||
"ping": self.utilities.ping,
|
||||
"write_plc": self.utilities.write_plc
|
||||
}
|
||||
|
||||
if method is not None:
|
||||
#check utilities for function
|
||||
log.debug(f"Looking for {method} in Utilities")
|
||||
log.info(self.__devices)
|
||||
if method in commands.keys():
|
||||
if method == "write_plc":
|
||||
log.info(commands[method](self.__devices["Big Test Boi"]["logixdriver"],content))
|
||||
else:
|
||||
log.info(commands[method](content))
|
||||
|
||||
27
Thingsboard Gateway/ethernetip_converter.py
Normal file
27
Thingsboard Gateway/ethernetip_converter.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from thingsboard_gateway.connectors.converter import Converter, log
|
||||
|
||||
|
||||
class EthernetIPConverter(Converter):
|
||||
def __init__(self, config):
|
||||
self.__config = config
|
||||
self.result_dict = {
|
||||
'deviceName': config.get('name', 'EthernetIPDevice'),
|
||||
'deviceType': config.get('deviceType', 'default'),
|
||||
'attributes': [],
|
||||
'telemetry': []
|
||||
}
|
||||
|
||||
def convert(self, config, data):
|
||||
keys = ["attributes", "telemetry"]
|
||||
for k in keys:
|
||||
self.result_dict[k] = []
|
||||
if self.__config.get(k) is not None and data is not None:
|
||||
for datapoint in data:
|
||||
if datapoint[3] == None:
|
||||
try:
|
||||
log.debug(config)
|
||||
converted_data = {config[k][datapoint[0]]["key"]: datapoint[1]}
|
||||
self.result_dict[k].append(converted_data)
|
||||
except KeyError:
|
||||
continue
|
||||
return self.result_dict
|
||||
110
Thingsboard Gateway/tb_gateway.yaml
Normal file
110
Thingsboard Gateway/tb_gateway.yaml
Normal file
@@ -0,0 +1,110 @@
|
||||
thingsboard:
|
||||
host: hp.henrypump.cloud
|
||||
port: 1883
|
||||
remoteShell: true
|
||||
remoteConfiguration: false
|
||||
statsSendPeriodInSeconds: 60
|
||||
minPackSendDelayMS: 0
|
||||
checkConnectorsConfigurationInSeconds: 60
|
||||
security:
|
||||
accessToken: testtesttest
|
||||
qos: 1
|
||||
storage:
|
||||
# type: memory
|
||||
# read_records_count: 100
|
||||
# max_records_count: 100000
|
||||
type: file
|
||||
data_folder_path: ./data/
|
||||
max_file_count: 10
|
||||
max_read_records_count: 10
|
||||
max_records_per_file: 10000
|
||||
# type: sqlite
|
||||
# data_file_path: ./data/data.db
|
||||
# messages_ttl_check_in_hours: 1
|
||||
# messages_ttl_in_days: 7
|
||||
grpc:
|
||||
enabled: false
|
||||
serverPort: 9595
|
||||
keepaliveTimeMs: 10000
|
||||
keepaliveTimeoutMs: 5000
|
||||
keepalivePermitWithoutCalls: true
|
||||
maxPingsWithoutData: 0
|
||||
minTimeBetweenPingsMs: 10000
|
||||
minPingIntervalWithoutDataMs: 5000
|
||||
connectors:
|
||||
-
|
||||
name: Ethernetip Connector
|
||||
type: ethernetip
|
||||
class: EthernetIPConnector
|
||||
configuration: ethernetip.json
|
||||
|
||||
# -
|
||||
# name: Modbus Connector
|
||||
# type: modbus
|
||||
# configuration: modbus.json
|
||||
#
|
||||
# -
|
||||
# name: Modbus Connector
|
||||
# type: modbus
|
||||
# configuration: modbus_serial.json
|
||||
#
|
||||
# -
|
||||
# name: OPC-UA Connector
|
||||
# type: opcua
|
||||
# configuration: opcua.json
|
||||
#
|
||||
# -
|
||||
# name: BLE Connector
|
||||
# type: ble
|
||||
# configuration: ble.json
|
||||
#
|
||||
# -
|
||||
# name: REQUEST Connector
|
||||
# type: request
|
||||
# configuration: request.json
|
||||
#
|
||||
# -
|
||||
# name: CAN Connector
|
||||
# type: can
|
||||
# configuration: can.json
|
||||
#
|
||||
# -
|
||||
# name: BACnet Connector
|
||||
# type: bacnet
|
||||
# configuration: bacnet.json
|
||||
#
|
||||
# -
|
||||
# name: ODBC Connector
|
||||
# type: odbc
|
||||
# configuration: odbc.json
|
||||
#
|
||||
# -
|
||||
# name: REST Connector
|
||||
# type: rest
|
||||
# configuration: rest.json
|
||||
#
|
||||
# -
|
||||
# name: SNMP Connector
|
||||
# type: snmp
|
||||
# configuration: snmp.json
|
||||
#
|
||||
# -
|
||||
# name: FTP Connector
|
||||
# type: ftp
|
||||
# configuration: ftp.json
|
||||
#
|
||||
#
|
||||
# ========= Customization ==========
|
||||
#
|
||||
#
|
||||
# -
|
||||
# name: Custom Serial Connector
|
||||
# type: serial
|
||||
# configuration: custom_serial.json
|
||||
# class: CustomSerialConnector
|
||||
#
|
||||
# -
|
||||
# name: GRPC Connector 1
|
||||
# key: auto
|
||||
# type: grpc
|
||||
# configuration: grpc_connector_1.json
|
||||
Reference in New Issue
Block a user