commit 340ac5ab604ef11fe68558eca533fe9970cf7625 Author: Patrick McDonagh Date: Tue Dec 8 22:19:39 2015 -0600 Initial Commit diff --git a/alarmLogger.py b/alarmLogger.py new file mode 100644 index 0000000..1bcdce3 --- /dev/null +++ b/alarmLogger.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python + +''' +Created on Oct 1, 2014 + +@author: PJMcdona +''' + +from datetime import datetime +from random import randint +from time import sleep +import sys + +# MYSQL Config +import MySQLdb + +db = MySQLdb.connect(host="127.0.0.1", user="website", passwd="henrypump", db="WellData") +cur = db.cursor() +query = "SELECT * FROM WellData.config ORDER BY dateChanged DESC LIMIT 1;" +cur.execute(query) +setup = cur.fetchall() +db.commit() +db.close() + +PLC_IP_ADDRESS = setup[0][2] +PLC_TYPE = setup[0][1] + +sys.path.append("../") + + +path_to_CSV = "/mnt/usb/" + +# TUXEIP Connection to PLC +# TUXEIP Connection to PLC +from tuxeip import TuxEIP, LGX, LGX_REAL + +tux = TuxEIP(libpath="/usr/lib/libtuxeip.so") +sess = tux.OpenSession(PLC_IP_ADDRESS) +reg = tux.RegisterSession(sess) +conn = tux.ConnectPLCOverCNET(sess, LGX, 1, 100, 123, randint(0, 9999), 123, 321, 100, 5000, 1, '01') + + + +safetySetup = [["Safety_Casing_Pressure", "Casing Pressure"], + ["Safety_Flow_Line_Pressure", "Flow Line Pressure"], + ["Safety_Flowmeter", "Flowmeter"], + ["Safety_Fluid_Load", "Fluid Load"], + ["Safety_Inclinometer", "Inclinometer"], + ["Safety_Load_HiHi", "Load HiHi"], + ["Safety_Load_Hi", "Load Hi"], + ["Safety_Load_Lo", "Load Lo"], + ["Safety_Load_LoLo", "Load LoLo"], + ["Safety_Speed", "Speed"], + ["Safety_Tubing_Pressure", "Tubing Pressure"] + ] + +condition = { + 20: "Low", + 21: "High", + 24: "LoLo", + 25: "HiHi", + 32: "Input Failure", + 34: "Configuration Error", + 16: "Failure to Stop", + 17: "Failure to Start", + 18: "Drive Fault" +} + +bitsSetup = [ + ["Pump.Auto_Stop", "Pump Off (Auto Mode)", "Unit Stop"], + ["Pump.POC_Stop", "Pump Off (POC Mode)", "Unit Stop"], + ["Pump.Timed_Stop", "Pump Off (Timer Mode)", "Unit Stop"], + ["Pump.Stop", "User Initiated Stop", "Unit Stop"], + ["PeakEnergy.Stop", "Peak Energy Stop", "Unit Stop"], + ["Pump.Start", "User Initiated Start", "Unit Start"], + ["Pump.POC_Restart", "Restart (POC Mode)", "Unit Start"], + ["Pump.Timed_Restart", "Restart (Timer Mode)", "Unit Start"], + ["Pump.Auto_Restart", "Restart (Auto Mode)", "Unit Start"], + ["PeakEnergy.Restart", "Peak Energy Restart", "Unit Start"], + ["Pump.Jog", "Unit Jogged", "Unit Jog"], +] + +safetyList = [] +bitList = [] + + +class SafetyTag: + """Safety structure""" + + def __init__(self, tag, name): + self.name = name + self.tag = tag + self.alarm = False + self.warning = False + self.condition = "" + self.type = "" + self.value = 0.0 + self.stored = False + + def writeToDB(self): + global tux + global sess + global conn + global condition + stroke_num = int(tux.ReadLGXDataAsInteger(sess, conn, "Stroke_Count_Today", 1)[0]) + db = MySQLdb.connect(host="127.0.0.1", user="website", passwd="henrypump", db="WellData") + cur = db.cursor() + event_query = "INSERT INTO WellData.Event_List (device_name, type, cond, value, datetime, tag, stroke_number) VALUES ('{0}', '{1}', '{2}', {3}, '{4}', '{5}', {6});".format( + self.name, self.type, self.condition, self.value, datetime.now(), self.name, stroke_num) + print event_query + store_event = cur.execute(event_query) + db.commit() + db.close() + self.stored = True + + def ReadStatus(self): + global tux + global sess + global conn + global condition + try: + a = tux.ReadLGXDataAsInteger(sess, conn, self.tag + ".Alarm", 1) + w = tux.ReadLGXDataAsInteger(sess, conn, self.tag + ".Warning", 1) + aInt = int(a[0]) + wInt = int(w[0]) + if aInt == 1: + self.alarm = True + self.condition = condition[tux.ReadLGXDataAsInteger(sess, conn, self.tag + ".Alarm_Code", 1)] + self.value = round(tux.ReadLGXDataAsInteger(sess, conn, self.tag + ".Alarm_Value", 1), 3) + self.type = "Alarm" + if (self.stored == False): + self.writeToDB() + elif wInt == 1: + self.warning = True + self.condition = condition[tux.ReadLGXDataAsInteger(sess, conn, self.tag + ".Alarm_Code", 1)] + self.value = round(tux.ReadLGXDataAsInteger(sess, conn, self.tag + ".Alarm_Value", 1), 3) + self.type = "Warning" + if (self.stored == False): + self.writeToDB() + else: + self.alarm = False + self.warning = False + self.condition = "" + self.type = "" + self.stored = False + except: + print "Unable to read " + self.tag + + +class BitTag: + """Safety structure""" + + def __init__(self, tag, name, condition): + self.name = name + self.tag = tag + self.condition = condition + self.type = "Info" + self.value = 0.0 + self.stored = False + + def writeToDB(self): + global tux + global sess + global conn + global condition + stroke_num = int(tux.ReadLGXDataAsInteger(sess, conn, "Stroke_Count_Today", 1)[0]) + db = MySQLdb.connect(host="127.0.0.1", user="website", passwd="henrypump", db="WellData") + cur = db.cursor() + event_query = "INSERT INTO WellData.Event_List (device_name, type, cond, value, datetime, tag, stroke_number) VALUES ('{0}', '{1}', '{2}', {3}, '{4}', '{5}', {6});".format( + self.name, self.type, self.condition, self.value, datetime.now(), self.name, stroke_num) + print event_query + store_event = cur.execute(event_query) + db.commit() + db.close() + self.stored = True + + def ReadStatus(self): + global tux + global sess + global conn + global condition + try: + a = tux.ReadLGXDataAsInteger(sess, conn, self.tag, 1) + aInt = int(a[0]) + # print self.tag + ": " + str(aInt) + if aInt <> 0: + if (self.stored == False): + self.writeToDB() + else: + self.stored = False + except: + print "Unable to read " + self.tag + + +for saf in safetySetup: + safetyList.append(SafetyTag(saf[0], saf[1])) + +for bit in bitsSetup: + bitList.append(BitTag(bit[0], bit[1], bit[2])) + +if (PLC_TYPE == "VFD"): + safetyList.append(SafetyTag("Safety_Pump_PF755", "Drive")) +if (PLC_TYPE == "E300"): + safetyList.append(SafetyTag("Safety_E300", "Relay Overload")) + +while True: + for s in safetyList: + s.ReadStatus() + for b in bitList: + b.ReadStatus() + sleep(.50) diff --git a/alarmLogger_pycomm.py b/alarmLogger_pycomm.py new file mode 100644 index 0000000..1ecacbc --- /dev/null +++ b/alarmLogger_pycomm.py @@ -0,0 +1,143 @@ +#!/usr/bin/python + +from datetime import datetime +from time import sleep +import sys + +# MYSQL Config +import MySQLdb + +db = MySQLdb.connect(host="127.0.0.1", user="website", passwd="henrypump", db="WellData") +cur = db.cursor() +query = "SELECT * FROM WellData.config ORDER BY dateChanged DESC LIMIT 1;" +cur.execute(query) +setup = cur.fetchall() +db.commit() +db.close() + +try: + PLC_IP_ADDRESS = setup[0][2] + PLC_TYPE = setup[0][1] +except: + print("PLC Address not set in database... using default of 192.168.1.10") + PLC_IP_ADDRESS = "192.168.1.10" + PLC_TYPE = "VFD" + +#PYCOMM Connection to PLC +from pycomm.ab_comm.clx import Driver as ClxDriver +from pycomm.ab_comm.clx import CommError as ClxCommError +from pycomm.ab_comm.clx import DataError as ClxDataError +c = ClxDriver(True, 'ClxDriver.log') + +safetySetup = [{'tag':"Safety_Casing_Pressure", 'name':"Casing Pressure", "active":False}, + {'tag':"Safety_Flow_Line_Pressure", 'name':"Flow Line Pressure", "active":False}, + {'tag':"Safety_Flowmeter", 'name':"Flowmeter", "active":False}, + {'tag':"Safety_Fluid_Load", 'name':"Fluid Load", "active":False}, + {'tag':"Safety_Inclinometer", 'name':"Inclinometer", "active":False}, + {'tag':"Safety_Load_HiHi", 'name':"Load HiHi", "active":False}, + {'tag':"Safety_Load_Hi", 'name':"Load Hi", "active":False}, + {'tag':"Safety_Load_Lo", 'name':"Load Lo", "active":False}, + {'tag':"Safety_Load_LoLo", 'name':"Load LoLo", "active":False}, + {'tag':"Safety_Speed", 'name':"Speed", "active":False}, + {'tag':"Safety_Tubing_Pressure", 'name':"Tubing Pressure", "active":False} +] + +condition = { + 20: "Low", + 21: "High", + 24: "LoLo", + 25: "HiHi", + 32: "Input Failure", + 34: "Configuration Error", + 16: "Failure to Stop", + 17: "Failure to Start", + 18: "Drive Fault" +} + +bitsSetup = [ + {'tag':"Pump.Auto_Stop", 'name':"Pump Off (Auto Mode)", 'condition':"Unit Stop", 'active':False}, + {'tag':"Pump.POC_Stop", 'name':"Pump Off (POC Mode)", 'condition':"Unit Stop", 'active':False}, + {'tag':"Pump.Timed_Stop", 'name':"Pump Off (Timer Mode)", 'condition':"Unit Stop", 'active':False}, + {'tag':"Pump.Stop", 'name':"User Initiated Stop", 'condition':"Unit Stop", 'active':False}, + {'tag':"PeakEnergy.Stop", 'name':"Peak Energy Stop", 'condition':"Unit Stop", 'active':False}, + {'tag':"Pump.Start", 'name':"User Initiated Start", 'condition':"Unit Start", 'active':False}, + {'tag':"Pump.POC_Restart", 'name':"Restart (POC Mode)", 'condition':"Unit Start", 'active':False}, + {'tag':"Pump.Timed_Restart", 'name':"Restart (Timer Mode)", 'condition':"Unit Start", 'active':False}, + {'tag':"Pump.Auto_Restart", 'name':"Restart (Auto Mode)", 'condition':"Unit Start", 'active':False}, + {'tag':"PeakEnergy.Restart", 'name':"Peak Energy Restart", 'condition':"Unit Start", 'active':False}, + {'tag':"Pump.Jog", 'name':"Unit Jogged", 'condition':"Unit Jog", 'active':False}, +] + +def write_alarm(name, type, condition, value, tag): + """writes the specified alarm to the MySQL database""" + global c + + stroke_num = int(c.read_tag(["Stroke_Count_Today"])[0][1]) + db = MySQLdb.connect(host="127.0.0.1", user="website", passwd="henrypump", db="WellData") + cur = db.cursor() + event_query = "INSERT INTO WellData.Event_List (device_name, type, cond, value, datetime, tag, stroke_number) VALUES ('{0}', '{1}', '{2}', {3}, '{4}', '{5}', {6});".format( + name, type, condition, value, datetime.now(), tag, stroke_num) + print event_query + store_event = cur.execute(event_query) + db.commit() + db.close() + +c.open(PLC_IP_ADDRESS) +retry = False +number_of_retry = 0 +while True: + try: + if retry: + retry = False + print "retrying" + sleep(0.5) + c.forward_close() + if number_of_retry >= 5: + c.close() + c.open(PLC_IP_ADDRESS) + number_of_retry = 0 + + for safety in safetySetup: + try: + alarm_sts = int(c.read_tag(["{0}.Alarm".format(safety['tag'])])[0][1]) + warning_sts = int(c.read_tag([safety['tag'] + ".Warning"])[0][1]) + print("Tag: {0}, Alarm: {1}, Warning: {2}".format(safety['tag'], alarm_sts, warning_sts)) + safety_type = "" + if alarm_sts == 1: + safety_type = "Alarm" + if warning_sts == 1: + safety_type = "Warning" + if (alarm_sts == 1 or warning_sts == 1): + safety_condition = condition[c.read_tag(["{0}.Alarm_Code".format(safety['tag'])])[0][1]] + safety_value = round(c.read_tag(["{0}.Alarm_Value".format(safety['tag'])])[0][1], 3) + if not safety['active']: + write_alarm(safety['name'], safety_type, safety_condition, safety_value, safety['tag']) + safety['active'] = True + else: + safety['active'] = False + except Exception, e: + print("[ERROR] Error reading safety {0}: {1}".format(safety['tag'], e)) + for bit in bitsSetup: + try: + bit_sts = int(c.read_tag([bit['tag']])[0][1]) + print("Tag: {0}, Status: {1}".format(bit['tag'], bit_sts)) + bit_type = "Info" + if bit_sts == 1: + bit_condition = bit['condition'] + bit_value = 0.0 + if not bit['active']: + write_alarm(bit['name'], bit_type, bit_condition, bit_value, bit['tag']) + bit['active'] = True + else: + bit['active'] = False + except Exception, e: + print("[ERROR] Error reading bit {0}: {1}".format(bit['tag'], e)) + + sleep(0.5) + except ClxCommError as e: + print(e) + retry = True + + except ClxDataError as e: + print (e) +c.close() diff --git a/backupPLC.py b/backupPLC.py new file mode 100644 index 0000000..541ef46 --- /dev/null +++ b/backupPLC.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python + +''' +Created on Oct 1, 2014 + +@author: PJMcdona +''' + + +#from prettytable import PrettyTable +import csv +from datetime import datetime +import os +import sys +from random import randint +from time import sleep +import MySQLdb + + + +db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") +cur = db.cursor() +query = "SELECT * FROM WellData.config ORDER BY dateChanged DESC LIMIT 1;" +cur.execute(query) +setup = cur.fetchall() +db.commit() +db.close() + +PLC_IP_ADDRESS = setup[0][2] +PLC_TYPE = setup[0][1] + +sys.path.append("../") + +path_to_CSV = "/mnt/usb/" + +#TUXEIP Connection to PLC +from tuxeip import TuxEIP, LGX, LGX_REAL +tux = TuxEIP(libpath="/usr/lib/libtuxeip.so") +sess = tux.OpenSession(PLC_IP_ADDRESS) +reg = tux.RegisterSession(sess) +conn = tux.ConnectPLCOverCNET(sess, LGX, 1, 100, 123, randint(0,9999), 123, 321, 100, 5000, 1, '01') + +now = datetime.now() +nowDT = datetime.strftime(now,"%Y%m%d_%H%M%S") +filename = path_to_CSV + "backup_"+nowDT+".csv" + +if os.path.exists(filename): + os.remove(filename) + +taper_setup_params = [ + ["Length","REAL"], + ["Diameter","REAL"], + ["Material","DINT"], + ["c","REAL"], + ["UseRodCount","BOOL"], + ["RodCount","DINT"] + ] + +data = {} + +tags_to_read = [['Casing_ID', 'REAL'], + ['UnitConfig.MotorNameplate.Volts', 'REAL'], + ['UnitConfig.MotorNameplate.Amps', 'REAL'], + ['UnitConfig.MotorNameplate.Hertz', 'REAL'], + ['UnitConfig.MotorNameplate.Poles', 'INT'], + ['UnitConfig.MotorNameplate.RPM', 'REAL'], + ['UnitConfig.MotorNameplate.ServiceFactor', 'REAL'], + ['UnitConfig.MotorNameplate.Horsepower', 'REAL'], + ['UnitConfig.Pump_Diameter', 'REAL'], + ['UnitConfig.Pump_Constant', 'REAL'], + ['UnitConfig.Anchor_Depth', 'REAL'], + ['UnitConfig.Total_Stroke_Length', 'REAL'], + ['UnitConfig.Motor_Sheave_Size', 'REAL'], + ['UnitConfig.Gearbox_Limit', 'REAL'], + ['UnitConfig.Gearbox_Ratio', 'REAL'], + ['UnitConfig.Gearbox_Sheave', 'REAL'], + ['UnitConfig.RPM_Maximum', 'REAL'], + ['UnitConfig.RPM_Minimum', 'REAL'], + ['UnitConfig.MotorCntrlMode', 'DINT'], + ['UnitConfig.MaxFreq', 'REAL'], + ['UnitConfig.Speed_Torque_Mode', 'DINT'], + ['UnitConfig.Rating_Gearbox', 'REAL'], + ['UnitConfig.Rating_Structural', 'REAL'], + ['UnitConfig.Well_Type', 'SINT'], + ['UnitConfig.Total_Vertical_Depth', 'REAL'], + ['UnitConfig.Total_Vertical_Depth_Input', 'REAL'], + ['UnitConfig.Tubing_Size_ID', 'REAL'], + ['UnitConfig.Tubing_Size_OD', 'REAL'], + ['UnitConfig.API_Oil', 'REAL'], + ['UnitConfig.SG_Water', 'REAL'], + ['UnitConfig.Percent_Water', 'REAL'], + ['Youngs_Modulus_Fiberglass', 'REAL'], + ['Youngs_Modulus_Steel', 'REAL'], + ] + + +def ReadFromPLC(tag, tag_type): + try: + if (tag_type == "REAL"): + a = tux.ReadLGXDataAsFloat(sess, conn, tag, 1) + result = round(float(a[0]),3) + #elif (tag_type == "INT" or tag_type == "DINT" or tag_type =="SINT"): + elif tag_type[-3:] == "INT": + a = tux.ReadLGXDataAsInteger(sess, conn, tag, 1) + result = int(a[0]) + elif (tag_type == "BOOL"): + a = tux.ReadLGXDataAsInteger(sess, conn, tag, 1) + intermediate = int(a[0]) + if intermediate == 0: + result = 0 + else: + result = 1 + elif (tag_type =="STRING"): + a = tux.ReadLGXDataAsInteger(sess, conn, tag, 82) + word = "" + for ch in range(len(a)): + word = word + unichr(int(a[ch])) + result = word + else: + result = "?" + return result + except: + print "Unable to read " + tag + return 911 + + +myfile = open(filename, 'wb') +wr = csv.writer(myfile) +for t in tags_to_read: + tagVal = ReadFromPLC(t[0],t[1]) + if tagVal != 911: + wr.writerow([t[0], tagVal, t[1]]) +wr.writerow(["TAPER", "CONFIG"]) +for i in range(0,11): + for p in taper_setup_params: + wr.writerow(["Taper.Taper[" + str(i) + "].Setup." + p[0], ReadFromPLC("Taper.Taper[" + str(i) + "].Setup." + p[0], p[1]), p[1]]) +myfile.close() +print "Backed up PLC settings to", filename diff --git a/calibrateInclinometer.py b/calibrateInclinometer.py new file mode 100644 index 0000000..178d983 --- /dev/null +++ b/calibrateInclinometer.py @@ -0,0 +1,92 @@ +import readTag +import writeTag +from time import sleep +import sys + +def main(): + print ("Getting original limits...") + read_min = readTag.main("Input_Inclinometer_AIN.Cfg_InpRawMin") + if read_min['status']== 'success': + prev_min = read_min['value'] + print ("Previous Min. Value: {0}".format(prev_min)) + else: + print("Could not find previous min. value.") + print("Error: {0}".format(read_min['message'])) + sys.exit(1) + + read_max = readTag.main("Input_Inclinometer_AIN.Cfg_InpRawMax") + if read_max['status']== 'success': + prev_max = read_max['value'] + print ("Previous Max. Value: {0}".format(prev_max)) + else: + print("Could not find previous max. value.") + print("Error: {0}".format(read_max['message'])) + sys.exit(1) + + write_calibrate = writeTag.main("Input_Inclinometer_Calibrate", 1) + if write_calibrate['status']== 'success': + sleep(2) + unset_calibrate = writeTag.main("Input_Inclinometer_Calibrate", 0) + if unset_calibrate['status']== 'success': + check_calibrating = readTag.main("Inclinometer_Calibrating") + if check_calibrating['status']== 'success' and check_calibrating['value']== 1: + print ("Successfully Initiated Calibration...") + i = 0 + while i < 30: + x = 2 + print("[{0} s. Remaining] - Waiting for calibration".format(30 - i)) + sleep(x) + i = i + x + + check_calibrating_again = readTag.main("Inclinometer_Calibrating") + if check_calibrating_again['status']== 'success' and check_calibrating_again['value']== 0: + print ("Successfully Completed Calibration...") + + read_min_again = readTag.main("Input_Inclinometer_AIN.Cfg_InpRawMin") + if read_min_again['status']== 'success': + new_min = read_min_again['value'] + print ("New Min. Value: {0}".format(new_min)) + else: + print("Could not find new min. value.") + print("Error: {0}".format(read_min_again['message'])) + sys.exit(1) + + read_max_again = readTag.main("Input_Inclinometer_AIN.Cfg_InpRawMax") + if read_max_again['status']== 'success': + new_max = read_max_again['value'] + print ("New Max. Value: {0}".format(new_max)) + else: + print("Could not find new max. value.") + print("Error: {0}".format(read_max_again['message'])) + sys.exit(1) + + print("Calibration process complete. Thanks for playing...") + + else: + if check_calibrating_again['message']: + print("Error reading Inclinometer_Calibrating") + print("Error: {0}".format(write_calibrate['message'])) + else: + print("Calibration still running. Something went wrong.") + sys.exit(1) + + else: + if write_calibrate['message']: + print("Error reading Inclinometer_Calibrating") + print("Error: {0}".format(write_calibrate['message'])) + else: + print("Calibration not started. Is the pump running?") + sys.exit(1) + + else: + print("Could not write 0 to Input_Inclinometer_Calibrate") + print("Error: {0}".format(write_calibrate['message'])) + sys.exit(1) + + else: + print("Could not write 1 to Input_Inclinometer_Calibrate") + print("Error: {0}".format(write_calibrate['message'])) + sys.exit(1) + +if __name__ == '__main__': + main() diff --git a/dataLogger.py b/dataLogger.py new file mode 100644 index 0000000..4aac854 --- /dev/null +++ b/dataLogger.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python + +''' +Created on Oct 1, 2014 + +@author: PJMcdona +''' + + +#from prettytable import PrettyTable +import csv +from datetime import datetime +import os +import sys +from random import randint +import time +import MySQLdb + + + +db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") +cur = db.cursor() +query = "SELECT * FROM WellData.config ORDER BY dateChanged DESC LIMIT 1;" +cur.execute(query) +setup = cur.fetchall() +db.commit() +db.close() + +PLC_IP_ADDRESS = setup[0][2] +PLC_TYPE = setup[0][1] + +sys.path.append("../") + +path_to_CSV = "/mnt/usb/" + +#TUXEIP Connection to PLC +from tuxeip import TuxEIP, LGX, LGX_REAL +tux = TuxEIP(libpath="/usr/lib/libtuxeip.so") +sess = tux.OpenSession(PLC_IP_ADDRESS) +reg = tux.RegisterSession(sess) +conn = tux.ConnectPLCOverCNET(sess, LGX, 1, 100, 123, randint(0,9999), 123, 321, 100, 5000, 1, '01') + +if os.path.exists(path_to_CSV + "current.csv"): + os.remove(path_to_CSV + "current.csv") + + + +data = {} + +tags_to_read = [['Card_Past[1].ID', 'INT', "Card_ID"], + ['Card_Past[1].Params.Num_Tapers', 'INT', 'Num_Tapers'], + ['Card_Past[1].Num_Points', 'INT', 'Num_Points'], + ['Card_Past[1].Card_Type', 'INT', 'Card_Type'], + ['Card_Past[1].Name.Data[0]','STRING', 'Well_Name'], + ['Card_Past[1].Params.Tubing_Head_Pressure','REAL', 'Tubing_Head_Pressure'], + ['Card_Past[1].Params.Fluid_Gradient','REAL', 'Fluid_Gradient'], + ['Card_Past[1].Params.Stuffing_Box_Friction','REAL', 'Stuffing_Box_Friction'], + ['Card_Past[1].Params.dt','REAL', 'dt'], + ['Card_Past[1].Downhole_Max_Load.Load','REAL', 'Downhole_Max_Load'], + ['Card_Past[1].Downhole_Min_Load.Load','REAL', 'Downhole_Min_Load'], + ['Card_Past[1].Downhole_Max_Position.Position','REAL', 'Downhole_Max_Position'], + ['Card_Past[1].Downhole_Min_Position.Position','REAL', 'Downhole_Min_Position'], + ['Card_Past[1].Downhole_GrossStroke','REAL', 'Downhole_Gross_Stroke'], + ['Card_Past[1].Downhole_AdjustedGrossStroke','REAL', 'Downhole_Adjusted_Gross_Stroke'], + ['Card_Past[1].Downhole_NetStroke','REAL', 'Downhole_Net_Stroke'], + ['Card_Past[1].Downhole_FluidLoad','REAL', 'Downhole_Fluid_Load'], + ['Card_Past[1].Surface_Max.Load','REAL', 'Surface_Max_Load'], + ['Card_Past[1].Surface_Min.Load','REAL', 'Surface_Min_Load'], + ['Card_Past[1].Surface_Max.Position','REAL', 'Surface_Max_Position'], + ['Card_Past[1].Surface_Min.Position','REAL', 'Surface_Min_Position'], + ['Card_Past[1].Tubing_Movement','REAL', 'Tubing_Movement'], + ['Card_Past[1].Surface_StrokeLength','REAL', 'Surface_Stroke_Length'], + ['Card_Past[1].Fillage_Percent','REAL', 'Fillage_Percent'], + ['Card_Past[1].Polished_Rod_HP','REAL', 'Polished_Rod_HP'], + ['Card_Past[1].Pump_HP','REAL', 'Pump_HP'], + ['Card_Past[1].SPM','REAL', 'SPM'], + ['Card_Past[1].Fluid_Above_Pump','REAL', 'Fluid_Above_Pump'], + ['Card_Past[1].Pump_Intake_Pressure','REAL', 'Pump_Intake_Pressure'], + ['Stroke_Production','REAL', 'Stroke_Production'], + ['DriveTorqueMode','BOOL', 'Drive_Torque_Mode'], + ['PF755_Drive:O.TrqRefAStpt','REAL', 'Torque_Reference'], + ['Pump_PF755.PSet_SpeedRef','REAL', 'Speed_Reference'], + ] + +datetime_tags = [ + ['Card_Past[1].End_Time.Year', 'INT', '_Year'], + ['Card_Past[1].End_Time.Month', 'INT', '_Month'], + ['Card_Past[1].End_Time.Day', 'INT', '_Day'], + ['Card_Past[1].End_Time.Hour', 'INT', '_Hour'], + ['Card_Past[1].End_Time.Min', 'INT', '_Minute'], + ['Card_Past[1].End_Time.Sec', 'INT', '_Second'] +] + + +def ReadFromPLC(tag, tag_type): + try: + if (tag_type == "REAL"): + a = tux.ReadLGXDataAsFloat(sess, conn, tag, 1) + #print a + result = float(a[0]) + #print tag, result + elif (tag_type == "INT"): + a = tux.ReadLGXDataAsInteger(sess, conn, tag, 1) + #print a + result = int(a[0]) + #print tag, result + elif (tag_type == "BOOL"): + a = tux.ReadLGXDataAsInteger(sess, conn, tag, 1) + val = int(a[0]) + if val != 0: + val = 1 + result = val + elif (tag_type =="STRING"): + #print "./read_"+tag_type+ " , " + tag + a = tux.ReadLGXDataAsInteger(sess, conn, tag, 82) + #print a + #split_chars = a.split(",") + #print split_chars + word = "" + for ch in range(len(a)): + word = word + unichr(int(a[ch])) + #print word + result = word + else: + result = "?" + return result + except: + print "Unable to read " + tag + return 911 + +def readPoints(): + surface = [] + downhole = [] + for i in range(0, data['Num_Points']): + sp = round(ReadFromPLC("Card_Past[1].Surface_Position[" + str(i) + "]", "REAL"),3) + sl = round(ReadFromPLC("Card_Past[1].Surface_Load[" + str(i) + "]", "REAL"),3) + surface.append([sp,sl]) + + dp = round(ReadFromPLC("Card_Past[1].Downhole_Position[" + str(i) + "]", "REAL"),3) + dl = round(ReadFromPLC("Card_Past[1].Downhole_Load[" + str(i) + "]", "REAL"),3) + downhole.append([dp, dl]) + + +def readSetpoints(): + modeMap = { + 0: "Error", + 1: "Auto", + 2: "POC", + 3: "Timer", + 4: "Manual", + 5: "DH PID" + } + + + with open('/mnt/usb/setpoints.csv', 'w') as setpoint_file: + wr = csv.writer(setpoint_file) + stroke_time = time.time() + dt = datetime.fromtimestamp(stroke_time) + wr.writerow(['localtime', dt]) + wr.writerow(['utctime', datetime.utcfromtimestamp(stroke_time)]) + wr.writerow(['Mode', ReadFromPLC("Pump.Mode", "INT")]) + wr.writerow(['Speed_Setpoint_SPM', ReadFromPLC("Pump.Speed_Setpoint_SPM", "REAL")]) + wr.writerow(['Speed_Max', ReadFromPLC("Pump.Speed_Max", "REAL")]) + wr.writerow(['Speed_Min', ReadFromPLC("Pump.Speed_Min", "REAL")]) + wr.writerow(['Auto-Speed_Startpoint_SPM', ReadFromPLC("Pump.Speed_Startpoint_SPM_Auto", "REAL")]) + wr.writerow(['Auto-Percentage_Ramp_Down', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-Increment_Ramp_Down', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-Percent_Ramp_Up', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-Percent_Ramp_Down', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-Min_Speed_Strokes', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-Percent_Ramp_Up', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-POC-Startup_Ignore_Cards', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-POC-Card_Quantity', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-Percent_Ramp_Up', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['POC-Percent_Pumpoff', ReadFromPLC("Pump.Mode", "REAL")]) + + +cards_read = 1 +read_tapers = False +already_gauged_off = False +already_entered_well_test = False +while True: + now = datetime.now() + with open('/mnt/usb/status.txt', 'w') as status_file: + status_file.write("{0}-->{1}\n{2},{3},{4},{5}".format(datetime.strftime(now,"%Y%m%d_%H%M%S"), ReadFromPLC("Pump.Run_Status", "INT"),ReadFromPLC("Card_Past[1].ID", "INT"),ReadFromPLC("Card_Past[1].Fillage_Percent", "REAL"),ReadFromPLC("Card_Past[1].Fluid_Above_Pump", "REAL"),ReadFromPLC("Stroke_Production", "REAL"))) + #status_file.write("{0}-->{1}\n{2},{3},{4},{5}".format(datetime.now(), ReadFromPLC("Pump.Run_Status", "INT"),ReadFromPLC("Card_Past[1].ID", "INT"),ReadFromPLC("Card_Past[1].Fillage_Percent", "REAL"),ReadFromPLC("Card_Past[1].Fluid_Above_Pump", "REAL"),ReadFromPLC("Stroke_Production", "REAL"))) + + ############# + # CARD DATA # + ############# + + EOS = ReadFromPLC("End_Of_Stroke", "INT") + Already_Read = ReadFromPLC("Card_Past[1].Data_Read", "INT") > 0 + num_points = ReadFromPLC("Card_Past[1].Num_Points", "INT") + + + if (EOS and not Already_Read and (EOS != 911)): + filename = path_to_CSV + "current.csv" + myfile = open(filename, 'wb') + wr = csv.writer(myfile, quoting=csv.QUOTE_ALL) + stroke_time = time.time() + dt = datetime.fromtimestamp(stroke_time) + wr.writerow(['localtime', dt]) + wr.writerow(['utctime', datetime.utcfromtimestamp(stroke_time)]) + for t in tags_to_read: + #print t + data[t[2]] = ReadFromPLC(t[0], t[1]) + wr.writerow([t[2] ,data[t[2]]]) + wr.writerow(["s_pos", "s_load"]) + for i in range(1, num_points-1): + wr.writerow([round(ReadFromPLC("Card_Past[1].Surface_Position[" + str(i) + "]", "REAL"),3), round(ReadFromPLC("Card_Past[1].Surface_Load[" + str(i) + "]", "REAL"),3)]) + wr.writerow(["d_pos", "d_load"]) + for i in range(1, num_points-1): + wr.writerow([round(ReadFromPLC("Card_Past[1].Downhole_Position[" + str(i) + "]", "REAL"),3), round(ReadFromPLC("Card_Past[1].Downhole_Load[" + str(i) + "]", "REAL"),3)]) + myfile.close() + + st = datetime.strftime(dt,"%Y%m%d_%H%M%S") + date = datetime.strftime(dt,"%Y%m%d") + + if (data["Card_Type"] == 0): + data["Card_Type"] = "Normal" + elif (data["Card_Type"]==1): + data["Card_Type"] = "Shutdown" + elif (data["Card_Type"]==2): + data["Card_Type"] = "Alarm" + elif (data["Card_Type"]==3): + data["Card_Type"] = "Startup" + else: + data["Card_Type"] ="Unknown" + + if not os.path.exists(path_to_CSV +"CSV/"+date): + os.makedirs(path_to_CSV+"CSV/"+date) + + fill_percent_file = str(data['Fillage_Percent']).replace(".","-") + rename_file = path_to_CSV+"CSV/"+ date+"/"+st+"_"+str(data["Card_ID"])+"_"+data['Card_Type']+ "_"+fill_percent_file +".csv" + os.rename(filename, rename_file) + + tux.WriteLGXData(sess, conn, "Card_Past[1].Data_Read", LGX_REAL, 1, 1) + print "CARD NUMBER " + str(cards_read) + " READ: "+str(data["Card_ID"])+ ", STORED AS "+ rename_file + cards_read = cards_read + 1 + + + ############## + # TAPER DATA # + ############## + + update_taper = ReadFromPLC("Write_Tapers", "INT") + if (update_taper == 0): + if read_tapers: + read_tapers = False + print "Update Tapers = False" + + if (update_taper and (not read_tapers) and (update_taper != 911)): + print "reading taper file" + taper_count = 0; + + tFilename = path_to_CSV + "CSV/TAPER/TAPER_" + datetime.strftime(now,"%Y%m%d_%H%M%S")+ '.CSV' + tFile = open(tFilename, 'wb') + twr = csv.writer(tFile, quoting=csv.QUOTE_ALL) + for taps in range(1,10): + taper_in_use_temp = ReadFromPLC('Taper.Taper[' + str(taps)+'].Calculated.InUse', "INT") + if taper_in_use_temp: + taper_count = taper_count + 1 + #print "reading Taper"+ str(taper_count) + twr.writerow(["Taper",taper_count]) + twr.writerow(['Length',ReadFromPLC('Taper.Taper['+str(taps) +'].Setup.Length', 'REAL')]) + twr.writerow(['Diameter',ReadFromPLC('Taper.Taper['+str(taps) +'].Setup.Diameter', 'REAL')]) + tMaterial = ReadFromPLC('Taper.Taper['+str(taps) +'].Setup.Material', 'INT') + if (tMaterial == 1): + twr.writerow(['Material',"Steel"]) + elif (tMaterial == 2): + twr.writerow(['Material',"Fiberglass"]) + twr.writerow(['Weight_Per_Foot', ReadFromPLC('Taper.Taper['+str(taps) +'].Setup.Weight', 'REAL')]) + twr.writerow(['Youngs_Modulus',ReadFromPLC('Taper.Taper['+str(taps) +'].Setup.Youngs_Modulus', 'REAL')]) + twr.writerow(['Damping_Factor',ReadFromPLC('Taper.Taper['+str(taps) +'].Setup.c', 'REAL')]) + twr.writerow(['Area',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Area', 'REAL')]) + twr.writerow(['Rod_Depth',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Rod_Depth', 'REAL')]) + twr.writerow(['Pressure',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Pressure', 'REAL')]) + twr.writerow(['Buoyant_Force',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Buoyant_Force', 'REAL')]) + twr.writerow(['Rod_Weight',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Rod_Weight_Air', 'REAL')]) + twr.writerow(['Force',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Force', 'REAL')]) + twr.writerow(['Stretch',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Stretch', 'REAL')]) + twr.writerow(["",""]) + else: + break + twr.writerow(["UnitConfig",""]) + twr.writerow(['Pump_Diameter',ReadFromPLC('UnitConfig.Pump_Diameter', 'REAL')]) + tFile.close() + read_tapers = True + print "TAPER DATA READ: "+ tFilename + + ################## + # GAUGE OFF DATA # + ################## + gauge_off = ReadFromPLC("Gauge_Off_Command", "INT") + if (gauge_off == 0): + if already_gauged_off: + already_gauged_off = False + print "Already gauged off... Setting gauge_off to False" + + if (gauge_off and (not already_gauged_off) and (gauge_off != 911)): + print "Gauging off..." + gYear = ReadFromPLC("GAUGEOFF_DateTime.Year", "INT") + gMonth = ReadFromPLC("GAUGEOFF_DateTime.Month", "INT") + gDay = ReadFromPLC("GAUGEOFF_DateTime.Day", "INT") + gHour = ReadFromPLC("GAUGEOFF_DateTime.Hour", "INT") + gMin = ReadFromPLC("GAUGEOFF_DateTime.Min", "INT") + gSec = ReadFromPLC("GAUGEOFF_DateTime.Sec", "INT") + gauge_date = datetime(year = gYear, month = gMonth,day = gDay,hour = gHour,minute = gMin,second = gSec) + percent_run = round(ReadFromPLC("GAUGEOFF_Percent_Run", "REAL"),2) + kWh = round(ReadFromPLC("GAUGEOFF_kWh", "REAL"),3) + electricity_cost = round(ReadFromPLC("GAUGEOFF_Electricity_Cost", "REAL"),2) + peak_load = round(ReadFromPLC("GAUGEOFF_Max_Load", "REAL"),3) + min_load = round(ReadFromPLC("GAUGEOFF_Min_Load", "REAL"),3) + average_SPM = round(ReadFromPLC("GAUGEOFF_Average_SPM", "REAL"),4) + production_calculated = round(ReadFromPLC("GAUGEOFF_Production_Calculated", "REAL"),2) + full_card_production = round(ReadFromPLC("GAUGEOFF_Full_Card_Production", "REAL"),2) + polished_rod_HP = round(ReadFromPLC("GAUGEOFF_Polished_Rod_HP", "REAL"),3) + lifting_cost = round(ReadFromPLC("GAUGEOFF_Lifting_Cost", "REAL"),4) + fluid_above_pump = round(ReadFromPLC("GAUGEOFF_Fluid_Above_Pump", "REAL"),2) + pump_intake_pressure = round(ReadFromPLC("GAUGEOFF_pump_intake_pressure", "REAL"),2) + kWh_regen = round(ReadFromPLC("GAUGEOFF_kWh_regen", "REAL"),2) + inflow_rate = round(ReadFromPLC("GAUGEOFF_Inflow_Rate", "REAL"),4) + + db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + print """INSERT INTO WellData.Hist_Day (gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate) VALUES ('%s', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f');"""%(gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate) + storeHist = cur.execute("""INSERT INTO WellData.Hist_Day (gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate) VALUES ('%s', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f');"""%(gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate)) + db.commit() + db.close() + + already_gauged_off = True + print "Gauged off!" + + + ################## + # WELL TEST DATA # + ################## + + well_test_entered = ReadFromPLC("Well_Test.Test_Submit", "INT") + if (well_test_entered == 0): + if already_entered_well_test: + already_entered_well_test = False + print "Already entered well Test... Setting well_test_entered to False" + if (well_test_entered and (not already_entered_well_test) and well_test_entered != 911): + print "Well Test Entered" + + tYear = ReadFromPLC("Well_Test.DateTime_Complete.Year", "INT") + tMonth = ReadFromPLC("Well_Test.DateTime_Complete.Month", "INT") + tDay = ReadFromPLC("Well_Test.DateTime_Complete.Day", "INT") + tHour = ReadFromPLC("Well_Test.DateTime_Complete.Hour", "INT") + tMin = ReadFromPLC("Well_Test.DateTime_Complete.Min", "INT") + tSec = ReadFromPLC("Well_Test.DateTime_Complete.Sec", "INT") + test_date = datetime(year = tYear, month = tMonth,day = tDay,hour = tHour,minute = tMin,second = tSec) + test_duration = round(ReadFromPLC("Well_Test.Test_Duration", "REAL"),3) + v_water = round(ReadFromPLC("Well_Test.Volume_Water", "REAL"),3) + v_oil = round(ReadFromPLC("Well_Test.Volume_Oil", "REAL"),3) + v_gas = round(ReadFromPLC("Well_Test.Volume_Gas", "REAL"),3) + p_v_water = round(ReadFromPLC("Well_Test.Projected_Volume_Water", "REAL"),3) + p_v_oil = round(ReadFromPLC("Well_Test.Projected_Volume_Oil", "REAL"),3) + k_factor = round(ReadFromPLC("Well_Test.k_Factor", "REAL"),3) + api_oil = round(ReadFromPLC("Well_Test.API_Oil", "REAL"),3) + sg_water = round(ReadFromPLC("Well_Test.SG_Water", "REAL"),3) + + db = MySQLdb.connect(host="localhost",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + test_query = "INSERT INTO WellData.Well_Test (test_date, test_volume_oil, test_volume_water, test_volume_gas, k_factor, projected_volume_oil, projected_volume_water, api_gravity_oil, sg_water, test_hours) VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}', '{8}', '{9}');".format(test_date, v_oil, v_water, v_gas, k_factor, p_v_oil, p_v_water, api_oil, sg_water, test_duration) + print test_query + storeTest = cur.execute(test_query) + db.commit() + db.close() + + already_entered_well_test = True + print "Well Test Stored!" + + time.sleep(.20) diff --git a/dataLoggerMySQL.py b/dataLoggerMySQL.py new file mode 100644 index 0000000..f06d9c2 --- /dev/null +++ b/dataLoggerMySQL.py @@ -0,0 +1,395 @@ +#!/usr/bin/env python + +''' +Created on Oct 1, 2014 + +@author: PJMcdona +''' + + +#from prettytable import PrettyTable +import csv +from datetime import datetime +import os +import sys +from random import randint +import time +import MySQLdb + + + +db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") +cur = db.cursor() +query = "SELECT * FROM WellData.config ORDER BY dateChanged DESC LIMIT 1;" +cur.execute(query) +setup = cur.fetchall() +db.commit() +db.close() + +PLC_IP_ADDRESS = setup[0][2] +PLC_TYPE = setup[0][1] + +sys.path.append("../") + +path_to_CSV = "/mnt/usb/" + +#TUXEIP Connection to PLC +from tuxeip import TuxEIP, LGX, LGX_REAL +tux = TuxEIP(libpath="/usr/lib/libtuxeip.so") +sess = tux.OpenSession(PLC_IP_ADDRESS) +reg = tux.RegisterSession(sess) +conn = tux.ConnectPLCOverCNET(sess, LGX, 1, 100, 123, randint(0,9999), 123, 321, 100, 5000, 1, '01') + +if os.path.exists(path_to_CSV + "current.csv"): + os.remove(path_to_CSV + "current.csv") + + + +data = {} + +tags_to_read = [['Card_Past[1].ID', 'INT', "Card_ID"], + ['Card_Past[1].Params.Num_Tapers', 'INT', 'Num_Tapers'], + ['Card_Past[1].Num_Points', 'INT', 'Num_Points'], + ['Card_Past[1].Card_Type', 'INT', 'Card_Type'], + ['Card_Past[1].Name.Data[0]','STRING', 'Well_Name'], + ['Card_Past[1].Params.Tubing_Head_Pressure','REAL', 'Tubing_Head_Pressure'], + ['Card_Past[1].Params.Fluid_Gradient','REAL', 'Fluid_Gradient'], + ['Card_Past[1].Params.Stuffing_Box_Friction','REAL', 'Stuffing_Box_Friction'], + ['Card_Past[1].Params.dt','REAL', 'dt'], + ['Card_Past[1].Downhole_Max_Load.Load','REAL', 'Downhole_Max_Load'], + ['Card_Past[1].Downhole_Min_Load.Load','REAL', 'Downhole_Min_Load'], + ['Card_Past[1].Downhole_Max_Position.Position','REAL', 'Downhole_Max_Position'], + ['Card_Past[1].Downhole_Min_Position.Position','REAL', 'Downhole_Min_Position'], + ['Card_Past[1].Downhole_GrossStroke','REAL', 'Downhole_Gross_Stroke'], + ['Card_Past[1].Downhole_AdjustedGrossStroke','REAL', 'Downhole_Adjusted_Gross_Stroke'], + ['Card_Past[1].Downhole_NetStroke','REAL', 'Downhole_Net_Stroke'], + ['Card_Past[1].Downhole_FluidLoad','REAL', 'Downhole_Fluid_Load'], + ['Card_Past[1].Surface_Max.Load','REAL', 'Surface_Max_Load'], + ['Card_Past[1].Surface_Min.Load','REAL', 'Surface_Min_Load'], + ['Card_Past[1].Surface_Max.Position','REAL', 'Surface_Max_Position'], + ['Card_Past[1].Surface_Min.Position','REAL', 'Surface_Min_Position'], + ['Card_Past[1].Tubing_Movement','REAL', 'Tubing_Movement'], + ['Card_Past[1].Surface_StrokeLength','REAL', 'Surface_Stroke_Length'], + ['Card_Past[1].Fillage_Percent','REAL', 'Fillage_Percent'], + ['Card_Past[1].Polished_Rod_HP','REAL', 'Polished_Rod_HP'], + ['Card_Past[1].Pump_HP','REAL', 'Pump_HP'], + ['Card_Past[1].SPM','REAL', 'SPM'], + ['Card_Past[1].Fluid_Above_Pump','REAL', 'Fluid_Level'], + ['Card_Past[1].Pump_Intake_Pressure','REAL', 'Pump_Intake_Pressure'], + ['Stroke_Production','REAL', 'Stroke_Production'], + ['DriveTorqueMode','BOOL', 'Drive_Torque_Mode'], + ] +mode_tags = {"torque":['PF755_Drive:O.TrqRefAStpt','REAL', 'Torque_Reference'], + "speed":['Pump_PF755.PSet_SpeedRef','REAL', 'Speed_Reference']} +datetime_tags = [ + ['Card_Past[1].End_Time.Year', 'INT', '_Year'], + ['Card_Past[1].End_Time.Month', 'INT', '_Month'], + ['Card_Past[1].End_Time.Day', 'INT', '_Day'], + ['Card_Past[1].End_Time.Hour', 'INT', '_Hour'], + ['Card_Past[1].End_Time.Min', 'INT', '_Minute'], + ['Card_Past[1].End_Time.Sec', 'INT', '_Second'] +] + + +def ReadFromPLC(tag, tag_type): + try: + if (tag_type == "REAL"): + a = tux.ReadLGXDataAsFloat(sess, conn, tag, 1) + #print a + result = float(a[0]) + #print tag, result + elif (tag_type == "INT"): + a = tux.ReadLGXDataAsInteger(sess, conn, tag, 1) + #print a + result = int(a[0]) + #print tag, result + elif (tag_type == "BOOL"): + a = tux.ReadLGXDataAsInteger(sess, conn, tag, 1) + val = int(a[0]) + if val != 0: + val = 1 + result = val + elif (tag_type =="STRING"): + #print "./read_"+tag_type+ " , " + tag + a = tux.ReadLGXDataAsInteger(sess, conn, tag, 82) + #print a + #split_chars = a.split(",") + #print split_chars + word = "" + for ch in range(len(a)): + word = word + unichr(int(a[ch])) + #print word + result = word + else: + result = "?" + return result + except: + print "Unable to read " + tag + return 911 + +def readPoints(): + surface = [] + downhole = [] + for i in range(0, data['Num_Points']): + sp = round(ReadFromPLC("Card_Past[1].Surface_Position[" + str(i) + "]", "REAL"),3) + sl = round(ReadFromPLC("Card_Past[1].Surface_Load[" + str(i) + "]", "REAL"),3) + surface.append([sp,sl]) + + dp = round(ReadFromPLC("Card_Past[1].Downhole_Position[" + str(i) + "]", "REAL"),3) + dl = round(ReadFromPLC("Card_Past[1].Downhole_Load[" + str(i) + "]", "REAL"),3) + downhole.append([dp, dl]) + + +def readSetpoints(): + modeMap = { + 0: "Error", + 1: "Auto", + 2: "POC", + 3: "Timer", + 4: "Manual", + 5: "DH PID" + } + + + with open('/mnt/usb/setpoints.csv', 'w') as setpoint_file: + wr = csv.writer(setpoint_file) + stroke_time = time.time() + dt = datetime.fromtimestamp(stroke_time) + wr.writerow(['localtime', dt]) + wr.writerow(['utctime', datetime.utcfromtimestamp(stroke_time)]) + wr.writerow(['Mode', ReadFromPLC("Pump.Mode", "INT")]) + wr.writerow(['Speed_Setpoint_SPM', ReadFromPLC("Pump.Speed_Setpoint_SPM", "REAL")]) + wr.writerow(['Speed_Max', ReadFromPLC("Pump.Speed_Max", "REAL")]) + wr.writerow(['Speed_Min', ReadFromPLC("Pump.Speed_Min", "REAL")]) + wr.writerow(['Auto-Speed_Startpoint_SPM', ReadFromPLC("Pump.Speed_Startpoint_SPM_Auto", "REAL")]) + wr.writerow(['Auto-Percentage_Ramp_Down', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-Increment_Ramp_Down', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-Percent_Ramp_Up', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-Percent_Ramp_Down', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-Min_Speed_Strokes', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-Percent_Ramp_Up', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-POC-Startup_Ignore_Cards', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-POC-Card_Quantity', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['Auto-Percent_Ramp_Up', ReadFromPLC("Pump.Mode", "REAL")]) + wr.writerow(['POC-Percent_Pumpoff', ReadFromPLC("Pump.Mode", "REAL")]) + + +cards_read = 1 +read_tapers = False +already_gauged_off = False +already_entered_well_test = False +while True: + now = datetime.now() + with open('/mnt/usb/status.txt', 'w') as status_file: + status_file.write("{0}-->{1}\n{2},{3},{4},{5}".format(datetime.strftime(now,"%Y%m%d_%H%M%S"), ReadFromPLC("Pump.Run_Status", "INT"),ReadFromPLC("Card_Past[1].ID", "INT"),ReadFromPLC("Card_Past[1].Fillage_Percent", "REAL"),ReadFromPLC("Card_Past[1].Fluid_Above_Pump", "REAL"),ReadFromPLC("Stroke_Production", "REAL"))) + #status_file.write("{0}-->{1}\n{2},{3},{4},{5}".format(datetime.now(), ReadFromPLC("Pump.Run_Status", "INT"),ReadFromPLC("Card_Past[1].ID", "INT"),ReadFromPLC("Card_Past[1].Fillage_Percent", "REAL"),ReadFromPLC("Card_Past[1].Fluid_Above_Pump", "REAL"),ReadFromPLC("Stroke_Production", "REAL"))) + + ############# + # CARD DATA # + ############# + + EOS = ReadFromPLC("End_Of_Stroke", "INT") + Already_Read = ReadFromPLC("Card_Past[1].Data_Read", "INT") > 0 + num_points = ReadFromPLC("Card_Past[1].Num_Points", "INT") + + + if (EOS and not Already_Read and (EOS != 911)): + stroke_time = time.time() + dt = datetime.fromtimestamp(stroke_time) + data['localtime'] = dt + data['Stroke_Time'] = dt + data['utctime'] = datetime.utcfromtimestamp(stroke_time) + for t in tags_to_read: + data[t[2]] = ReadFromPLC(t[0], t[1]) + + data['Surface_Position'] = [] + data['Surface_Load'] = [] + data['Downhole_Position'] = [] + data['Downhole_Load'] = [] + + for i in range(1, num_points-1): + data['Surface_Position'].append(round(ReadFromPLC("Card_Past[1].Surface_Position[" + str(i) + "]", "REAL"),3)) + data['Surface_Load'].append(round(ReadFromPLC("Card_Past[1].Surface_Load[" + str(i) + "]", "REAL"),3)) + data['Downhole_Position'].append(round(ReadFromPLC("Card_Past[1].Downhole_Position[" + str(i) + "]", "REAL"),3)) + data['Downhole_Load'].append(round(ReadFromPLC("Card_Past[1].Downhole_Load[" + str(i) + "]", "REAL"),3)) + + st = datetime.strftime(dt,"%Y%m%d_%H%M%S") + date = datetime.strftime(dt,"%Y%m%d") + + if (data["Card_Type"] == 0): + data["Card_Type"] = "Normal" + elif (data["Card_Type"]== 1): + data["Card_Type"] = "Shutdown" + elif (data["Card_Type"]== 2): + data["Card_Type"] = "Alarm" + elif (data["Card_Type"]== 3): + data["Card_Type"] = "Startup" + else: + data["Card_Type"] ="Unknown" + + mode = 'torque' + if data['Drive_Torque_Mode'] == 0: + mode = 'speed' + data['Drive_Reference'] = ReadFromPLC(mode_tags[mode][0], mode_tags[mode][1]) + + data['sp_string'] = ','.join(map(str, data['Surface_Position'])) + data['sl_string'] = ','.join(map(str, data['Surface_Load'])) + data['dp_string'] = ','.join(map(str, data['Downhole_Position'])) + data['dl_string'] = ','.join(map(str, data['Downhole_Load'])) + + insert_query = ("INSERT INTO WellData.card_history " + "(Card_ID, Num_Tapers, Num_Points, Card_Type, Stroke_Time, Tubing_Head_Pressure, Fluid_Gradient, " + "Stuffing_Box_Friction, dt, Downhole_Max_Load, Downhole_Min_Load, Downhole_Max_Position, Downhole_Min_Position, " + "Downhole_Gross_Stroke, Downhole_Adjusted_Gross_Stroke, Downhole_Net_Stroke, Downhole_Fluid_Load, Surface_Max_Load, " + "Surface_Min_Load, Surface_Max_Position, Surface_Min_Position, Tubing_Movement, Surface_Stroke_Length, Fillage_Percent, " + "Polished_Rod_HP, Pump_HP, SPM, Fluid_Level, Pump_Intake_Pressure, Stroke_Production, Drive_Torque_Mode, Drive_Reference, " + "Surface_Position, Surface_Load, Downhole_Position, Downhole_Load) VALUES " + "(%(Card_ID)s, %(Num_Tapers)s, %(Num_Points)s, %(Card_Type)s, %(Stroke_Time)s, %(Tubing_Head_Pressure)s, %(Fluid_Gradient)s, " + "%(Stuffing_Box_Friction)s, %(dt)s, %(Downhole_Max_Load)s, %(Downhole_Min_Load)s, %(Downhole_Max_Position)s, %(Downhole_Min_Position)s, " + "%(Downhole_Gross_Stroke)s, %(Downhole_Adjusted_Gross_Stroke)s, %(Downhole_Net_Stroke)s, %(Downhole_Fluid_Load)s, %(Surface_Max_Load)s, " + "%(Surface_Min_Load)s, %(Surface_Max_Position)s, %(Surface_Min_Position)s, %(Tubing_Movement)s, %(Surface_Stroke_Length)s, %(Fillage_Percent)s, " + "%(Polished_Rod_HP)s, %(Pump_HP)s, %(SPM)s, %(Fluid_Level)s, %(Pump_Intake_Pressure)s, %(Stroke_Production)s, %(Drive_Torque_Mode)s, %(Drive_Reference)s, " + "%(sp_string)s, %(sl_string)s, %(dp_string)s, %(dl_string)s)") + db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + cur.execute(insert_query, data) + db.commit() + db.close() + tux.WriteLGXData(sess, conn, "Card_Past[1].Data_Read", LGX_REAL, 1, 1) + print "CARD NUMBER " + str(data["Card_ID"]) + " READ!" + + + ############## + # TAPER DATA # + ############## + + update_taper = ReadFromPLC("Write_Tapers", "INT") + if (update_taper == 0): + if read_tapers: + read_tapers = False + print "Update Tapers = False" + + if (update_taper and (not read_tapers) and (update_taper != 911)): + print "reading taper file" + taper_count = 0; + + tFilename = path_to_CSV + "CSV/TAPER/TAPER_" + datetime.strftime(now,"%Y%m%d_%H%M%S")+ '.CSV' + tFile = open(tFilename, 'wb') + twr = csv.writer(tFile, quoting=csv.QUOTE_ALL) + for taps in range(1,10): + taper_in_use_temp = ReadFromPLC('Taper.Taper[' + str(taps)+'].Calculated.InUse', "INT") + if taper_in_use_temp: + taper_count = taper_count + 1 + #print "reading Taper"+ str(taper_count) + twr.writerow(["Taper",taper_count]) + twr.writerow(['Length',ReadFromPLC('Taper.Taper['+str(taps) +'].Setup.Length', 'REAL')]) + twr.writerow(['Diameter',ReadFromPLC('Taper.Taper['+str(taps) +'].Setup.Diameter', 'REAL')]) + tMaterial = ReadFromPLC('Taper.Taper['+str(taps) +'].Setup.Material', 'INT') + if (tMaterial == 1): + twr.writerow(['Material',"Steel"]) + elif (tMaterial == 2): + twr.writerow(['Material',"Fiberglass"]) + twr.writerow(['Weight_Per_Foot', ReadFromPLC('Taper.Taper['+str(taps) +'].Setup.Weight', 'REAL')]) + twr.writerow(['Youngs_Modulus',ReadFromPLC('Taper.Taper['+str(taps) +'].Setup.Youngs_Modulus', 'REAL')]) + twr.writerow(['Damping_Factor',ReadFromPLC('Taper.Taper['+str(taps) +'].Setup.c', 'REAL')]) + twr.writerow(['Area',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Area', 'REAL')]) + twr.writerow(['Rod_Depth',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Rod_Depth', 'REAL')]) + twr.writerow(['Pressure',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Pressure', 'REAL')]) + twr.writerow(['Buoyant_Force',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Buoyant_Force', 'REAL')]) + twr.writerow(['Rod_Weight',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Rod_Weight_Air', 'REAL')]) + twr.writerow(['Force',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Force', 'REAL')]) + twr.writerow(['Stretch',ReadFromPLC('Taper.Taper['+str(taps) +'].Calculated.Stretch', 'REAL')]) + twr.writerow(["",""]) + else: + break + twr.writerow(["UnitConfig",""]) + twr.writerow(['Pump_Diameter',ReadFromPLC('UnitConfig.Pump_Diameter', 'REAL')]) + tFile.close() + read_tapers = True + print "TAPER DATA READ: "+ tFilename + + ################## + # GAUGE OFF DATA # + ################## + gauge_off = ReadFromPLC("Gauge_Off_Command", "INT") + if (gauge_off == 0): + if already_gauged_off: + already_gauged_off = False + print "Already gauged off... Setting gauge_off to False" + + if (gauge_off and (not already_gauged_off) and (gauge_off != 911)): + print "Gauging off..." + gYear = ReadFromPLC("GAUGEOFF_DateTime.Year", "INT") + gMonth = ReadFromPLC("GAUGEOFF_DateTime.Month", "INT") + gDay = ReadFromPLC("GAUGEOFF_DateTime.Day", "INT") + gHour = ReadFromPLC("GAUGEOFF_DateTime.Hour", "INT") + gMin = ReadFromPLC("GAUGEOFF_DateTime.Min", "INT") + gSec = ReadFromPLC("GAUGEOFF_DateTime.Sec", "INT") + gauge_date = datetime(year = gYear, month = gMonth,day = gDay,hour = gHour,minute = gMin,second = gSec) + percent_run = round(ReadFromPLC("GAUGEOFF_Percent_Run", "REAL"),2) + kWh = round(ReadFromPLC("GAUGEOFF_kWh", "REAL"),3) + electricity_cost = round(ReadFromPLC("GAUGEOFF_Electricity_Cost", "REAL"),2) + peak_load = round(ReadFromPLC("GAUGEOFF_Max_Load", "REAL"),3) + min_load = round(ReadFromPLC("GAUGEOFF_Min_Load", "REAL"),3) + average_SPM = round(ReadFromPLC("GAUGEOFF_Average_SPM", "REAL"),4) + production_calculated = round(ReadFromPLC("GAUGEOFF_Production_Calculated", "REAL"),2) + full_card_production = round(ReadFromPLC("GAUGEOFF_Full_Card_Production", "REAL"),2) + polished_rod_HP = round(ReadFromPLC("GAUGEOFF_Polished_Rod_HP", "REAL"),3) + lifting_cost = round(ReadFromPLC("GAUGEOFF_Lifting_Cost", "REAL"),4) + fluid_above_pump = round(ReadFromPLC("GAUGEOFF_Fluid_Above_Pump", "REAL"),2) + pump_intake_pressure = round(ReadFromPLC("GAUGEOFF_pump_intake_pressure", "REAL"),2) + kWh_regen = round(ReadFromPLC("GAUGEOFF_kWh_regen", "REAL"),2) + inflow_rate = round(ReadFromPLC("GAUGEOFF_Inflow_Rate", "REAL"),4) + + db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + print """INSERT INTO WellData.Hist_Day (gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate) VALUES ('%s', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f');"""%(gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate) + storeHist = cur.execute("""INSERT INTO WellData.Hist_Day (gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate) VALUES ('%s', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f');"""%(gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate)) + db.commit() + db.close() + + already_gauged_off = True + print "Gauged off!" + + + ################## + # WELL TEST DATA # + ################## + + well_test_entered = ReadFromPLC("Well_Test.Test_Submit", "INT") + if (well_test_entered == 0): + if already_entered_well_test: + already_entered_well_test = False + print "Already entered well Test... Setting well_test_entered to False" + if (well_test_entered and (not already_entered_well_test) and well_test_entered != 911): + print "Well Test Entered" + + tYear = ReadFromPLC("Well_Test.DateTime_Complete.Year", "INT") + tMonth = ReadFromPLC("Well_Test.DateTime_Complete.Month", "INT") + tDay = ReadFromPLC("Well_Test.DateTime_Complete.Day", "INT") + tHour = ReadFromPLC("Well_Test.DateTime_Complete.Hour", "INT") + tMin = ReadFromPLC("Well_Test.DateTime_Complete.Min", "INT") + tSec = ReadFromPLC("Well_Test.DateTime_Complete.Sec", "INT") + test_date = datetime(year = tYear, month = tMonth,day = tDay,hour = tHour,minute = tMin,second = tSec) + test_duration = round(ReadFromPLC("Well_Test.Test_Duration", "REAL"),3) + v_water = round(ReadFromPLC("Well_Test.Volume_Water", "REAL"),3) + v_oil = round(ReadFromPLC("Well_Test.Volume_Oil", "REAL"),3) + v_gas = round(ReadFromPLC("Well_Test.Volume_Gas", "REAL"),3) + p_v_water = round(ReadFromPLC("Well_Test.Projected_Volume_Water", "REAL"),3) + p_v_oil = round(ReadFromPLC("Well_Test.Projected_Volume_Oil", "REAL"),3) + k_factor = round(ReadFromPLC("Well_Test.k_Factor", "REAL"),3) + api_oil = round(ReadFromPLC("Well_Test.API_Oil", "REAL"),3) + sg_water = round(ReadFromPLC("Well_Test.SG_Water", "REAL"),3) + + db = MySQLdb.connect(host="localhost",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + test_query = "INSERT INTO WellData.Well_Test (test_date, test_volume_oil, test_volume_water, test_volume_gas, k_factor, projected_volume_oil, projected_volume_water, api_gravity_oil, sg_water, test_hours) VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}', '{8}', '{9}');".format(test_date, v_oil, v_water, v_gas, k_factor, p_v_oil, p_v_water, api_oil, sg_water, test_duration) + print test_query + storeTest = cur.execute(test_query) + db.commit() + db.close() + + already_entered_well_test = True + print "Well Test Stored!" + + time.sleep(.20) diff --git a/dataLogger_pycomm.py b/dataLogger_pycomm.py new file mode 100644 index 0000000..737215c --- /dev/null +++ b/dataLogger_pycomm.py @@ -0,0 +1,330 @@ +#!/usr/bin/env python + +''' +Created on Oct 1, 2014 + +@author: PJMcdona +''' + + +#from prettytable import PrettyTable +import csv +from datetime import datetime +import os +import sys +from random import randint +import time +import MySQLdb + +def main(): + + db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + query = "SELECT * FROM WellData.config ORDER BY dateChanged DESC LIMIT 1;" + cur.execute(query) + setup = cur.fetchall() + db.commit() + db.close() + try: + PLC_IP_ADDRESS = setup[0][2] + PLC_TYPE = setup[0][1] + except: + print("PLC Address not set in database... using default of 192.168.1.10") + PLC_IP_ADDRESS = "192.168.1.10" + PLC_TYPE = "VFD" + + sys.path.append("../") + + path_to_CSV = "/mnt/usb/" + + #PYCOMM Connection to PLC + from pycomm.ab_comm.clx import Driver as ClxDriver + + c = ClxDriver(True, 'ClxDriver.log') + + + + if os.path.exists(path_to_CSV + "current.csv"): + os.remove(path_to_CSV + "current.csv") + + + tags_to_read = [['Card_Past[1].ID', 'INT', "Card_ID"], + ['Card_Past[1].Params.Num_Tapers', 'INT', 'Num_Tapers'], + ['Card_Past[1].Num_Points', 'INT', 'Num_Points'], + ['Card_Past[1].Card_Type', 'INT', 'Card_Type'], + ['Card_Past[1].End_Time.Year', 'INT', '_Year'], + ['Card_Past[1].End_Time.Month', 'INT', '_Month'], + ['Card_Past[1].End_Time.Day', 'INT', '_Day'], + ['Card_Past[1].End_Time.Hour', 'INT', '_Hour'], + ['Card_Past[1].End_Time.Min', 'INT', '_Minute'], + ['Card_Past[1].End_Time.Sec', 'INT', '_Second'], + #['Card_Past[1].Name.Data[0]','STRING', 'Well_Name'], + ['Card_Past[1].Params.Tubing_Head_Pressure','REAL', 'Tubing_Head_Pressure'], + ['Card_Past[1].Params.Fluid_Gradient','REAL', 'Fluid_Gradient'], + ['Card_Past[1].Params.Stuffing_Box_Friction','REAL', 'Stuffing_Box_Friction'], + ['Card_Past[1].Params.dt','REAL', 'dt'], + # ['Card_Past[1].Downhole_Max_Load.Load','REAL', 'Downhole_Max_Load'], + # ['Card_Past[1].Downhole_Min_Load.Load','REAL', 'Downhole_Min_Load'], + # ['Card_Past[1].Downhole_Max_Position.Position','REAL', 'Downhole_Max_Position'], + # ['Card_Past[1].Downhole_Min_Position.Position','REAL', 'Downhole_Min_Position'], + ['Card_Past[1].Downhole_GrossStroke','REAL', 'Downhole_Gross_Stroke'], + ['Card_Past[1].Downhole_AdjustedGrossStroke','REAL', 'Downhole_Adjusted_Gross_Stroke'], + ['Card_Past[1].Downhole_NetStroke','REAL', 'Downhole_Net_Stroke'], + ['Card_Past[1].Downhole_FluidLoad','REAL', 'Downhole_Fluid_Load'], + ['Card_Past[1].Surface_Max.Load','REAL', 'Surface_Max_Load'], + ['Card_Past[1].Surface_Min.Load','REAL', 'Surface_Min_Load'], + # ['Card_Past[1].Surface_Max.Position','REAL', 'Surface_Max_Position'], + # ['Card_Past[1].Surface_Min.Position','REAL', 'Surface_Min_Position'], + ['Card_Past[1].Tubing_Movement','REAL', 'Tubing_Movement'], + ['Card_Past[1].Surface_StrokeLength','REAL', 'Surface_Stroke_Length'], + ['Card_Past[1].Fillage_Percent','REAL', 'Fillage_Percent'], + ['Card_Past[1].Polished_Rod_HP','REAL', 'Polished_Rod_HP'], + ['Card_Past[1].Pump_HP','REAL', 'Pump_HP'], + ['Card_Past[1].SPM','REAL', 'SPM'], + ['Card_Past[1].Fluid_Above_Pump','REAL', 'Fluid_Above_Pump'], + ['Stroke_Production','REAL', 'Stroke_Production'], + ['Pump_Intake_Pressure','REAL', 'Pump_Intake_Pressure'], + ] + + def readString(tag): + read_vals = c.read_array(tag, 82) + string = filter(lambda b: b != "",map(lambda a: chr(a[1]),read_vals)) + return "".join(string) + + + cards_read = 1 + read_tapers = False + already_gauged_off = False + already_entered_well_test = False + try: + if c.open(PLC_IP_ADDRESS): + while True: + data = {} + + now = datetime.now() + run_status = c.read_tag(['Pump.Run_Status'])[0][1] + card_id = c.read_tag(['Card_Past[1].ID'])[0][1] + fillage_percent = c.read_tag(['Card_Past[1].Fillage_Percent'])[0][1] + fluid_above_pump = c.read_tag(['Card_Past[1].Fluid_Above_Pump'])[0][1] + stroke_production = c.read_tag(['Stroke_Production'])[0][1] + with open('/mnt/usb/status.txt', 'w') as status_file: + status_file.write("{0}-->{1}\n{2},{3},{4},{5}".format(datetime.strftime(now,"%Y%m%d_%H%M%S"), run_status, card_id, fillage_percent, fluid_above_pump, stroke_production)) + + ############# + # CARD DATA # + ############# + + EOS = c.read_tag(["End_Of_Stroke"])[0][1] + Already_Read = c.read_tag(["Card_Past[1].Data_Read"])[0][1] > 0 + + if (EOS and not Already_Read and (EOS != 911)): + num_points = c.read_tag(["Card_Past[1].Num_Points"])[0][1] + data['Well_Name'] = readString('Card_Past[1].Name.Data') + filename = path_to_CSV + "current.csv" + myfile = open(filename, 'wb') + wr = csv.writer(myfile, quoting=csv.QUOTE_ALL) + stroke_time = time.time() + dt = datetime.fromtimestamp(stroke_time) + wr.writerow(['localtime', dt]) + wr.writerow(['utctime', datetime.utcfromtimestamp(stroke_time)]) + # wr.writerow(["Well_Name",data["Well_Name"]]) + for t in tags_to_read: + data[t[2]] = c.read_tag([t[0]])[0][1] + wr.writerow([t[2],data[t[2]]]) + numPointsRead = num_points + 1 + sp = c.read_array("Card_Past[0].Surface_Position", numPointsRead) + sl = c.read_array("Card_Past[0].Surface_Load", numPointsRead) + dp = c.read_array("Card_Past[0].Downhole_Position", numPointsRead) + dl = c.read_array("Card_Past[0].Downhole_Load", numPointsRead) + wr.writerow(["s_pos", "s_load"]) + for i in range(0, numPointsRead): + if sp[i][1] and (sp[i][1] != 0.0) and sl[i][1]: + wr.writerow([round(sp[i][1],3), round(sl[i][1],3)]) + wr.writerow(["d_pos", "d_load"]) + for i in range(1, numPointsRead): + if dp[i][1] and (dp[i][1] != 0.0) and dl[i][1]: + wr.writerow([round(dp[i][1],3), round(dl[i][1],3)]) + myfile.close() + dt = datetime(year = data["_Year"], month = data["_Month"],day = data["_Day"],hour = data["_Hour"],minute = data["_Minute"],second = data["_Second"]) + st = datetime.strftime(dt,"%Y%m%d_%H%M%S") + date = datetime.strftime(dt,"%Y%m%d") + + if (data["Card_Type"] == 0): + data["Card_Type"] = "Normal" + elif (data["Card_Type"]==1): + data["Card_Type"] = "Shutdown" + elif (data["Card_Type"]==2): + data["Card_Type"] = "Alarm" + elif (data["Card_Type"]==3): + data["Card_Type"] = "Startup" + else: + data["Card_Type"] ="Unknown" + + if not os.path.exists(path_to_CSV +"CSV/"+date): + os.makedirs(path_to_CSV+"CSV/"+date) + + fill_percent_file = str(round(data['Fillage_Percent'],3)).replace(".","-") + rename_file = path_to_CSV+"CSV/"+ date+"/"+st+"_"+str(data["Card_ID"])+"_"+data['Card_Type']+ "_"+fill_percent_file +".csv" + os.rename(filename, rename_file) + + c.write_tag('Card_Past[1].Data_Read', 1, 'REAL') + print "CARD NUMBER " + str(cards_read) + " READ: "+str(data["Card_ID"])+ ", STORED AS "+ rename_file + cards_read = cards_read + 1 + + + ############## + # TAPER DATA # + ############## + update_taper = c.read_tag(["Write_Tapers"])[0][1] + if (update_taper == 0): + if read_tapers: + read_tapers = False + print "Update Tapers = False" + + if (update_taper and (not read_tapers) and (update_taper != 911)): + print "reading taper file" + taper_count = 0; + + tFilename = path_to_CSV + "CSV/TAPER/TAPER_" + datetime.strftime(now,"%Y%m%d_%H%M%S")+ '.CSV' + tFile = open(tFilename, 'wb') + twr = csv.writer(tFile, quoting=csv.QUOTE_ALL) + for taps in range(1,10): + taper_in_use_temp = c.read_tag(['Taper.Taper[' + str(taps)+'].Calculated.InUse'])[0][1] + if taper_in_use_temp: + taper_count = taper_count + 1 + #print "reading Taper"+ str(taper_count) + twr.writerow(["Taper",taper_count]) + twr.writerow(['Length',c.read_tag(['Taper.Taper['+str(taps) +'].Setup.Length'])[0][1]]) + twr.writerow(['Diameter',c.read_tag(['Taper.Taper['+str(taps) +'].Setup.Diameter'])[0][1]]) + tMaterial = c.read_tag(['Taper.Taper['+str(taps) +'].Setup.Material'])[0][1] + if (tMaterial == 1): + twr.writerow(['Material',"Steel"]) + elif (tMaterial == 2): + twr.writerow(['Material',"Fiberglass"]) + twr.writerow(['Weight_Per_Foot', c.read_tag(['Taper.Taper['+str(taps) +'].Setup.Weight'])[0][1]]) + twr.writerow(['Youngs_Modulus',c.read_tag(['Taper.Taper['+str(taps) +'].Setup.Youngs_Modulus'])[0][1]]) + twr.writerow(['Damping_Factor',c.read_tag(['Taper.Taper['+str(taps) +'].Setup.c'])[0][1]]) + twr.writerow(['Area',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Area'])[0][1]]) + twr.writerow(['Rod_Depth',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Rod_Depth'])[0][1]]) + twr.writerow(['Pressure',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Pressure'])[0][1]]) + twr.writerow(['Buoyant_Force',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Buoyant_Force'])[0][1]]) + twr.writerow(['Rod_Weight',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Rod_Weight_Air'])[0][1]]) + twr.writerow(['Force',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Force'])[0][1]]) + twr.writerow(['Stretch',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Stretch'])[0][1]]) + twr.writerow(["",""]) + else: + break + twr.writerow(["UnitConfig",""]) + twr.writerow(['Pump_Diameter',c.read_tag(['UnitConfig.Pump_Diameter'])[0][1]]) + tFile.close() + read_tapers = True + print "TAPER DATA READ: "+ tFilename + + ################## + # GAUGE OFF DATA # + ################## + gauge_off = c.read_tag(['Gauge_Off_Command'])[0][1] + if (gauge_off == 0): + if already_gauged_off: + already_gauged_off = False + print "Already gauged off... Setting gauge_off to False" + + if (gauge_off and (not already_gauged_off)): + print "Gauging off..." + gYear = c.read_tag(['GAUGEOFF_DateTime.Year'])[0][1] + gMonth = c.read_tag(['GAUGEOFF_DateTime.Month'])[0][1] + gDay = c.read_tag(['GAUGEOFF_DateTime.Day'])[0][1] + gHour = c.read_tag(['GAUGEOFF_DateTime.Hour'])[0][1] + gMin = c.read_tag(['GAUGEOFF_DateTime.Min'])[0][1] + gSec = c.read_tag(['GAUGEOFF_DateTime.Sec'])[0][1] + gauge_date = datetime(year = gYear, month = gMonth,day = gDay,hour = gHour,minute = gMin,second = gSec) + print "gaugeDate: {0}".format(gauge_date) + percent_run = round(c.read_tag(['GAUGEOFF_Percent_Run'])[0][1],2) + print "percent_run: {0}".format(percent_run) + kWh = round(c.read_tag(['GAUGEOFF_kWh'])[0][1],3) + print "kWh: {0}".format(kWh) + electricity_cost = round(c.read_tag(['GAUGEOFF_Electricity_Cost'])[0][1],2) + print "electricity_cost: {0}".format(electricity_cost) + peak_load = round(c.read_tag(['GAUGEOFF_Max_Load'])[0][1],3) + print "peak_load: {0}".format(peak_load) + min_load = round(c.read_tag(['GAUGEOFF_Min_Load'])[0][1],3) + print "min_load: {0}".format(min_load) + average_SPM = round(c.read_tag(['GAUGEOFF_Average_SPM'])[0][1],4) + print "average_SPM: {0}".format(average_SPM) + production_calculated = round(c.read_tag(['GAUGEOFF_Production_Calculated'])[0][1],2) + print "production_calculated: {0}".format(production_calculated) + full_card_production = round(c.read_tag(['GAUGEOFF_Full_Card_Production'])[0][1],2) + print "full_card_production: {0}".format(full_card_production) + polished_rod_HP = round(c.read_tag(['GAUGEOFF_Polished_Rod_HP'])[0][1],3) + print "polished_rod_HP: {0}".format(polished_rod_HP) + lifting_cost = round(c.read_tag(['GAUGEOFF_Lifting_Cost'])[0][1],4) + print "lifting_cost: {0}".format(lifting_cost) + fluid_above_pump = round(c.read_tag(['GAUGEOFF_Fluid_Above_Pump'])[0][1],2) + print "fluid_above_pump: {0}".format(fluid_above_pump) + pump_intake_pressure = round(c.read_tag(['GAUGEOFF_pump_intake_pressure'])[0][1],2) + print "pump_intake_pressure: {0}".format(pump_intake_pressure) + kWh_regen = round(c.read_tag(['GAUGEOFF_kWh_regen'])[0][1],2) + print "kWh_regen: {0}".format(kWh_regen) + inflow_rate = round(c.read_tag(['GAUGEOFF_Inflow_Rate'])[0][1],4) + print "inflow_rate: {0}".format(inflow_rate) + + db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + print """INSERT INTO WellData.Hist_Day (gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate) VALUES ('%s', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f');"""%(gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate) + storeHist = cur.execute("""INSERT INTO WellData.Hist_Day (gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate) VALUES ('%s', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f');"""%(gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate)) + db.commit() + db.close() + + already_gauged_off = True + print "Gauged off!" + + + # ################## + # # WELL TEST DATA # + # ################## + + well_test_entered = c.read_tag(['Well_Test.Test_Submit'])[0][1] + if (well_test_entered == 0): + if already_entered_well_test: + already_entered_well_test = False + print "Already entered well Test... Setting well_test_entered to False" + if (well_test_entered and (not already_entered_well_test) and well_test_entered != 911): + print "Well Test Entered" + + tYear = c.read_tag(['Well_Test.DateTime_Complete.Year'])[0][1] + tMonth = c.read_tag(['Well_Test.DateTime_Complete.Month'])[0][1] + tDay = c.read_tag(['Well_Test.DateTime_Complete.Day'])[0][1] + tHour = c.read_tag(['Well_Test.DateTime_Complete.Hour'])[0][1] + tMin = c.read_tag(['Well_Test.DateTime_Complete.Min'])[0][1] + tSec = c.read_tag(['Well_Test.DateTime_Complete.Sec'])[0][1] + test_date = datetime(year = tYear, month = tMonth,day = tDay,hour = tHour,minute = tMin,second = tSec) + test_duration = round(c.read_tag(['Well_Test.Test_Duration'])[0][1],3) + v_water = round(c.read_tag(['Well_Test.Volume_Water'])[0][1],3) + v_oil = round(c.read_tag(['Well_Test.Volume_Oil'])[0][1],3) + v_gas = round(c.read_tag(['Well_Test.Volume_Gas'])[0][1],3) + p_v_water = round(c.read_tag(['Well_Test.Projected_Volume_Water'])[0][1],3) + p_v_oil = round(c.read_tag(['Well_Test.Projected_Volume_Oil'])[0][1],3) + k_factor = round(c.read_tag(['Well_Test.k_Factor'])[0][1],3) + api_oil = round(c.read_tag(['Well_Test.API_Oil'])[0][1],3) + sg_water = round(c.read_tag(['Well_Test.SG_Water'])[0][1],3) + + db = MySQLdb.connect(host="localhost",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + test_query = "INSERT INTO WellData.Well_Test (test_date, test_volume_oil, test_volume_water, test_volume_gas, k_factor, projected_volume_oil, projected_volume_water, api_gravity_oil, sg_water, test_hours) VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}', '{8}', '{9}');".format(test_date, v_oil, v_water, v_gas, k_factor, p_v_oil, p_v_water, api_oil, sg_water, test_duration) + print test_query + storeTest = cur.execute(test_query) + db.commit() + db.close() + + already_entered_well_test = True + print "Well Test Stored!" + + time.sleep(.20) + except Exception, e: + print("FATAL ERROR: Communication Error connecting to the PLC... ", e) + c.forward_close() + c.open(PLC_IP_ADDRESS) + main() + +if __name__ == '__main__': + main() diff --git a/dataLogger_pycomm_mysql.py b/dataLogger_pycomm_mysql.py new file mode 100644 index 0000000..2e304a2 --- /dev/null +++ b/dataLogger_pycomm_mysql.py @@ -0,0 +1,297 @@ +#!/usr/bin/env python + +''' +Created on Oct 1, 2014 + +@author: PJMcdona +''' + + +#from prettytable import PrettyTable +import csv +from datetime import datetime +import os +import sys +from random import randint +from time import sleep +import MySQLdb + + + +db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") +cur = db.cursor() +query = "SELECT * FROM WellData.config ORDER BY dateChanged DESC LIMIT 1;" +cur.execute(query) +setup = cur.fetchall() +db.commit() +db.close() + +PLC_IP_ADDRESS = setup[0][2] +PLC_TYPE = setup[0][1] + +sys.path.append("../") + +path_to_CSV = "/mnt/usb/" + +#PYCOMM Connection to PLC +from pycomm.ab_comm.clx import Driver as ClxDriver + +c = ClxDriver(True, 'ClxDriver.log') + + + +if os.path.exists(path_to_CSV + "current.csv"): + os.remove(path_to_CSV + "current.csv") + + +tags_to_read = [['Card_Past[1].ID', 'INT', "Card_ID"], + ['Card_Past[1].Params.Num_Tapers', 'INT', 'Num_Tapers'], + ['Card_Past[1].Num_Points', 'INT', 'Num_Points'], + ['Card_Past[1].Card_Type', 'INT', 'Card_Type'], + ['Card_Past[1].End_Time.Year', 'INT', '_Year'], + ['Card_Past[1].End_Time.Month', 'INT', '_Month'], + ['Card_Past[1].End_Time.Day', 'INT', '_Day'], + ['Card_Past[1].End_Time.Hour', 'INT', '_Hour'], + ['Card_Past[1].End_Time.Min', 'INT', '_Minute'], + ['Card_Past[1].End_Time.Sec', 'INT', '_Second'], + #['Card_Past[1].Name.Data[0]','STRING', 'Well_Name'], + ['Card_Past[1].Params.Tubing_Head_Pressure','REAL', 'Tubing_Head_Pressure'], + ['Card_Past[1].Params.Fluid_Gradient','REAL', 'Fluid_Gradient'], + ['Card_Past[1].Params.Stuffing_Box_Friction','REAL', 'Stuffing_Box_Friction'], + ['Card_Past[1].Params.dt','REAL', 'dt'], + ['Card_Past[1].Downhole_Max_Load.Load','REAL', 'Downhole_Max_Load'], + ['Card_Past[1].Downhole_Min_Load.Load','REAL', 'Downhole_Min_Load'], + ['Card_Past[1].Downhole_Max_Position.Position','REAL', 'Downhole_Max_Position'], + ['Card_Past[1].Downhole_Min_Position.Position','REAL', 'Downhole_Min_Position'], + ['Card_Past[1].Downhole_GrossStroke','REAL', 'Downhole_Gross_Stroke'], + ['Card_Past[1].Downhole_AdjustedGrossStroke','REAL', 'Downhole_Adjusted_Gross_Stroke'], + ['Card_Past[1].Downhole_NetStroke','REAL', 'Downhole_Net_Stroke'], + ['Card_Past[1].Downhole_FluidLoad','REAL', 'Downhole_Fluid_Load'], + ['Card_Past[1].Surface_Max.Load','REAL', 'Surface_Max_Load'], + ['Card_Past[1].Surface_Min.Load','REAL', 'Surface_Min_Load'], + ['Card_Past[1].Surface_Max.Position','REAL', 'Surface_Max_Position'], + ['Card_Past[1].Surface_Min.Position','REAL', 'Surface_Min_Position'], + ['Card_Past[1].Tubing_Movement','REAL', 'Tubing_Movement'], + ['Card_Past[1].Surface_StrokeLength','REAL', 'Surface_Stroke_Length'], + ['Card_Past[1].Fillage_Percent','REAL', 'Fillage_Percent'], + ['Card_Past[1].Polished_Rod_HP','REAL', 'Polished_Rod_HP'], + ['Card_Past[1].Pump_HP','REAL', 'Pump_HP'], + ['Card_Past[1].SPM','REAL', 'SPM'], + ['Card_Past[1].Fluid_Above_Pump','REAL', 'Fluid_Above_Pump'], + ['Stroke_Production','REAL', 'Stroke_Production'], + ] + +def readString(tag): + read_vals = c.read_array(tag, 82) + string = filter(lambda b: b != "",map(lambda a: chr(a[1]),read_vals)) + return "".join(string) + + +cards_read = 1 +read_tapers = False +already_gauged_off = False +already_entered_well_test = False +if c.open(PLC_IP_ADDRESS): + while True: + data = {} + + now = datetime.now() + run_status = c.read_tag(['Pump.Run_Status'])[0][1] + card_id = c.read_tag(['Card_Past[1].ID'])[0][1] + fillage_percent = c.read_tag(['Card_Past[1].Fillage_Percent'])[0][1] + fluid_above_pump = c.read_tag(['Card_Past[1].Fluid_Above_Pump'])[0][1] + stroke_production = c.read_tag(['Stroke_Production'])[0][1] + with open('/mnt/usb/status.txt', 'w') as status_file: + status_file.write("{0}-->{1}\n{2},{3},{4},{5}".format(datetime.strftime(now,"%Y%m%d_%H%M%S"), run_status, card_id, fillage_percent, fluid_above_pump, stroke_production)) + + ############# + # CARD DATA # + ############# + + EOS = c.read_tag(["End_Of_Stroke"])[0][1] + Already_Read = c.read_tag(["Card_Past[1].Data_Read"])[0][1] > 0 + + if (EOS and not Already_Read and (EOS != 911)): + num_points = c.read_tag(["Card_Past[1].Num_Points"])[0][1] + data['Well_Name'] = readString('Card_Past[1].Name.Data') + filename = path_to_CSV + "current.csv" + myfile = open(filename, 'wb') + wr = csv.writer(myfile, quoting=csv.QUOTE_ALL) + wr.writerow(["Well_Name",data["Well_Name"]]) + for t in tags_to_read: + data[t[2]] = c.read_tag([t[0]])[0][1] + wr.writerow([t[2],data[t[2]]]) + numPointsRead = num_points + 1 + sp = c.read_array("Card_Past[0].Surface_Position", numPointsRead) + sl = c.read_array("Card_Past[0].Surface_Load", numPointsRead) + dp = c.read_array("Card_Past[0].Downhole_Position", numPointsRead) + dl = c.read_array("Card_Past[0].Downhole_Load", numPointsRead) + wr.writerow(["s_pos", "s_load"]) + for i in range(0, numPointsRead): + if sp[i][1] != 0.0 and sl[i][1]: + wr.writerow([round(sp[i][1],3), round(sl[i][1],3)]) + wr.writerow(["d_pos", "d_load"]) + for i in range(1, numPointsRead): + if dp[i][1] != 0.0 and dl[i][1]: + wr.writerow([round(dp[i][1],3), round(dl[i][1],3)]) + myfile.close() + dt = datetime(year = data["_Year"], month = data["_Month"],day = data["_Day"],hour = data["_Hour"],minute = data["_Minute"],second = data["_Second"]) + st = datetime.strftime(dt,"%Y%m%d_%H%M%S") + date = datetime.strftime(dt,"%Y%m%d") + + if (data["Card_Type"] == 0): + data["Card_Type"] = "Normal" + elif (data["Card_Type"]==1): + data["Card_Type"] = "Shutdown" + elif (data["Card_Type"]==2): + data["Card_Type"] = "Alarm" + elif (data["Card_Type"]==3): + data["Card_Type"] = "Startup" + else: + data["Card_Type"] ="Unknown" + + if not os.path.exists(path_to_CSV +"CSV/"+date): + os.makedirs(path_to_CSV+"CSV/"+date) + + fill_percent_file = str(round(data['Fillage_Percent'],3)).replace(".","-") + rename_file = path_to_CSV+"CSV/"+ date+"/"+st+"_"+str(data["Card_ID"])+"_"+data['Card_Type']+ "_"+fill_percent_file +".csv" + os.rename(filename, rename_file) + + c.write_tag('Card_Past[1].Data_Read', 1, 'REAL') + print "CARD NUMBER " + str(cards_read) + " READ: "+str(data["Card_ID"])+ ", STORED AS "+ rename_file + cards_read = cards_read + 1 + + + ############## + # TAPER DATA # + ############## + update_taper = c.read_tag(["Write_Tapers"])[0][1] + if (update_taper == 0): + if read_tapers: + read_tapers = False + print "Update Tapers = False" + + if (update_taper and (not read_tapers) and (update_taper != 911)): + print "reading taper file" + taper_count = 0; + + tFilename = path_to_CSV + "CSV/TAPER/TAPER_" + datetime.strftime(now,"%Y%m%d_%H%M%S")+ '.CSV' + tFile = open(tFilename, 'wb') + twr = csv.writer(tFile, quoting=csv.QUOTE_ALL) + for taps in range(1,10): + taper_in_use_temp = c.read_tag(['Taper.Taper[' + str(taps)+'].Calculated.InUse'])[0][1] + if taper_in_use_temp: + taper_count = taper_count + 1 + #print "reading Taper"+ str(taper_count) + twr.writerow(["Taper",taper_count]) + twr.writerow(['Length',c.read_tag(['Taper.Taper['+str(taps) +'].Setup.Length'])[0][1]]) + twr.writerow(['Diameter',c.read_tag(['Taper.Taper['+str(taps) +'].Setup.Diameter'])[0][1]]) + tMaterial = c.read_tag(['Taper.Taper['+str(taps) +'].Setup.Material'])[0][1] + if (tMaterial == 1): + twr.writerow(['Material',"Steel"]) + elif (tMaterial == 2): + twr.writerow(['Material',"Fiberglass"]) + twr.writerow(['Weight_Per_Foot', c.read_tag(['Taper.Taper['+str(taps) +'].Setup.Weight'])[0][1]]) + twr.writerow(['Youngs_Modulus',c.read_tag(['Taper.Taper['+str(taps) +'].Setup.Youngs_Modulus'])[0][1]]) + twr.writerow(['Damping_Factor',c.read_tag(['Taper.Taper['+str(taps) +'].Setup.c'])[0][1]]) + twr.writerow(['Area',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Area'])[0][1]]) + twr.writerow(['Rod_Depth',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Rod_Depth'])[0][1]]) + twr.writerow(['Pressure',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Pressure'])[0][1]]) + twr.writerow(['Buoyant_Force',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Buoyant_Force'])[0][1]]) + twr.writerow(['Rod_Weight',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Rod_Weight_Air'])[0][1]]) + twr.writerow(['Force',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Force'])[0][1]]) + twr.writerow(['Stretch',c.read_tag(['Taper.Taper['+str(taps) +'].Calculated.Stretch'])[0][1]]) + twr.writerow(["",""]) + else: + break + twr.writerow(["UnitConfig",""]) + twr.writerow(['Pump_Diameter',c.read_tag(['UnitConfig.Pump_Diameter'])[0][1]]) + tFile.close() + read_tapers = True + print "TAPER DATA READ: "+ tFilename + + ################## + # GAUGE OFF DATA # + ################## + gauge_off = c.read_tag(['Gauge_Off_Command'])[0][1] + if (gauge_off == 0): + if already_gauged_off: + already_gauged_off = False + print "Already gauged off... Setting gauge_off to False" + + if (gauge_off and (not already_gauged_off)): + print "Gauging off..." + gYear = c.read_tag(['GAUGEOFF_DateTime.Year'])[0][1] + gMonth = c.read_tag(['GAUGEOFF_DateTime.Month'])[0][1] + gDay = c.read_tag(['GAUGEOFF_DateTime.Day'])[0][1] + gHour = c.read_tag(['GAUGEOFF_DateTime.Hour'])[0][1] + gMin = c.read_tag(['GAUGEOFF_DateTime.Min'])[0][1] + gSec = c.read_tag(['GAUGEOFF_DateTime.Sec'])[0][1] + gauge_date = datetime(year = gYear, month = gMonth,day = gDay,hour = gHour,minute = gMin,second = gSec) + percent_run = round(c.read_tag(['GAUGEOFF_Percent_Run'])[0][1],2) + kWh = round(c.read_tag(['GAUGEOFF_kWh'])[0][1],3) + electricity_cost = round(c.read_tag(['GAUGEOFF_Electricity_Cost'])[0][1],2) + peak_load = round(c.read_tag(['GAUGEOFF_Max_Load'])[0][1],3) + min_load = round(c.read_tag(['GAUGEOFF_Min_Load'])[0][1],3) + average_SPM = round(c.read_tag(['GAUGEOFF_Average_SPM'])[0][0],4) + production_calculated = round(c.read_tag(['GAUGEOFF_Production_Calculated'])[0][1],2) + full_card_production = round(c.read_tag(['GAUGEOFF_Full_Card_Production'])[0][1],2) + polished_rod_HP = round(c.read_tag(['GAUGEOFF_Polished_Rod_HP'])[0][1],3) + lifting_cost = round(c.read_tag(['GAUGEOFF_Lifting_Cost'])[0][1],4) + fluid_above_pump = round(c.read_tag(['GAUGEOFF_Fluid_Above_Pump'])[0][1],2) + pump_intake_pressure = round(c.read_tag(['GAUGEOFF_pump_intake_pressure'])[0][1],2) + kWh_regen = round(c.read_tag(['GAUGEOFF_kWh_regen'])[0][1],2) + inflow_rate = round(c.read_tag(['GAUGEOFF_Inflow_Rate'])[0][1],4) + + db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + print """INSERT INTO WellData.Hist_Day (gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate) VALUES ('%s', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f');"""%(gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate) + storeHist = cur.execute("""INSERT INTO WellData.Hist_Day (gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate) VALUES ('%s', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f', '%f');"""%(gauge_date, percent_run, kWh, electricity_cost, peak_load, min_load, average_SPM, production_calculated, full_card_production, polished_rod_HP, lifting_cost, fluid_above_pump, pump_intake_pressure, kWh_regen, inflow_rate)) + db.commit() + db.close() + + already_gauged_off = True + print "Gauged off!" + + + # ################## + # # WELL TEST DATA # + # ################## + + well_test_entered = c.read_tag(['Well_Test.Test_Submit'])[0][1] + if (well_test_entered == 0): + if already_entered_well_test: + already_entered_well_test = False + print "Already entered well Test... Setting well_test_entered to False" + if (well_test_entered and (not already_entered_well_test) and well_test_entered != 911): + print "Well Test Entered" + + tYear = c.read_tag(['Well_Test.DateTime_Complete.Year'])[0][1] + tMonth = c.read_tag(['Well_Test.DateTime_Complete.Month'])[0][1] + tDay = c.read_tag(['Well_Test.DateTime_Complete.Day'])[0][1] + tHour = c.read_tag(['Well_Test.DateTime_Complete.Hour'])[0][1] + tMin = c.read_tag(['Well_Test.DateTime_Complete.Min'])[0][1] + tSec = c.read_tag(['Well_Test.DateTime_Complete.Sec'])[0][1] + test_date = datetime(year = tYear, month = tMonth,day = tDay,hour = tHour,minute = tMin,second = tSec) + test_duration = round(c.read_tag(['Well_Test.Test_Duration'])[0][1],3) + v_water = round(c.read_tag(['Well_Test.Volume_Water'])[0][1],3) + v_oil = round(c.read_tag(['Well_Test.Volume_Oil'])[0][1],3) + v_gas = round(c.read_tag(['Well_Test.Volume_Gas'])[0][1],3) + p_v_water = round(c.read_tag(['Well_Test.Projected_Volume_Water'])[0][1],3) + p_v_oil = round(c.read_tag(['Well_Test.Projected_Volume_Oil'])[0][1],3) + k_factor = round(c.read_tag(['Well_Test.k_Factor'])[0][1],3) + api_oil = round(c.read_tag(['Well_Test.API_Oil'])[0][1],3) + sg_water = round(c.read_tag(['Well_Test.SG_Water'])[0][1],3) + + db = MySQLdb.connect(host="localhost",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + test_query = "INSERT INTO WellData.Well_Test (test_date, test_volume_oil, test_volume_water, test_volume_gas, k_factor, projected_volume_oil, projected_volume_water, api_gravity_oil, sg_water, test_hours) VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}', '{8}', '{9}');".format(test_date, v_oil, v_water, v_gas, k_factor, p_v_oil, p_v_water, api_oil, sg_water, test_duration) + print test_query + storeTest = cur.execute(test_query) + db.commit() + db.close() + + already_entered_well_test = True + print "Well Test Stored!" + + sleep(.20) diff --git a/getTodaysTotals.py b/getTodaysTotals.py new file mode 100644 index 0000000..f670e83 --- /dev/null +++ b/getTodaysTotals.py @@ -0,0 +1,66 @@ +import csv +from datetime import datetime +import os +import sys +from random import randint +import time +import MySQLdb + +def main(): + + db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + query = "SELECT * FROM WellData.config ORDER BY dateChanged DESC LIMIT 1;" + cur.execute(query) + setup = cur.fetchall() + db.commit() + db.close() + try: + PLC_IP_ADDRESS = setup[0][2] + PLC_TYPE = setup[0][1] + except: + print("PLC Address not set in database... using default of 192.168.1.10") + PLC_IP_ADDRESS = "192.168.1.10" + PLC_TYPE = "VFD" + + from pycomm.ab_comm.clx import Driver as ClxDriver + c = ClxDriver(True, 'ClxDriver.log') + + today_tags = [ + {'name':"Average_SPM",'tag':"TODAY_Average_SPM"}, + {'name':"Downhole_Net_Stroke",'tag':"TODAY_Downhole_NetStroke"}, + {'name':"Electricity_Cost",'tag':"TODAY_Electricity_Cost"}, + {'name':"Fluid_Level",'tag':"TODAY_Fluid_Above_Pump"}, + {'name':"Full_Card_Production",'tag':"TODAY_Full_Card_Production"}, + {'name':"Inflow_Rate",'tag':"TODAY_Inflow_Rate"}, + {'name':"kWh",'tag':"TODAY_kWh"}, + {'name':"kWh_Regen",'tag':"TODAY_kWh_Regen"}, + {'name':"Lifting_Cost",'tag':"TODAY_Lifting_Cost"}, + {'name':"Peak_Load",'tag':"TODAY_Max_Load"}, + {'name':"Min_Load",'tag':"TODAY_Min_Load"}, + {'name':"Percent_Run",'tag':"TODAY_Percent_Run"}, + {'name':"Polished_Rod_HP",'tag':"TODAY_Polished_Rod_HP"}, + {'name':"Calculated_Production",'tag':"TODAY_Production_Calculated"}, + {'name':"Projected_Production",'tag':"TODAY_Production_Projected"}, + {'name':"Pump_HP",'tag':"TODAY_Pump_HP"}, + {'name':"Pump_Intake_Presure",'tag':"TODAY_Pump_Intake_Pressure"}, + {'name':"Surface_Stroke_Length",'tag':"TODAY_Surface_StrokeLength"}, + {'name':"Tubing_Movement",'tag':"TODAY_Tubing_Movement"} + ] + + out_tags = {} + try: + if c.open(PLC_IP_ADDRESS): + out_list = map(lambda i: {'name':i['name'], 'value':c.read_tag([i['tag']])[0][1]}, today_tags) + return {'status':'success', 'values':out_list} + # for i in today_tags: + # out_tags[i['name']] = c.read_tag([i['tag']])[0][1] + # return out_tags + + + except Exception, e: + # print("FATAL ERROR: Communication Error connecting to the PLC... ", e) + return {'status':'error', 'message':e} + +if __name__ == '__main__': + print main() diff --git a/readTag.py b/readTag.py new file mode 100644 index 0000000..52bad46 --- /dev/null +++ b/readTag.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +import os +import sys +import MySQLdb + +def main(tagName): + db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + query = "SELECT * FROM WellData.config ORDER BY dateChanged DESC LIMIT 1;" + cur.execute(query) + setup = cur.fetchall() + db.commit() + db.close() + + PLC_IP_ADDRESS = setup[0][2] + + #PYCOMM Connection to PLC + from pycomm.ab_comm.clx import Driver as ClxDriver + + c = ClxDriver(True, 'ClxDriver.log') + + def readString(tag): + read_vals = c.read_array(tag, 82) + string = filter(lambda b: b != "",map(lambda a: chr(a[1]),read_vals)) + return "".join(string) + + if c.open(PLC_IP_ADDRESS): + out = {} + try: + result = c.read_tag([tagName]) + if result[0][2] == None: + raise ValueError('Tag not found') + out['status'] = "success" + out['value'] = result[0][1] + out['type'] = result[0][2] + except Exception, e: + out['status'] = "error" + out['message'] = "Tag not found" + return out + +if __name__ == '__main__': + res = main(sys.argv[1]) + print res diff --git a/restorePLC.py b/restorePLC.py new file mode 100644 index 0000000..e59d665 --- /dev/null +++ b/restorePLC.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python + +''' +Created on Oct 1, 2014 + +@author: PJMcdona +''' + + +#from prettytable import PrettyTable +import csv +from datetime import datetime +import os +import sys +from random import randint +from time import sleep +import MySQLdb + +def main(fullfilepath): + + db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + query = "SELECT * FROM WellData.config ORDER BY dateChanged DESC LIMIT 1;" + cur.execute(query) + setup = cur.fetchall() + db.commit() + db.close() + + PLC_IP_ADDRESS = setup[0][2] + PLC_TYPE = setup[0][1] + + + + #TUXEIP Connection to PLC + from tuxeip import TuxEIP, LGX, LGX_REAL, LGX_BOOL, LGX_INT, LGX_DINT, LGX_SINT + tux = TuxEIP(libpath="/usr/lib/libtuxeip.so") + sess = tux.OpenSession(PLC_IP_ADDRESS) + reg = tux.RegisterSession(sess) + conn = tux.ConnectPLCOverCNET(sess, LGX, 1, 100, 123, randint(0,9999), 123, 321, 100, 5000, 1, '01') + + def WriteToPLC(tag, ttype, value): + try: + r=0 + if ttype == "INT": + r = tux.WriteLGXData(sess, conn, tag, LGX_INT, int(value), 1) + elif ttype == "DINT": + r = tux.WriteLGXData(sess, conn, tag, LGX_DINT, int(value), 1) + elif ttype == "SINT": + r = tux.WriteLGXData(sess, conn, tag, LGX_SINT, int(value), 1) + elif ttype == "REAL": + r = tux.WriteLGXData(sess, conn, tag, LGX_REAL, float(value), 1) + elif ttype == "BOOL": + r = tux.WriteLGXData(sess, conn, tag, LGX_BOOL, int(value), 1) + else: + print "invalid type", ttype + r = -1 + if r == -1: + print "Error writing to", tag + except: + print "Error writing to", tag + + def ReadFromPLC(tag, tag_type): + try: + if (tag_type == "REAL"): + a = tux.ReadLGXDataAsFloat(sess, conn, tag, 1) + result = round(float(a[0]),3) + #elif (tag_type == "INT" or tag_type == "DINT" or tag_type =="SINT"): + elif tag_type[-3:] == "INT": + a = tux.ReadLGXDataAsInteger(sess, conn, tag, 1) + result = int(a[0]) + elif (tag_type == "BOOL"): + a = tux.ReadLGXDataAsInteger(sess, conn, tag, 1) + intermediate = int(a[0]) + if intermediate == 0: + result = 0 + else: + result = 1 + elif (tag_type =="STRING"): + a = tux.ReadLGXDataAsInteger(sess, conn, tag, 82) + word = "" + for ch in range(len(a)): + word = word + unichr(int(a[ch])) + result = word + else: + result = "?" + return result + except: + print "Unable to read " + tag + return 911 + + errors = [] + myfile = open(fullfilepath, 'rb') + wr = csv.reader(myfile) + for row in wr: + if len(row) == 3: + (tag, value, tagType) = row + WriteToPLC(tag, tagType, value) + actual = ReadFromPLC(tag, tagType) + verify = False + if tagType == "REAL": + verify = actual == float(value) + elif tagType[-3:] == "INT": + verify = actual == int(value) + elif tagType == "BOOL": + verify = actual == int(value) + if not verify: + errors.append( "Validation Error:", tag, "does not equal", value, "(actual value:", actual,")") + myfile.close() + print "Restore Complete with", len(errors), "errors." + if len(errors) > 0: + print "-------------------------" + print "-- ERRORS --" + print "-------------------------" + for i in range(0,len(errors)): + print i+1,"-",errors[i] +if __name__ == '__main__': + main(sys.argv[1]) diff --git a/tuxeip.py b/tuxeip.py new file mode 100644 index 0000000..1c39e40 --- /dev/null +++ b/tuxeip.py @@ -0,0 +1,276 @@ +#! /usr/bin/env python + +# Copyright (C) 2014 Gayner Technical Services Pty Ltd + +from ctypes import * + +# PLC TYPES +Unknow=0 +PLC=1 +SLC500=2 +LGX=3 + +# EIP DATA TYPES +PLC_BIT=1 +PLC_BIT_STRING=2 +PLC_BYTE_STRING=3 +PLC_INTEGER=4 +PLC_TIMER=5 +PLC_COUNTER=6 +PLC_CONTROL=7 +PLC_FLOATING=8 +PLC_ARRAY=9 +PLC_ADRESS=15 +PLC_BCD=16 + +# LOGIX DATA TYPES +LGX_BOOL=0xC1 +LGX_BITARRAY=0xD3 +LGX_SINT=0xC2 +LGX_INT=0xC3 +LGX_DINT=0xC4 +LGX_REAL=0xCA + +class Eip_Session(Structure): + _fields_ = [ + ('sock',c_int), + ('Session_Handle', c_uint), + ('Sender_ContextL',c_int), + ('Sender_ContextH',c_int), + ('timeout', c_int), + ('references', c_int), + ('Data', c_void_p), + ] + +class Eip_Connection(Structure): + _fields_ = [ + ('Eip_Session', Eip_Session), + ('references', c_int), + ('Data', c_void_p), + ('ConnectionSerialNumber', c_uint), + ('OriginatorVendorID', c_uint), + ('OriginatorSerialNumber', c_int), + ('OT_ConnID', c_int), + ('TO_ConnID', c_int), + ('packet', c_short), + ('Path_size', c_byte) + ] + +class Eip_PLC_Read(Structure): + _fields_ = [ + ('type', c_int), + ('Varcount', c_int), + ('totalise', c_int), + ('elementsize', c_int), + ('mask', c_uint), + ] + +class TuxEIPException(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return repr(self.value) + +class TuxEIP: + + def __init__(self, **kwargs): + self.__libpath = kwargs.get("libpath", "libtuxeip.dylib") + self.__tuxeip = CDLL(self.__libpath) + self.__tuxeip._cip_err_msg.restype = c_char_p + + def __del__(self): + del self.__tuxeip + + def OpenSession(self, slaveip_, slaveport_=44818, slavetimeout_=1000): + self.__tuxeip._OpenSession.restype = POINTER(Eip_Session) + + # Convert params to C types + slaveip = c_char_p(slaveip_) + slaveport = c_int(slaveport_) + slavetimeout = c_int(slavetimeout_) + + session = self.__tuxeip._OpenSession(slaveip, slaveport, slavetimeout) + + #print self.__tuxeip._cip_err_msg, self.__tuxeip._cip_errno, self.__tuxeip._cip_ext_errno + + if bool(session) == False: + raise TuxEIPException("Could not open session to " + str(slaveip) + ":" + str(slaveport)) + + return session + + def RegisterSession(self, sess_): + self.__tuxeip._RegisterSession.restype = c_int + reg = self.__tuxeip._RegisterSession(sess_) + + if reg != False: + raise TuxEIPException("Could not register session") + + return reg + + def ConnectPLCOverCNET(self, sess_, plctype_, priority_, timeoutticks_, connid_, conserial_, + vendorid_, serialnum_, timeoutmult_, rpi_, transport_, slavepath_): + # Convert params to C types + priority = c_byte(priority_) + timeoutticks = c_byte(timeoutticks_) + connid = c_uint(connid_) + conserial = c_ushort(conserial_) + vendorid = c_ushort(vendorid_) + serialnum = c_uint(serialnum_) + timeutmult = c_byte(timeoutmult_) + rpi = c_uint(rpi_) + transport = c_byte(transport_) + slavepath = c_char_p(slavepath_) + pathlength = len(slavepath_) + + self.__tuxeip._ConnectPLCOverCNET.restype = POINTER(Eip_Connection) + + connection = self.__tuxeip._ConnectPLCOverCNET( + sess_, + plctype_, + priority, + timeoutticks, + connid, + conserial, + vendorid, + serialnum, + timeutmult, + rpi, + transport, + slavepath, + pathlength + ) + + if bool(connection) == False: + raise TuxEIPException("Could not connect to CPU") + + return connection + + def ReadLgxData(self, sess_, conn_, var_, num_): + self.__tuxeip._ReadLgxData.restype = POINTER(Eip_PLC_Read) + readdata = self.__tuxeip._ReadLgxData(sess_, conn_, var_, num_) + + if bool(readdata) == False: + raise TuxEIPException("Read data failed") + + return readdata + + def WriteLGXData(self, sess_, conn_, address_, datatype_, data_, num_ ): + if datatype_ == LGX_INT or datatype_ == LGX_BOOL or datatype_ == LGX_DINT or datatype_ == LGX_SINT: + data = c_int(data_) + elif datatype_ == LGX_REAL: + data = c_float(data_) + else: + raise TuxEIPException("Write data failed") + + data = self.__tuxeip._WriteLgxData(sess_, conn_, address_, datatype_, byref(data), num_) + + return data + + def ReadLGXDataAsFloat(self, sess_, conn_, var_, num_): + data = self.ReadLgxData(sess_, conn_, var_, num_) + d = self.GetLGXValueAsFloat(data) + self.FreePLCRead(data) + return d + + def ReadLGXDataAsInteger(self, sess_, conn_, var_, num_): + data = self.ReadLgxData(sess_, conn_, var_, num_) + d = self.GetLGXValueAsInteger(data) + self.FreePLCRead(data) + return d + + def ReadPLCDataAsFloat(self, sess_, conn_, dhp_, routepath_, routesize_, plctype_, tns_, address_, number_): + data = self.ReadPLCData(sess_, conn_, dhp_, routepath_, routesize_, plctype_, tns_, address_, number_) + d = self.PCCC_GetValueAsFloat(data) + self.FreePLCRead(data) + return d + + def ReadPLCDataAsInteger(self, sess_, conn_, dhp_, routepath_, routesize_, plctype_, tns_, address_, number_): + data = self.ReadPLCData(sess_, conn_, dhp_, routepath_, routesize_, plctype_, tns_, address_, number_) + d = self.PCCC_GetValueAsInteger(data) + self.FreePLCRead(data) + return d + + def ReadPLCData(self, sess_, conn_, dhp_, routepath_, routesize_, plctype_, tns_, address_, number_): + self.__tuxeip._ReadPLCData.restype = POINTER(Eip_PLC_Read) + readdata = self.__tuxeip._ReadPLCData(sess_, conn_, dhp_, routepath_, routesize_, plctype_, + tns_, address_, number_) + + if bool(readdata) == False: + raise TuxEIPException("Read data failed") + + return readdata + + def GetLGXValueAsFloat(self, readdata_): + if bool(readdata_) == False: + return None + + self.__tuxeip._GetLGXValueAsFloat.restype = c_float + values = [] + for i in range(0, readdata_.contents.Varcount): + v = self.__tuxeip._GetLGXValueAsFloat(readdata_, i) + values.append(v) + + return values + + def GetLGXValueAsInteger(self, readdata_): + if bool(readdata_) == False: + return None + + self.__tuxeip._GetLGXValueAsInteger.restype = c_int + values = [] + for i in range(0, readdata_.contents.Varcount): + v = self.__tuxeip._GetLGXValueAsInteger(readdata_, i) + values.append(v) + + return values + + def PCCC_GetValueAsFloat(self, readdata_): + if bool(readdata_) == False: + return None + + self.__tuxeip._PCCC_GetValueAsFloat.restype = c_float + values = [] + for i in range(0, readdata_.contents.Varcount): + v = self.__tuxeip._PCCC_GetValueAsFloat(readdata_, i) + values.append(v) + + return values + + def PCCC_GetValueAsInteger(self, readdata_): + if bool(readdata_) == False: + return None + + self.__tuxeip._PCCC_GetValueAsInteger.restype = c_int + values = [] + for i in range(0, readdata_.contents.Varcount): + v = self.__tuxeip._PCCC_GetValueAsInteger(readdata_, i) + values.append(v) + + return values + + def WritePLCData(self, sess_, conn_, dhp_, routepath_, routesize_, plctype_, tns_, address_, datatype_, data_, number_): + + if datatype_ == PLC_INTEGER: + data = c_int(data_) + elif datatype_ == PLC_FLOATING: + data = c_float(data_) + else: + raise TuxEIPException("Variable type not supported" + str(datatype_)) + + result = self.__tuxeip._WritePLCData(sess_, conn_, dhp_, routepath_, routesize_, plctype_, + tns_, address_, datatype_, byref(data), number_) + + return result + + def Forward_Close(self, conn_): + self.__tuxeip._Forward_Close(conn_) + + def UnRegisterSession(self, sess_): + self.__tuxeip._UnRegisterSession(sess_) + + def CloseSession(self, sess_): + self.__tuxeip.CloseSession(sess_) + + def FreePLCRead(self, data_): + self.__tuxeip._FreePLCRead(data_) diff --git a/writeTag.py b/writeTag.py new file mode 100644 index 0000000..9d772d5 --- /dev/null +++ b/writeTag.py @@ -0,0 +1,120 @@ +from pycomm.ab_comm.clx import Driver as ClxDriver +import sys +import MySQLdb +from time import sleep + +def closeEnough(a,b): + return abs(a - b) <= 0.1 + +def getPLCIP(): + db = MySQLdb.connect(host="127.0.0.1",user="website",passwd="henrypump",db="WellData") + cur = db.cursor() + query = "SELECT * FROM WellData.config ORDER BY dateChanged DESC LIMIT 1;" + cur.execute(query) + setup = cur.fetchall() + db.commit() + db.close() + + return setup[0][2] + +def readTag(tagName): + PLC_IP_ADDRESS = getPLCIP() + + c = ClxDriver(True, 'ClxDriver.log') + + def readString(tag): + read_vals = c.read_array(tag, 82) + string = filter(lambda b: b != "",map(lambda a: chr(a[1]),read_vals)) + return "".join(string) + + if c.open(PLC_IP_ADDRESS): + out = {} + try: + result = c.read_tag([tagName]) + if result[0][2] == None: + raise ValueError('Tag not found') + out['status'] = "success" + out['value'] = result[0][1] + out['type'] = result[0][2] + except Exception, e: + out['status'] = "error" + out['message'] = "Tag Not Found" + c.close() + return out + +def main(tag, value): + + r = 0 + PLC_IP_ADDRESS = getPLCIP() + + readObj = readTag(tag) + if readObj['status'] == "error": + return readObj + elif readObj['status'] == 'success': + tagType = readObj['type'] + + if tagType[:-3] == "INT" or tagType == "BOOL": + value = int(value) + elif tagType == "REAL": + value = float(value) + c = ClxDriver(True, 'ClxDriver.log') + if c.open(PLC_IP_ADDRESS): + r = c.write_tag(tag, value, tagType) + else: + return {"status": 'error', "message": "not connected to PLC"} + c.close() + + sleep(2) + + return readTag(tag) + +def writeTagAndVerify(tag,value, sleepValue=2): + """Writes the specified value to tag and confirms that the value has been set""" + r = 0 + PLC_IP_ADDRESS = getPLCIP() + readObj = readTag(tag) + if readObj['status'] == "error": + return readObj + elif readObj['status'] == 'success': + tagType = readObj['type'] + prevValue = readObj['value'] + if tagType[:-3] == "INT" or tagType == "BOOL": + value = int(value) + elif tagType == "REAL": + value = float(value) + c = ClxDriver(True, 'ClxDriver.log') + if c.open(PLC_IP_ADDRESS): + r = c.write_tag(tag, value, tagType) + sleep(float(sleepValue)) + newObj = readTag(tag) + if newObj['status'] == "error": + return newObj + elif newObj['status'] == 'success': + newTagType = newObj['type'] + newValue = newObj['value'] + if (newTagType == tagType): + if (closeEnough(newValue, value)): + return {'status':'success', 'value':newValue, 'type':newTagType, 'verified':'true','prevValue':prevValue} + else: + return {"status": 'error', "message": "The tag value does not match the specified value", "value":newValue} + else: + return {"status": 'error', "message": "Somehow the tag type has changed"} + else: + return {"status": 'error', "message": "not connected to PLC"} + c.close() + +def toggle(tag, toggleVal, timeToggled=2): + val = int(toggleVal) + set_tag = writeTagAndVerify(tag,toggleVal,sleepValue=1) + if set_tag['status']== 'success': + sleep(timeToggled) + reset_tag = writeTagAndVerify(tag, set_tag['prevValue'],sleepValue=1) + if reset_tag['status'] == "success": + return {'status':'success'} + else: + return {'status':'error', 'message':reset_tag['message']} + else: + return {'status':'error', 'message':set_tag['message']} + +if __name__ == '__main__': + print main(sys.argv[1], sys.argv[2])