Files
ThingsBoard/ThingsBoardClient/ethernetip_connector.py
2022-08-20 10:06:20 -05:00

141 lines
5.9 KiB
Python

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