diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..14b902f --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,4 @@ +0.0 +--- + +- Initial version. diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..f2d2aff --- /dev/null +++ b/__init__.py @@ -0,0 +1,21 @@ +import threading +from plc_to_mongo import PLC_to_Mongo +from poc_to_modbus import ModbusTCPMongoServer + +PLC_IP_ADDRESS = 'denise1601.henryres.poconsole.net' + +scraper_thread = PLC_to_Mongo(PLC_IP_ADDRESS) +server_thread = ModbusTCPMongoServer() + + +def main(): + scraper_thread.start() + server_thread.start() + + +def justscrape(): + scraper_thread.start() + + +def justserve(): + server_thread.start() diff --git a/plc_to_mongo.py b/plc_to_mongo.py index 325dc74..060d9f9 100644 --- a/plc_to_mongo.py +++ b/plc_to_mongo.py @@ -4,83 +4,76 @@ from time import sleep from time import time as now from pymongo import MongoClient import pycomm_helper.utils as plc - -PLC_IP_ADDRESS = '10.20.4.7' +import threading -def main(): - client = MongoClient() - db = client.tag_data +class PLC_to_Mongo(threading.Thread): + def __init__(self, plc_address): + super(PLC_to_Mongo, self).__init__() + client = MongoClient() + self.db = client.tag_data + self.tag_vals = self.db.tag_vals + self.PLC_IP_ADDRESS = plc_address - tag_vals = db.tag_vals - print("THERE ARE ALREADY {} VALUES IN tag_vals".format(tag_vals.count())) - with open('analog.json', 'rb') as analogfile: - analog_list = json.loads(analogfile.read()) + def run(self): + print("THERE ARE ALREADY {} VALUES IN tag_vals".format(self.tag_vals.count())) + with open('analog.json', 'rb') as analogfile: + analog_list = json.loads(analogfile.read()) - with open('digital.json', 'rb') as digitalfile: - digital_list = json.loads(digitalfile.read()) + with open('digital.json', 'rb') as digitalfile: + digital_list = json.loads(digitalfile.read()) - with open('arraylist.json', 'rb') as arrayfile: - arr_list = json.loads(arrayfile.read()) + with open('arraylist.json', 'rb') as arrayfile: + arr_list = json.loads(arrayfile.read()) - for entry in analog_list + digital_list + arr_list: - if tag_vals.find({'tag_name': entry['tag_name']}).count() < 1: - tag_vals.insert(entry) - print("NOW THERE ARE {} VALUES IN tag_vals".format(tag_vals.count())) + for entry in analog_list + digital_list + arr_list: + if self.tag_vals.find({'tag_name': entry['tag_name']}).count() < 1: + self.tag_vals.insert(entry) + print("NOW THERE ARE {} VALUES IN tag_vals".format(self.tag_vals.count())) - while True: - for t in analog_list: - try: - plc_val = plc.readTag(PLC_IP_ADDRESS, t['tag_name']) - if plc_val: - t['tag_type'] = plc_val[1] - t['val'] = plc_val[0] - t['timestamp'] = now() - tag_vals.update({'tag_name': t['tag_name']}, t) - print("Updated: {} - {}".format(t['tag_name'], t['val'])) - except Exception as e: - print("[ERROR] {} - {}".format(t['tag_name'], e)) + while True: + for t in analog_list: + try: + plc_val = plc.readTag(self.PLC_IP_ADDRESS, t['tag_name']) + if plc_val: + t['tag_type'] = plc_val[1] + t['val'] = plc_val[0] + t['timestamp'] = now() + self.tag_vals.update({'tag_name': t['tag_name']}, t) + print("Updated: {} - {}".format(t['tag_name'], t['val'])) + except Exception as e: + print("[ERROR] {} - {}".format(t['tag_name'], e)) - for t in digital_list: - try: - plc_val = plc.readTag(PLC_IP_ADDRESS, t['tag_name']) - if plc_val: - t['tag_type'] = plc_val[1] - t['val'] = plc_val[0] - t['timestamp'] = now() - tag_vals.update({'tag_name': t['tag_name']}, t) - print("Updated: {} - {}".format(t['tag_name'], t['val'])) - except Exception as e: - print("[ERROR] {} - {}".format(t['tag_name'], e)) + for t in digital_list: + try: + plc_val = plc.readTag(self.PLC_IP_ADDRESS, t['tag_name']) + if plc_val: + t['tag_type'] = plc_val[1] + t['val'] = plc_val[0] + t['timestamp'] = now() + self.tag_vals.update({'tag_name': t['tag_name']}, t) + print("Updated: {} - {}".format(t['tag_name'], t['val'])) + except Exception as e: + print("[ERROR] {} - {}".format(t['tag_name'], e)) - for a in arr_list: - try: - plc_val = plc.readArray(PLC_IP_ADDRESS, str(a['tag_name']), int(a['arr_len'])) - if plc_val: - a['val'] = plc_val - a['tag_type'] = 'ARRAY' - t['timestamp'] = now() - tag_vals.update({'tag_name': a['tag_name']}, a) - print("Updated: {} - {}".format(a['tag_name'], a['val'])) - except Exception as e: - print("[ERROR] {} - {}".format(a['tag_name'], e)) + for a in arr_list: + try: + plc_val = plc.readArray(self.PLC_IP_ADDRESS, str(a['tag_name']), int(a['arr_len'])) + if plc_val: + a['val'] = plc_val + a['tag_type'] = 'ARRAY' + t['timestamp'] = now() + self.tag_vals.update({'tag_name': a['tag_name']}, a) + print("Updated: {} - {}".format(a['tag_name'], a['val'])) + except Exception as e: + print("[ERROR] {} - {}".format(a['tag_name'], e)) - sleep(5) + sleep(5) + def purge(self): + client = MongoClient() + db = client.tag_data -def purge(): - client = MongoClient() - db = client.tag_data - - tag_vals = db.tag_vals - tag_vals.delete_many({}) - print("THERE ARE {} VALUES IN tag_vals".format(tag_vals.count())) - -if __name__ == '__main__': - import sys - if len(sys.argv) > 1: - if sys.argv[1] == 'purge': - print("Purging...") - purge() - else: - main() + self.tag_vals = db.tag_vals + self.tag_vals.delete_many({}) + print("THERE ARE {} VALUES IN tag_vals".format(self.tag_vals.count())) diff --git a/poc_to_modbus.py b/poc_to_modbus.py index 21c86b9..d013c86 100644 --- a/poc_to_modbus.py +++ b/poc_to_modbus.py @@ -23,6 +23,7 @@ from pymongo import MongoClient from pycomm_helper import utils as plc from time import time as now import struct +import threading # ---------------------------------------------------------------------------# # configure the service logging # ---------------------------------------------------------------------------# @@ -31,8 +32,6 @@ logging.basicConfig() log = logging.getLogger() log.setLevel(logging.INFO) -PLC_IP_ADDRESS = '10.20.4.7' - def float_to_bytes(float_val): ''' @@ -74,34 +73,6 @@ def lebyte_to_integer(word_list): return unpacked_int -def getTagsFromDB(): - client = MongoClient() - db = client.tag_data - tags = db.tag_vals - print("Found {} tags in the database".format(tags.count())) - di_tags_cur = tags.find({'register_type': 'di'}) - di_tags = list(di_tags_cur) - di_tags_num = di_tags_cur.count() - print("{} Digital Inputs".format(di_tags_num)) - - co_tags_cur = tags.find({'register_type': 'co'}) - co_tags = list(co_tags_cur) - co_tags_num = co_tags_cur.count() - print("{} Coils".format(co_tags_num)) - - ir_tags_cur = tags.find({'register_type': 'ir'}) - ir_tags = list(ir_tags_cur) - ir_tags_num = ir_tags_cur.count() - print("{} Input Registers".format(ir_tags_num)) - - hr_tags_cur = tags.find({'register_type': 'hr'}) - hr_tags = list(hr_tags_cur) - hr_tags_num = hr_tags_cur.count() - print("{} Holding Registers".format(hr_tags_num)) - - return {'di': di_tags, 'co': co_tags, 'ir': ir_tags, 'hr': hr_tags} - - # ---------------------------------------------------------------------------# # create your custom data block with callbacks # ---------------------------------------------------------------------------# @@ -248,34 +219,60 @@ class AnalogTagDataBlock(ModbusSparseDataBlock): print(e) -def main(): - # ---------------------------------------------------------------------------# - # initialize your data store - # ---------------------------------------------------------------------------# - tags_in_db = getTagsFromDB() - di_block = DigitalTagDataBlock('di', tags_in_db['di']) - co_block = DigitalTagDataBlock('co', tags_in_db['co']) - hr_block = AnalogTagDataBlock('hr', tags_in_db['hr']) - ir_block = AnalogTagDataBlock('ir', tags_in_db['ir']) - store = ModbusSlaveContext(di=di_block, co=co_block, hr=hr_block, ir=ir_block) - context = ModbusServerContext(slaves=store, single=True) +def getTagsFromDB(): + client = MongoClient() + db = client.tag_data + tags = db.tag_vals + print("Found {} tags in the database".format(tags.count())) + di_tags_cur = tags.find({'register_type': 'di'}) + di_tags = list(di_tags_cur) + di_tags_num = di_tags_cur.count() + print("{} Digital Inputs".format(di_tags_num)) - # ---------------------------------------------------------------------------# - # initialize the server information - # ---------------------------------------------------------------------------# - identity = ModbusDeviceIdentification() - identity.VendorName = 'pymodbus' - identity.ProductCode = 'PM' - identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' - identity.ProductName = 'pymodbus Server' - identity.ModelName = 'pymodbus Server' - identity.MajorMinorRevision = '1.0' + co_tags_cur = tags.find({'register_type': 'co'}) + co_tags = list(co_tags_cur) + co_tags_num = co_tags_cur.count() + print("{} Coils".format(co_tags_num)) - # ---------------------------------------------------------------------------# - # run the server you want - # ---------------------------------------------------------------------------# - StartTcpServer(context, identity=identity, address=("0.0.0.0", 502)) + ir_tags_cur = tags.find({'register_type': 'ir'}) + ir_tags = list(ir_tags_cur) + ir_tags_num = ir_tags_cur.count() + print("{} Input Registers".format(ir_tags_num)) + + hr_tags_cur = tags.find({'register_type': 'hr'}) + hr_tags = list(hr_tags_cur) + hr_tags_num = hr_tags_cur.count() + print("{} Holding Registers".format(hr_tags_num)) + + return {'di': di_tags, 'co': co_tags, 'ir': ir_tags, 'hr': hr_tags} -if __name__ == '__main__': - main() +class ModbusTCPMongoServer(threading.Thread): + def __init__(self): + # ---------------------------------------------------------------------------# + # initialize your data store + # ---------------------------------------------------------------------------# + tags_in_db = getTagsFromDB() + di_block = DigitalTagDataBlock('di', tags_in_db['di']) + co_block = DigitalTagDataBlock('co', tags_in_db['co']) + hr_block = AnalogTagDataBlock('hr', tags_in_db['hr']) + ir_block = AnalogTagDataBlock('ir', tags_in_db['ir']) + store = ModbusSlaveContext(di=di_block, co=co_block, hr=hr_block, ir=ir_block) + self.context = ModbusServerContext(slaves=store, single=True) + + # ---------------------------------------------------------------------------# + # initialize the server information + # ---------------------------------------------------------------------------# + self.identity = ModbusDeviceIdentification() + self.identity.VendorName = 'pymodbus' + self.identity.ProductCode = 'PM' + self.identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' + self.identity.ProductName = 'pymodbus Server' + self.identity.ModelName = 'pymodbus Server' + self.identity.MajorMinorRevision = '1.0' + + def run(self): + # ---------------------------------------------------------------------------# + # run the server you want + # ---------------------------------------------------------------------------# + StartTcpServer(self.context, identity=self.identity, address=("0.0.0.0", 502)) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..52626c5 --- /dev/null +++ b/setup.py @@ -0,0 +1,52 @@ +import os + +from setuptools import setup, find_packages + +here = os.path.abspath(os.path.dirname(__file__)) +with open(os.path.join(here, 'README.md')) as f: + README = f.read() +with open(os.path.join(here, 'CHANGES.md')) as f: + CHANGES = f.read() + +requires = [ + 'pymongo', + 'pycomm', + 'pymodbus', + 'cryptography', + 'pyasn1' +] + +tests_require = [ + 'pytest', +] + +setup( + name='poc_to_modbustcp', + version='0.0', + description='Modbus TCP Server for Henry POC', + long_description=README + '\n\n' + CHANGES, + classifiers=[ + 'Programming Language :: Python', + 'Framework :: Pyramid', + 'Topic :: Internet :: WWW/HTTP', + 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', + ], + author='', + author_email='', + url='', + keywords='web', + packages=find_packages(), + include_package_data=True, + zip_safe=False, + extras_require={ + 'testing': tests_require, + }, + install_requires=requires, + entry_points={ + 'console_scripts': [ + 'poc_to_modbustcp = poc_to_modbustcp.__init__:main', + 'poc_to_modbustcp_justscrape = poc_to_modbustcp.__init__:justscrape', + 'poc_to_modbustcp_justserve = poc_to_modbustcp.__init__:justserve', + ], + }, +)