35 Commits

Author SHA1 Message Date
Patrick McDonagh
ab32f65d7c Fixes restart command typo 2016-12-05 17:15:53 -06:00
Patrick McDonagh
0fba320e84 Updates README file 2016-12-05 16:22:42 -06:00
Patrick McDonagh
099fe06123 Handling PID file from within init script 2016-12-05 15:40:24 -06:00
Patrick McDonagh
a733ec4d9c write PID to file 2016-12-05 15:12:14 -06:00
Patrick McDonagh
912c8b17cf Uses start.sh instead of script variable 2016-12-05 12:50:46 -06:00
Patrick McDonagh
29c406eaa3 Adds startup script 2016-12-05 12:28:54 -06:00
Patrick McDonagh
c143f7ca6e Silences HTTPS warnings since we're using a self-signed certificate 2016-11-29 11:12:42 -06:00
Patrick McDonagh
14999fbab9 Removes unnecessary files and makes adjustment for new utils module in pycomm_helper 2016-11-28 16:18:20 -06:00
Patrick McDonagh
fdbee7c479 Merged in POCONSOLE-25-Flask (pull request #1)
POCONSOLE-25 flask
2016-11-21 23:33:56 +00:00
Patrick McDonagh
387e08d5bd Attempts to save some space by rounding points in cards to 2 digits 2016-11-18 14:32:07 -06:00
Patrick McDonagh
6f4f925f76 updates gauge off url 2016-11-17 16:20:03 -06:00
Patrick McDonagh
00c04636c8 Fixes error using stroke_tags 2016-11-15 11:21:52 -06:00
Patrick McDonagh
a8ed2b5c08 Mostly completes POCONSOLE-39. Still need to get it on an actual well to test the data coming in 2016-11-11 17:43:52 -06:00
Patrick McDonagh
2d928cc1aa per POCONSOLE-59, updates submodule 2016-09-09 18:16:53 -05:00
Patrick McDonagh
49e6e0605f Fix to init script 2016-08-05 16:00:42 -05:00
Patrick McDonagh
a61cdf0e55 Updated Tag submodule to work with POCONSOLE-51 (HTTPS) 2016-06-23 10:23:28 -05:00
Patrick McDonagh
2d1b3d9134 POCONSOLE-51 forces HTTPS 2016-06-22 11:58:02 -05:00
Patrick McDonagh
637ad310db Missed one. 2016-06-16 16:08:43 -05:00
Patrick McDonagh
59d1f08f8c Fixed tag names for using pretty names 2016-06-16 16:06:59 -05:00
Patrick McDonagh
a1200ec234 Fixes tag read bug 2016-06-16 10:50:54 -05:00
Patrick McDonagh
4481aa47b0 Updates tag so I don't have to keep fixing Micro800 imports 2016-06-14 19:09:03 -05:00
Patrick McDonagh
706c40a4ed Fixes driver. This file runs & works. 2016-06-14 19:06:35 -05:00
Patrick McDonagh
9035959a1b fixes map functions 2016-06-08 15:55:31 -05:00
Patrick McDonagh
b081120858 run_status uses 'status' instead of 'val' 2016-06-06 20:52:35 -05:00
Patrick McDonagh
bf90060f97 need to specify the id of the data_type for main_plc 2016-06-06 20:50:00 -05:00
Patrick McDonagh
b750edc4bd getMainPLC was returning a list instead of an object 2016-06-06 20:47:24 -05:00
Patrick McDonagh
22f20d90a2 Was never getting main PLC 2016-06-06 20:45:38 -05:00
Patrick McDonagh
d8a589c33f Device Types not being found before accessing 2016-06-06 20:43:30 -05:00
Patrick McDonagh
9151a33701 Adds a little error message 2016-06-06 16:39:18 -05:00
Patrick McDonagh
061189de4e adds Sails datalogger 2016-06-06 14:48:05 -05:00
Patrick McDonagh
a871da9c61 Uses the sail-ready tag submodule 2016-06-06 13:38:22 -05:00
Patrick McDonagh
4311bc5037 adds init script 2016-05-13 18:08:53 -05:00
Patrick McDonagh
76c5f63597 Create Seed functions 2016-05-08 21:14:36 -05:00
Patrick McDonagh
56c433545a Fixed some non-default IP address issues 2016-04-25 16:09:24 -05:00
Patrick McDonagh
133f0c36ad Prevent printing to console 2016-04-23 16:40:50 -05:00
21 changed files with 441 additions and 1726 deletions

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "tag"]
path = tag
url = http://patrickjmcd@bitbucket.poconsole.net/scm/poconsole/tag.git

View File

@@ -4,8 +4,20 @@ By Henry Pump
## Installation
1. Clone this repo
2. Make either setdb_MySQL.sh or setdb_SQLite.sh executable
3. Run setdb_MySQL.sh or setdb_SQLite.sh
2. Make the init script and start scripts executable. Move the init script and register it.
```
chmod +x start.sh
chmod +x datalogger.sh
sudo cp datalogger.sh /etc/init.d/datalogger
sudo update-rc.d datalogger defaults
```
## Running the Data Logger
```
sudo service datalogger start
```
## Credits
Developed by Patrick McDonagh, Henry Pump

320
dataLogger.py Normal file
View File

@@ -0,0 +1,320 @@
#!/usr/bin/env python
import time
from pycomm.ab_comm.clx import Driver as ClxDriver
from pycomm_helper.utils import readArray, readTag
from pycomm_helper.tag import Tag
from pycomm_helper.alarm import AnalogAlarm, bitAlarm
import traceback
import json
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from requests.packages.urllib3.exceptions import InsecurePlatformWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
requests.packages.urllib3.disable_warnings(InsecurePlatformWarning)
# DEFAULTS
API_METHOD = "https"
API_ADDRESS = "localhost"
API_PORT = 5000
API_BASE_URL = "{}://{}:{}/api".format(API_METHOD, API_ADDRESS, API_PORT)
scan_rate = 30 # seconds
save_all = "test" # use True, False, or any string
plc_handshake_tags = {}
last_handshake_time = 0
# GLOBAL VARIABLES
device_types = {}
devices = []
main_plc = {}
# ---------- MAP FUNCTIONS ---------- #
maps = {
'modeMap': {0: "Error", 1: "Auto", 2: "POC", 3: "Timer", 4: "Manual", 5: "DH PID"},
'card_type_map': {0: "Normal", 1: "Shutdown", 2: "Alarm", 3: "Startup", 4: "Low Fillage"},
'statusMap': {0: 'Stopped', 1: 'Running', 2: 'Pumped Off', 3: 'Faulted', 4: 'Starting', 5: 'Recovering', 100: 'Read Error', 1000: 'PLC Error', 9999: 'No Response'},
None: None,
'null': None
}
# ---------- TAGS ---------- #
tag_list = {}
bit_tags = {}
safety_tags = {}
custom_tags = {}
class Status(Tag):
def sendToDB(self):
global API_BASE_URL
post_data = {'run_status': self.value}
r = requests.post('{}/run_status_log'.format(API_BASE_URL), data=json.dumps(post_data), headers={'Content-Type': 'application/json'}, verify=False)
resp = json.loads(r.text)
print("Stored {} for Run Status at {}".format(resp['run_status'], self.name, resp['created_on']))
self.last_send_time = time.time()
def readConfig():
global API_BASE_URL, scan_rate, save_all
req = requests.get('{}/configs'.format(API_BASE_URL), verify=False)
res = json.loads(req.text)['objects']
if len(res) > 0:
for x in res:
if x['parameter'] == "scan_rate":
try:
scan_rate = int(x['val'])
except Exception as e:
print("Error setting scan_rate to {}".format(x['val']))
elif x['parameter'] == "save_all":
try:
if x['val'].lower() == 'true':
save_all = True
elif x['val'].lower() == 'true':
save_all = False
else:
print("Invalid save_all parameter: {}".format(x['val']))
except Exception as e:
print("Error setting save_all to {}".format(x['val']))
else:
print("No configuration data found.")
return True
def getDeviceTypes():
global API_BASE_URL
req = requests.get('{}/device_types'.format(API_BASE_URL), verify=False)
res = json.loads(req.text)['objects']
device_types = {}
if len(res) > 0:
for x in res:
device_types[x['_id']] = x['device_type']
return device_types
else:
print("No device type data found.")
return False
def setupTags():
global device_types, API_BASE_URL, tag_list, safety_tags, bit_tags
get_tag_request = requests.get('{}/tags'.format(API_BASE_URL), verify=False)
tags = json.loads(get_tag_request.text)['objects']
for t in tags:
tag_list[t['name']] = Tag(t['name'], t['tag'], t['_id'], t['data_type'], t['change_threshold'], t['guarantee_sec'], mapFn=maps[t['map_function']], ip_address=t['device']['address'], device_type=device_types[t['device']['device_type_id']])
get_event_request = requests.get('{}/event_configs'.format(API_BASE_URL), verify=False)
events = json.loads(get_event_request.text)['objects']
for e in events:
if e['event_type'] == 'analog':
safety_tags[e['name']] = AnalogAlarm(e['name'], e['tag'], e['_id'], ip_address=e['device']['address'], device_type=device_types[e['device']['device_type_id']])
elif e['event_type'] == 'bit':
bit_tags[e['name']] = bitAlarm(e['name'], e['tag'], e['condition'], e['_id'], ip_address=e['device']['address'], device_type=device_types[e['device']['device_type_id']])
return True
def getMainPLC():
global API_BASE_URL
get_plc_request = requests.get('{}/devices'.format(API_BASE_URL), verify=False)
return json.loads(get_plc_request.text)['objects'][0]
def readGaugeOffData():
global main_plc
try:
gaugeOffData = {
'spm_average': readTag(main_plc['address'], 'GAUGEOFF_Average_SPM')[0],
'downhole_gross_stroke_average': readTag(main_plc['address'], 'GAUGEOFF_Downhole_GrossStroke')[0],
'downhole_net_stroke_average': readTag(main_plc['address'], 'GAUGEOFF_Downhole_NetStroke')[0],
'electricity_cost_total': readTag(main_plc['address'], 'GAUGEOFF_Electricity_Cost')[0],
'fluid_level_average': readTag(main_plc['address'], 'GAUGEOFF_Fluid_Above_Pump')[0],
'full_card_production_total': readTag(main_plc['address'], 'GAUGEOFF_Full_Card_Production')[0],
'inflow_rate_average': readTag(main_plc['address'], 'GAUGEOFF_Inflow_Rate')[0],
'kWh_used_total': readTag(main_plc['address'], 'GAUGEOFF_kWh')[0],
'kWh_regen_total': readTag(main_plc['address'], 'GAUGEOFF_kWh_Regen')[0],
'lifting_cost_average': readTag(main_plc['address'], 'GAUGEOFF_Lifting_Cost')[0],
'peak_pr_load': readTag(main_plc['address'], 'GAUGEOFF_Max_Load')[0],
'min_pr_load': readTag(main_plc['address'], 'GAUGEOFF_Min_Load')[0],
'percent_run': readTag(main_plc['address'], 'GAUGEOFF_Percent_Run')[0],
'polished_rod_hp_average': readTag(main_plc['address'], 'GAUGEOFF_Polished_Rod_HP')[0],
'pump_hp_average': readTag(main_plc['address'], 'GAUGEOFF_Production_Calculated')[0],
'production_total': readTag(main_plc['address'], 'GAUGEOFF_Pump_HP')[0],
'pump_intake_pressure_average': readTag(main_plc['address'], 'GAUGEOFF_Pump_Intake_Pressure')[0],
'surface_stroke_length_average': readTag(main_plc['address'], 'GAUGEOFF_Surface_StrokeLength')[0],
'tubing_movement_average': readTag(main_plc['address'], 'GAUGEOFF_Tubing_Movement')[0]
}
except Exception as e:
print("Could not get all gauge off tags: {}".format(e))
return False
post_req = requests.post(API_BASE_URL + "/gauge_off", data=json.dumps(gaugeOffData), headers={'Content-Type': 'application/json'}, verify=False)
try:
post_res_id = json.loads(post_req.text)['_id']
return True
except Exception as e:
print("Did not get a valid JSON object back, got: {}".format(post_req.text))
return False
def evalTapers():
return True
def readPoints():
global main_plc
num_points = readTag(main_plc['address'], "Card_Past[1].Num_Points")[0]
surf_pos = readArray(main_plc['address'], "Card_Past[1].Surface_Position", num_points + 1)[1:]
if len(surf_pos) > 1:
surf_pos = [round(i, 2) for i in surf_pos]
surf_pos.append(surf_pos[0])
surf_lod = readArray(main_plc['address'], "Card_Past[1].Surface_Load", num_points + 1)[1:]
if len(surf_lod) > 1:
surf_lod = [round(i, 2) for i in surf_lod]
surf_lod.append(surf_lod[0])
down_pos = readArray(main_plc['address'], "Card_Past[1].Downhole_Position", num_points + 1)[1:]
if len(down_pos) > 1:
down_pos = [round(i, 2) for i in down_pos]
down_pos.append(down_pos[0])
down_lod = readArray(main_plc['address'], "Card_Past[1].Downhole_Load", num_points + 1)[1:]
if len(down_pos) > 1:
down_pos = [round(i, 2) for i in down_pos]
down_lod.append(down_lod[0])
return([surf_pos, surf_lod, down_pos, down_lod])
def checkCardDataAndStore(last_card_id):
'''
Check to see if a new stroke has been made and stores the stroke in the database.
Returns the current ID of the card
'''
global maps, main_plc, API_BASE_URL
try:
current_card_id = readTag(main_plc['address'], 'Card_Past[1].ID')[0]
if not (last_card_id == current_card_id):
[surface_position, surface_load, downhole_position, downhole_load] = readPoints()
card_type = maps['card_type_map'][readTag(main_plc['address'], 'Card_Past[1].Card_Type')[0]]
card_data = {
'stroke_number': current_card_id,
'stroke_type': card_type,
'surf_pos': str(surface_position),
'surf_lod': str(surface_load),
'down_pos': str(downhole_position),
'down_lod': str(downhole_load)
}
r = requests.post('{}/cards'.format(API_BASE_URL), data=json.dumps(card_data), headers={'Content-Type': 'application/json'}, verify=False)
resp = json.loads(r.text)
print("CARD NUMBER {} READ AT {}!".format(resp["stroke_number"], resp['created_on']))
last_card_id = current_card_id
return current_card_id
else:
return last_card_id
except Exception as e:
print("Exception during checkCardDataAndStore: {}".format(e))
return last_card_id
def main():
global main_plc, device_types
main_plc = getMainPLC()
rc_attempts = 0
rc = readConfig()
while not rc and rc_attempts < 10:
rc = readConfig()
device_type_attempts = 0
device_types = getDeviceTypes()
while not device_types and attempts < 10:
device_types = getDeviceTypes()
if setupTags():
pass
else:
print("Unable to read tags... Restarting.")
main()
status = Status('run_status', 'Pump.Run_Status', 0, 'STRING', 0, 3600, mapFn=maps['statusMap'], ip_address=main_plc['address'], device_type=device_types[main_plc['device_type']['_id']])
read_tapers = False
already_gauged_off = False
already_entered_well_test = False
last_card_id = 0
last_status = ""
statusChanged = False
while True:
try:
current_status = status.read("test")
statusChanged = not (current_status == last_status)
if statusChanged:
last_status = current_status
last_card_id = checkCardDataAndStore(last_card_id)
# read tags in tag_list and store if values require saving
for t in tag_list:
tag = tag_list[t]
tag.read(save_all)
# check if taper data has changed and store taper parameters if it has
update_taper = readTag(main_plc['address'], "Write_Tapers")[0] > 0
if (update_taper == 0):
if read_tapers:
read_tapers = False
print("Update Tapers = False")
if (update_taper and (not read_tapers)):
print("reading taper file")
read_tapers = evalTapers()
# store gauge-off data once it is set
gauge_off = readTag(main_plc['address'], "Gauge_Off_Command")[0]
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...")
already_gauged_off = readGaugeOffData()
print("Gauged off!")
#
well_test_entered = readTag(main_plc['address'], "Well_Test.Test_Submit")[0] > 0
if well_test_entered:
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)):
for wtest in welltest_tags:
w = welltest_tags[wtest]
w.read(True)
already_entered_well_test = True
print("Well Test Stored!")
###################
# ALARMS & EVENTS #
###################
for t in safety_tags:
safety_tags[t].checkStatus(last_card_id)
for b in bit_tags:
bit_tags[b].checkStatus(last_card_id)
time.sleep(.20)
except Exception as e:
print("Error during loop: {}".format(e))
traceback.print_exc()
if __name__ == '__main__':
main()

67
datalogger.sh Executable file
View File

@@ -0,0 +1,67 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: datalogger
# Required-Start: $local_fs $network $named $time $syslog
# Required-Stop: $local_fs $network $named $time $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: Runs the Henry Pump datalogger
### END INIT INFO
SCRIPT=/root/datalogger/start.sh
RUNAS=poconsole
PIDFILE=/root/datalogger.pid
LOGFILE=/root/datalogger.log
start() {
if [ -f "$PIDFILE" ] && kill -0 $(cat $PIDFILE); then
echo 'Service already running' >&2
return 1
fi
echo 'Starting service…' >&2
local CMD="$SCRIPT &> \"$LOGFILE\" & echo \$!"
su -c "$CMD" $RUNAS > "$PIDFILE"
echo 'Service started' >&2
}
stop() {
if [ ! -f "$PIDFILE" ] || ! kill -0 $(cat "$PIDFILE"); then
echo 'Service not running' >&2
return 1
fi
echo 'Stopping service…' >&2
kill -15 $(cat "$PIDFILE") && rm -f "$PIDFILE"
echo 'Service stopped' >&2
}
uninstall() {
echo -n "Are you really sure you want to uninstall this service? That cannot be undone. [yes|No] "
local SURE
read SURE
if [ "$SURE" = "yes" ]; then
stop
rm -f "$PIDFILE"
echo "Notice: log file is not be removed: '$LOGFILE'" >&2
update-rc.d -f datalogger remove
rm -fv "$0"
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
uninstall)
uninstall
;;
restart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart|uninstall}"
esac

View File

@@ -1,204 +0,0 @@
CREATE DATABASE IF NOT EXISTS poconsole;
CREATE TABLE IF NOT EXISTS poconsole.Event_List (
id int(11) NOT NULL AUTO_INCREMENT,
alarmID int(11),
type varchar(64),
cond varchar(64),
value float,
datetime datetime,
stroke_number int(11),
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.Hist_Day (
id int(11) NOT NULL AUTO_INCREMENT,
gauge_date datetime,
percent_run float,
kWh float,
kWh_regen float,
electricity_cost float,
peak_load float,
min_load float,
average_SPM float,
production_calculated float,
full_card_production float,
polished_rod_HP float,
lifting_cost float,
fluid_above_pump float,
pump_intake_pressure float,
inflow_rate float,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.Well_Test (
id int(11) NOT NULL AUTO_INCREMENT,
test_date datetime,
test_volume_oil float,
test_volume_water float,
test_volume_gas float,
k_factor float,
projected_volume_oil float,
projected_volume_water float,
api_gravity_oil float,
sg_oil float,
sg_water float,
test_hours float,
deleted int(11) DEFAULT 0,
PRIMARY KEY (id)
);
-- CREATE TABLE IF NOT EXISTS poconsole.config (
-- id int(11) NOT NULL AUTO_INCREMENT,
-- device_type varchar(64),
-- ip_address varchar(64),
-- dateChanged datetime DEFAULT NOW(),
-- PRIMARY KEY (id)
-- );
CREATE TABLE IF NOT EXISTS poconsole.config (
id INT NOT NULL AUTO_INCREMENT,
parameter varchar(128),
val varchar(128),
dateAdded TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.Notes (
id int(11) NOT NULL AUTO_INCREMENT,
author varchar(64),
note varchar(64),
datetime datetime DEFAULT NOW(),
type int(11),
associated_stroke int(11),
deleted int(11) DEFAULT 0,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.note_types(
id int(11) NOT NULL AUTO_INCREMENT,
type varchar(64),
deleted int(11) DEFAULT 0,
PRIMARY KEY (id)
);
INSERT INTO poconsole.note_types (id, type) VALUES ('1', 'Downtime Explanation');
INSERT INTO poconsole.note_types (id, type) VALUES ('2', 'Configuration Change');
INSERT INTO poconsole.note_types (id, type) VALUES ('3', 'Info');
INSERT INTO poconsole.note_types (id, type) VALUES ('4', 'Other');
CREATE TABLE IF NOT EXISTS poconsole.fluid_shot(
id int(11) NOT NULL AUTO_INCREMENT,
shot_datetime datetime,
taken_by varchar(64),
pump_intake_pressure float,
fluid_gradient float,
friction float,
deleted int(11) DEFAULT 0,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.card_history(
id int(11) NOT NULL AUTO_INCREMENT,
Stroke_Time datetime,
Card_id int(11),
Card_Type varchar(64),
Surface_Position varchar(4000),
Surface_Load varchar(4000),
Downhole_Position varchar(4000),
Downhole_Load varchar(4000),
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.card_history_dates(
id int(11) NOT NULL AUTO_INCREMENT,
year int(11),
month int(11),
day int(11),
first_id int(11),
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.tag_classes(
id int(11) NOT NULL AUTO_INCREMENT,
tag_class varchar(64),
description varchar(64),
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.tags(
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(128),
class int(11),
tag varchar(128),
description varchar(128),
data_type varchar(32),
change_threshold float,
guarantee_sec integer(11),
map_function varchar(64),
units varchar(64),
minExpected varchar(64),
maxExpected varchar(64), 
deleted INT NULL DEFAULT 0,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.tag_vals(
id int(11) NOT NULL AUTO_INCREMENT,
dtime datetime,
name varchar(128),
val float,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.well_config(
id int(11) NOT NULL AUTO_INCREMENT,
tstamp datetime,
type varchar(64),
val varchar(64),
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.run_status(
id int(11) NOT NULL AUTO_INCREMENT,
dtime datetime,
status varchar(64),
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.alarm_classes(
id int(11) NOT NULL AUTO_INCREMENT,
alarm_class varchar(64),
description varchar(128),
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS poconsole.alarms(
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(64),
class int(11),
tag varchar(128),
cond varchar(64),
PRIMARY KEY (id)
);
INSERT INTO tag_classes (id, tag_class, description) VALUES (1, 'stroke', 'Stroke Information');
INSERT INTO tag_classes (id, tag_class, description) VALUES (2, 'history', 'Historical Data');
INSERT INTO tag_classes (id, tag_class, description) VALUES (3, 'gaugeoff', 'Gauge Off Data');
INSERT INTO tag_classes (id, tag_class, description) VALUES (4, 'welltest', 'Well Test Data');
INSERT INTO tag_classes (id, tag_class, description) VALUES (5, 'custom', 'Custom tags');
INSERT INTO alarm_classes(id, alarm_class, description) VALUES (1, 'analog', 'Analog Alarms');
INSERT INTO alarm_classes(id, alarm_class, description) VALUES (2, 'bit', 'Bit Statuses');
CREATE USER 'website'@'localhost' IDENTIFIED BY 'henrypump';
GRANT ALL ON *.* TO 'website'@'localhost';
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'henrypump';
GRANT ALL ON *.* to 'admin'@'localhost';
CREATE USER 'admin'@'%' IDENTIFIED BY 'henrypump';
GRANT ALL ON *.* to 'admin'@'%';
FLUSH PRIVILEGES;

View File

@@ -1,418 +0,0 @@
#!/usr/bin/env python
from datetime import datetime
import time
import mysql.connector as mysqlcon
from pycomm.ab_comm.clx import Driver as ClxDriver
from tag.tag_mysql import Tag
from tag.tag_mysql import AnalogAlarm
from tag.tag_mysql import bitAlarm
from readConfig import readConfig
import traceback
import pickle
import os
with open(os.path.realpath('.') + '/mysql_cfg.pickle', 'rb') as cfgFile:
mysql_cfg = pickle.load(cfgFile)
con = mysqlcon.connect(**mysql_cfg)
try:
configProperties = readConfig()
except:
traceback.print_exc()
def readTag(addr, tag):
time.sleep(0.01)
c = ClxDriver()
if c.open(addr):
try:
v = c.read_tag(tag)
# print(v)
return v
except Exception:
print("ERROR RETRIEVING TAG: {}".format(tag))
c.close()
print traceback.print_exc()
pass
c.close()
def readArray(addr, arr, length):
# logging.basicConfig(filename="clx.log", format="%(levelname)-10s %(asctime)s %(message)s", level=logging.DEBUG)
c = ClxDriver()
if c.open(addr):
try:
v = c.read_array(arr, length)
# print(v)
return map(lambda x: x[1], v)
except Exception:
print("ERROR RETRIEVING ARRAY: {}".format(arr))
err = c.get_status()
c.close()
print err
pass
c.close()
def checkDateInDB(da):
y = int(da[0:4])
m = int(da[4:6])
d = int(da[6:8])
dquery = "SELECT id FROM card_history_dates WHERE year = {0} AND month = {1} AND day = {2};".format(y, m, d)
# dquery = "SELECT id FROM WellData.card_history_dates WHERE year = 2016 AND month = 1 AND day = 5;"
con.connect()
cur = con.cursor()
cur.execute(dquery)
dates = cur.fetchall()
if len(dates) > 0:
print("Date {0} already in db".format(da))
else:
ins_query = "INSERT INTO card_history_dates (year, month, day, first_id) VALUES ({0}, {1}, {2}, (SELECT MAX(id) FROM card_history));".format(y, m, d)
print(ins_query)
con.connect()
cur = con.cursor()
cur.execute(ins_query)
con.commit()
class Status(Tag):
def sendToDB(self):
query = "INSERT INTO run_status (dtime, status) VALUES ({}, '{}')".format(time.time(), self.value)
print query
con.connect()
cur = con.cursor()
cur.execute(query)
con.commit()
self.last_send_time = time.time()
# ---------- MAP FUNCTIONS ---------- #
maps = {
'modeMap': {
0: "Error",
1: "Auto",
2: "POC",
3: "Timer",
4: "Manual",
5: "DH PID"
},
'card_type_map': {
0: "Normal",
1: "Shutdown",
2: "Alarm",
3: "Startup",
4: "Low Fillage"
},
'statusMap': {
0: 'Stopped',
1: 'Running',
2: 'Pumped Off',
3: 'Faulted',
4: 'Starting',
5: 'Recovering',
100: 'Read Error',
1000: 'PLC Error',
9999: 'No Response'
},
'conditionMap': {
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"
}
}
# ---------- TAGS ---------- #
stroke_tags = {} # Tags stored for every single stroke
history_tags = {} # Tags stored on value change or age
gaugeoff_tags = {} # Tags stored at gauge off
welltest_tags = {} # Tags stored at well test submit
bit_tags = {}
safety_tags = {}
custom_tags = {}
status = Status('run_status', 'Pump.Run_Status', 0, 'STRING', 0, 3600, mapFn=maps['statusMap'])
def setupTags():
con.connect()
cur = con.cursor()
query = "SELECT t.name as name, c.tag_class as class, t.tag as tag, t.data_type as data_type, t.change_threshold as change_threshold, t.guarantee_sec as guarantee_sec, t.id as id, t.map_function as map_function FROM tags t JOIN tag_classes c ON c.id = t.class;"
cur.execute(query)
tags = cur.fetchall()
# (u'downhole_gross_stroke', u'history', u'Card_Past[1].Downhole_GrossStroke', u'REAL', 2.0, 3600, 6, None)
# 0: name, 1: class, 2: tag, 3: data_type, 4: change_threshold, 5: guarantee_sec, 6: db id, 7: map_function
for x in tags:
print(x)
if str(x[1]) == 'stroke':
if x[7]:
stroke_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5], mapFn=maps[str(x[7])])
else:
stroke_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5])
elif str(x[1]) == 'history':
if x[7]:
history_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5], mapFn=maps[str(x[7])])
else:
history_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5])
elif str(x[1]) == 'gaugeoff':
if x[7]:
gaugeoff_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5], mapFn=maps[str(x[7])])
else:
gaugeoff_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5])
elif str(x[1]) == 'welltest':
if x[7]:
welltest_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5], mapFn=maps[str(x[7])])
else:
welltest_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5])
elif str(x[1]) == 'custom':
if x[7]:
custom_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5], mapFn=maps[str(x[7])])
else:
custom_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5])
con.connect()
cur = con.cursor()
query = "SELECT c.alarm_class as class, a.name as name, a.tag as tag, a.cond as cond, a.id as id FROM alarms a JOIN alarm_classes c ON a.class = c.id;"
cur.execute(query)
alarms = cur.fetchall()
for x in alarms:
# 0: class, 1: name, 2: tag, 3: condition
if str(x[0]) == 'analog':
safety_tags[x[1]] = AnalogAlarm(str(x[1]), str(x[2]), int(x[4]), device_type="CLX", ip_address=configProperties['PLC_IP_ADDRESS'])
elif str(x[0]) == 'bit':
bit_tags[x[1]] = bitAlarm(str(x[1]), str(x[2]), str(x[3]), int(x[4]), device_type="CLX", ip_address=configProperties['PLC_IP_ADDRESS'])
print('===== STROKE TAGS =====')
for t in stroke_tags:
print(t)
print('===== HISTORY TAGS =====')
for t in history_tags:
print(t)
print('===== WELLTEST TAGS =====')
for t in welltest_tags:
print(t)
print('===== GAUGEOFF TAGS =====')
for t in gaugeoff_tags:
print(t)
print('===== BIT SAFETIES =====')
for t in bit_tags:
print(t)
print('===== ANALOG SAFETIES =====')
for t in safety_tags:
print(t)
print('===== CUSTOM TAGS =====')
for t in custom_tags:
print(t)
setupTags()
def readPoints():
global configProperties
num_points = readTag(configProperties['PLC_IP_ADDRESS'], "Card_Past[1].Num_Points")[0]
surf_pos = readArray(configProperties['PLC_IP_ADDRESS'], "Card_Past[1].Surface_Position", num_points + 1)[1:]
surf_pos.append(surf_pos[0])
surf_lod = readArray(configProperties['PLC_IP_ADDRESS'], "Card_Past[1].Surface_Load", num_points + 1)[1:]
surf_lod.append(surf_lod[0])
down_pos = readArray(configProperties['PLC_IP_ADDRESS'], "Card_Past[1].Downhole_Position", num_points + 1)[1:]
down_pos.append(down_pos[0])
down_lod = readArray(configProperties['PLC_IP_ADDRESS'], "Card_Past[1].Downhole_Load", num_points + 1)[1:]
down_lod.append(down_lod[0])
return([surf_pos, surf_lod, down_pos, down_lod])
def evalTapers():
global configProperties
ts = time.time()
numTapers = int(readTag(configProperties['PLC_IP_ADDRESS'], 'Card_Current.Params.Num_Tapers')[0])
for t in range(1, numTapers + 1):
taper_length = readTag(configProperties['PLC_IP_ADDRESS'], 'Taper.Taper[{}].Setup.Length'.format(t))[0]
taper_diameter = readTag(configProperties['PLC_IP_ADDRESS'], 'Taper.Taper[{}].Setup.Diameter'.format(t))[0]
taper_material = readTag(configProperties['PLC_IP_ADDRESS'], 'Taper.Taper[{}].Setup.Material'.format(t))[0]
if (taper_material == 1):
taper_material = "Steel"
elif (taper_material == 2):
taper_material = "Fiberglass"
tStr = "{{'taper':{}, 'length': {}, 'diameter': {}, 'material':'{}'}}".format(t, taper_length, taper_diameter, taper_material)
tQuery = 'INSERT INTO well_config (tstamp, type, val) VALUES ({}, "taper", "{}")'.format(ts, tStr)
print tQuery
con.connect()
cur = con.cursor()
cur.execute(tQuery)
con.commit()
pump_diameter = readTag(configProperties['PLC_IP_ADDRESS'], 'UnitConfig.Pump_Diameter')[0]
cfgQuery = "INSERT INTO well_config (tstamp, type, val) VALUES ({}, 'pump_diameter', '{}')".format(ts, pump_diameter)
con.connect()
cur = con.cursor()
cur.execute(cfgQuery)
con.commit()
print "TAPER DATA READ!"
return True
def main():
global configProperties
read_tapers = False
already_gauged_off = False
already_entered_well_test = False
last_date = ""
last_stroke = 0
last_status = ""
statusChanged = False
while True:
try:
current_status = status.read("test")
statusChanged = not (current_status == last_status)
if statusChanged:
last_status = current_status
#############
# CARD DATA #
#############
stroke_tags['card_id'].read('test')
if not (last_stroke == stroke_tags['card_id'].value):
sData = {}
last_stroke = stroke_tags['card_id'].value
stroke_time = time.time()
dt = datetime.fromtimestamp(stroke_time)
sData['localtime'] = dt
sData['stroke_time'] = dt
sData['utctime'] = datetime.utcfromtimestamp(stroke_time)
for t in stroke_tags:
if not t == "card_id":
stroke_tags[t].read(True)
[sData['Surface_Position'], sData['Surface_Load'], sData['Downhole_Position'], sData['Downhole_Load']] = readPoints()
# st = datetime.strftime(dt, "%Y%m%d_%H%M%S")
date = datetime.strftime(dt, "%Y%m%d")
if not date == last_date:
checkDateInDB(date)
last_date = date
sData["card_type"] = stroke_tags['card_type'].value
sData["card_id"] = stroke_tags['card_id'].value
sData['sp_string'] = ', '.join(map(str, sData['Surface_Position']))
sData['sl_string'] = ', '.join(map(str, sData['Surface_Load']))
sData['dp_string'] = ', '.join(map(str, sData['Downhole_Position']))
sData['dl_string'] = ', '.join(map(str, sData['Downhole_Load']))
insert_query = "INSERT INTO card_history (Card_ID, Card_Type, Stroke_Time, Surface_Position, Surface_Load, Downhole_Position, Downhole_Load) VALUES (:card_id, :card_type, :stroke_time, :sp_string, :sl_string, :dp_string, :dl_string)"
con.connect()
cur = con.cursor()
cur.execute(insert_query, sData)
con.commit()
print "CARD NUMBER " + str(sData["card_id"]) + " READ!"
###################
# HISTORICAL DATA #
###################
for hist in history_tags:
h = history_tags[hist]
h.read("test")
for cust in custom_tags:
t = custom_tags[cust]
t.read("test")
##############
# TAPER DATA #
##############
update_taper = readTag(configProperties['PLC_IP_ADDRESS'], "Write_Tapers")[0] > 0
if (update_taper == 0):
if read_tapers:
read_tapers = False
print "Update Tapers = False"
if (update_taper and (not read_tapers)):
print "reading taper file"
read_tapers = evalTapers()
##################
# GAUGE OFF DATA #
##################
gauge_off = readTag(configProperties['PLC_IP_ADDRESS'], "Gauge_Off_Command")[0]
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..."
for goff in gaugeoff_tags:
g = gaugeoff_tags[goff]
g.read(True)
gauge_date = datetime(year=gaugeoff_tags['year'].value, month=gaugeoff_tags['month'].value, day=gaugeoff_tags['day'].value, hour=gaugeoff_tags['hour'].value, minute=gaugeoff_tags['min'].value, second=gaugeoff_tags['sec'].value)
con.connect()
cur = con.cursor()
con.execute("""INSERT INTO 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, gaugeoff_tags['percent_run'].value, gaugeoff_tags['kwh'].value, gaugeoff_tags['electricity_cost'].value, gaugeoff_tags['max_load'].value, gaugeoff_tags['min_load'].value, gaugeoff_tags['average_spm'].value, gaugeoff_tags['production_calculated'].value, gaugeoff_tags['full_card_production'].value, gaugeoff_tags['polished_rod_hp'].value, gaugeoff_tags['lifting_cost'].value, gaugeoff_tags['fluid_level'].value, gaugeoff_tags['pump_intake_pressure'].value, gaugeoff_tags['kwh_regen'].value, gaugeoff_tags['inflow_rate'].value))
con.commit()
already_gauged_off = True
print "Gauged off!"
##################
# WELL TEST DATA #
##################
well_test_entered = readTag(configProperties['PLC_IP_ADDRESS'], "Well_Test.Test_Submit")[0] > 0
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)):
for wtest in welltest_tags:
w = welltest_tags[wtest]
w.read(True)
print "Well Test Entered"
print('{}/{}/{} {}:{}:{}'.format(welltest_tags['year'].value, welltest_tags['month'].value, welltest_tags['day'].value, welltest_tags['hour'].value, welltest_tags['min'].value, welltest_tags['sec'].value))
test_date = datetime(year=welltest_tags['year'].value, month=welltest_tags['month'].value, day=welltest_tags['day'].value, hour=welltest_tags['hour'].value, minute=welltest_tags['min'].value, second=welltest_tags['sec'].value)
con.connect()
cur = con.cursor()
test_query = "INSERT INTO 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, welltest_tags['v_oil'].value, welltest_tags['v_water'].value, welltest_tags['v_gas'].value, welltest_tags['k_factor'].value, welltest_tags['p_v_oil'].value, welltest_tags['p_v_water'].value, welltest_tags['api_oil'].value, welltest_tags['sg_water'].value, welltest_tags['test_duration'].value)
# print test_query
con.execute(test_query)
con.commit()
already_entered_well_test = True
print "Well Test Stored!"
###################
# ALARMS & EVENTS #
###################
for t in safety_tags:
safety_tags[t].checkStatus(stroke_tags['card_id'].value)
for b in bit_tags:
bit_tags[b].checkStatus(stroke_tags['card_id'].value)
time.sleep(.20)
except Exception, e:
print("Error during loop: {}".format(e))
traceback.print_exc()
if __name__ == '__main__':
main()

View File

@@ -1,18 +0,0 @@
(dp0
S'host'
p1
S'127.0.0.1'
p2
sS'password'
p3
S'henrypump'
p4
sS'user'
p5
S'website'
p6
sS'database'
p7
S'poconsole'
p8
s.

View File

@@ -1,57 +0,0 @@
import mysql.connector as mysqlcon
import pickle
import os
with open(os.path.realpath('.') + '/mysql_cfg.pickle', 'rb') as cfgFile:
mysql_cfg = pickle.load(cfgFile)
con = mysqlcon.connect(**mysql_cfg)
def readConfig():
configProperties = {}
configObj = {}
con.connect()
cur = con.cursor()
query = "SELECT parameter, val FROM config GROUP BY parameter;"
cur.execute(query)
config = cur.fetchall()
for x in config:
configObj[x[0]] = x[1]
try:
configProperties['PLC_IP_ADDRESS'] = str(configObj['ip_address'])
print("FYI, using PLC IP Address from the database {0}".format(configProperties['PLC_IP_ADDRESS']))
except KeyError:
print("FYI, there is no PLC IP Address stored in the database, defaulting to 192.168.1.10")
configProperties['PLC_IP_ADDRESS'] = "192.168.1.10"
try:
configProperties['plc_type'] = str(configObj['plc_type'])
print("FYI, using PLC Type from the database {0}".format(configProperties['plc_type']))
except KeyError:
print("FYI, there is no PLC Type stored in the database, defaulting to CLX")
configProperties['plc_type'] = "CLX"
try:
configProperties['scan_rate'] = int(configObj['scan_rate'])
print("FYI, using Scan Rate from the database {0}".format(configProperties['scan_rate']))
except KeyError:
print("FYI, there is no Scan Rate stored in the database, defaulting to 10 seconds")
configProperties['scan_rate'] = 10
try:
sa_test = str(configObj['save_all'])
if sa_test.lower() == "true":
configProperties['save_all'] = True
elif sa_test.lower() == "false":
configProperties['save_all'] = False
else:
configProperties['save_all'] = "test"
print("FYI, value for save_all is {0}".format(configProperties['save_all']))
except KeyError:
print("FYI, there is no save_all value stored in the database, using 'test'")
configProperties['save_all'] = 'test'
return configProperties

View File

@@ -1,176 +0,0 @@
CREATE TABLE IF NOT EXISTS Event_List (
id INTEGER PRIMARY KEY,
alarmID INTEGER,
type TEXT,
cond TEXT,
value REAL,
datetime TIMESTAMP,
stroke_number INTEGER
);
CREATE TABLE IF NOT EXISTS Hist_Day (
id INTEGER PRIMARY KEY,
gauge_date TIMESTAMP,
percent_run REAL,
kWh REAL,
kWh_regen REAL,
electricity_cost REAL,
peak_load REAL,
min_load REAL,
average_SPM REAL,
production_calculated REAL,
full_card_production REAL,
polished_rod_HP REAL,
lifting_cost REAL,
fluid_above_pump REAL,
pump_intake_pressure REAL,
inflow_rate REAL
);
CREATE TABLE IF NOT EXISTS Well_Test (
id INTEGER PRIMARY KEY,
test_date TIMESTAMP,
test_volume_oil REAL,
test_volume_water REAL,
test_volume_gas REAL,
k_factor REAL,
projected_volume_oil REAL,
projected_volume_water REAL,
api_gravity_oil REAL,
sg_oil REAL,
sg_water REAL,
test_hours REAL,
deleted INTEGER DEFAULT 0
);
-- CREATE TABLE IF NOT EXISTS config (
-- id INTEGER PRIMARY KEY,
-- device_type TEXT,
-- ip_address TEXT,
-- dateChanged TIMESTAMP DEFAULT CURRENT_TIMESTAMP
-- );
CREATE TABLE IF NOT EXISTS config (
id INTEGER PRIMARY KEY,
parameter TEXT,
val TEXT,
dateAdded TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS Notes (
id INTEGER PRIMARY KEY,
author TEXT,
note TEXT,
datetime TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
type INTEGER,
associated_stroke INTEGER,
deleted INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS note_types(
id INTEGER PRIMARY KEY,
type TEXT,
deleted INTEGER DEFAULT 0
);
INSERT INTO note_types (id, type) VALUES ('1', 'Downtime Explanation');
INSERT INTO note_types (id, type) VALUES ('2', 'Configuration Change');
INSERT INTO note_types (id, type) VALUES ('3', 'Info');
INSERT INTO note_types (id, type) VALUES ('4', 'Other');
CREATE TABLE IF NOT EXISTS fluid_shot(
id INTEGER PRIMARY KEY,
shot_datetime TIMESTAMP,
taken_by TEXT,
pump_intake_pressure REAL,
fluid_gradient REAL,
friction REAL,
deleted INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS card_history(
id INTEGER PRIMARY KEY,
Stroke_Time TIMESTAMP,
Card_ID INTEGER,
Card_Type TEXT,
Surface_Position BLOB,
Surface_Load BLOB,
Downhole_Position BLOB,
Downhole_Load BLOB
);
CREATE TABLE IF NOT EXISTS card_history_dates(
id INTEGER PRIMARY KEY,
year INTEGER,
month INTEGER,
day INTEGER,
first_id INTEGER
);
CREATE TABLE IF NOT EXISTS tag_classes(
id INTEGER PRIMARY KEY,
tag_class TEXT,
description TEXT
);
CREATE TABLE IF NOT EXISTS tags (
id INTEGER PRIMARY KEY,
name TEXT,
class TEXT,
tag TEXT,
description TEXT,
data_type TEXT,
change_threshold REAL,
guarantee_sec INTEGER,
map_function TEXT,
units TEXT,
minExpected REAL,
maxExpected REAL
dateAdded TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
deleted INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS tag_vals (
id INTEGER PRIMARY KEY,
tagID INTEGER,
val REAL,
dtime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS well_config(
id INTEGER PRIMARY KEY,
tstamp TIMESTAMP,
type TEXT,
val TEXT
);
CREATE TABLE IF NOT EXISTS run_status(
id INTEGER PRIMARY KEY,
dtime TIMESTAMP,
status TEXT
);
CREATE TABLE IF NOT EXISTS alarm_classes(
id INTEGER PRIMARY KEY,
alarm_class INTEGER,
description TEXT
);
CREATE TABLE IF NOT EXISTS alarms(
id INTEGER PRIMARY KEY,
name TEXT,
class INTEGER,
tag TEXT,
cond TEXT
);
INSERT INTO tag_classes (id, tag_class, description) VALUES (1, 'stroke', 'Stroke Information');
INSERT INTO tag_classes (id, tag_class, description) VALUES (2, 'history', 'Historical Data');
INSERT INTO tag_classes (id, tag_class, description) VALUES (3, 'gaugeoff', 'Gauge Off Data');
INSERT INTO tag_classes (id, tag_class, description) VALUES (4, 'welltest', 'Well Test Data');
INSERT INTO tag_classes (id, tag_class, description) VALUES (5, 'custom', 'Custom tags');
INSERT INTO alarm_classes(id, alarm_class, description) VALUES (1, 'analog', 'Analog Alarms');
INSERT INTO alarm_classes(id, alarm_class, description) VALUES (2, 'bit', 'Bit Statuses');

View File

@@ -1,410 +0,0 @@
#!/usr/bin/env python
from datetime import datetime
import time
import sqlite3 as lite
from pycomm.ab_comm.clx import Driver as ClxDriver
from tag.tag_sqlite import Tag
from tag.tag_sqlite import AnalogAlarm
from tag.tag_sqlite import bitAlarm
from readConfig import readConfig
import traceback
con = lite.connect("/mnt/usb/data.db")
try:
configProperties = readConfig()
except:
traceback.print_exc()
def readTag(addr, tag):
time.sleep(0.01)
c = ClxDriver()
if c.open(addr):
try:
v = c.read_tag(tag)
# print(v)
return v
except Exception:
print("ERROR RETRIEVING TAG: {}".format(tag))
c.close()
print traceback.print_exc()
pass
c.close()
def readArray(addr, arr, length):
# logging.basicConfig(filename="clx.log", format="%(levelname)-10s %(asctime)s %(message)s", level=logging.DEBUG)
c = ClxDriver()
if c.open(addr):
try:
v = c.read_array(arr, length)
# print(v)
return map(lambda x: x[1], v)
except Exception:
print("ERROR RETRIEVING ARRAY: {}".format(arr))
err = c.get_status()
c.close()
print err
pass
c.close()
def checkDateInDB(da):
y = int(da[0:4])
m = int(da[4:6])
d = int(da[6:8])
dquery = "SELECT id FROM card_history_dates WHERE year = {0} AND month = {1} AND day = {2};".format(y, m, d)
# dquery = "SELECT id FROM WellData.card_history_dates WHERE year = 2016 AND month = 1 AND day = 5;"
with con:
cur = con.cursor()
cur.execute(dquery)
dates = cur.fetchall()
if len(dates) > 0:
print("Date {0} already in db".format(da))
else:
ins_query = "INSERT INTO card_history_dates (year, month, day, first_id) VALUES ({0}, {1}, {2}, (SELECT MAX(id) FROM card_history));".format(y, m, d)
print(ins_query)
with con:
cur = con.cursor()
cur.execute(ins_query)
con.commit()
class Status(Tag):
def sendToDB(self):
query = "INSERT INTO run_status (dtime, status) VALUES ({}, '{}')".format(time.time(), self.value)
print query
with con:
cur = con.cursor()
cur.execute(query)
con.commit()
self.last_send_time = time.time()
# ---------- MAP FUNCTIONS ---------- #
maps = {
'modeMap': {
0: "Error",
1: "Auto",
2: "POC",
3: "Timer",
4: "Manual",
5: "DH PID"
},
'card_type_map': {
0: "Normal",
1: "Shutdown",
2: "Alarm",
3: "Startup",
4: "Low Fillage"
},
'statusMap': {
0: 'Stopped',
1: 'Running',
2: 'Pumped Off',
3: 'Faulted',
4: 'Starting',
5: 'Recovering',
100: 'Read Error',
1000: 'PLC Error',
9999: 'No Response'
},
'conditionMap': {
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"
}
}
# ---------- TAGS ---------- #
stroke_tags = {} # Tags stored for every single stroke
history_tags = {} # Tags stored on value change or age
gaugeoff_tags = {} # Tags stored at gauge off
welltest_tags = {} # Tags stored at well test submit
bit_tags = {}
safety_tags = {}
custom_tags = {}
status = Status('run_status', 'Pump.Run_Status', 0, 'STRING', 0, 3600, mapFn=maps['statusMap'])
def setupTags():
with con:
cur = con.cursor()
query = "SELECT t.name as name, c.tag_class as class, t.tag as tag, t.data_type as data_type, t.change_threshold as change_threshold, t.guarantee_sec as guarantee_sec, t.id as id, t.map_function as map_function FROM tags t JOIN tag_classes c ON c.id = t.class;"
cur.execute(query)
tags = cur.fetchall()
# (u'downhole_gross_stroke', u'history', u'Card_Past[1].Downhole_GrossStroke', u'REAL', 2.0, 3600, 6, None)
# 0: name, 1: class, 2: tag, 3: data_type, 4: change_threshold, 5: guarantee_sec, 6: db id, 7: map_function
for x in tags:
print(x)
if str(x[1]) == 'stroke':
if x[7]:
stroke_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5], mapFn=maps[str(x[7])])
else:
stroke_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5])
elif str(x[1]) == 'history':
if x[7]:
history_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5], mapFn=maps[str(x[7])])
else:
history_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5])
elif str(x[1]) == 'gaugeoff':
if x[7]:
gaugeoff_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5], mapFn=maps[str(x[7])])
else:
gaugeoff_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5])
elif str(x[1]) == 'welltest':
if x[7]:
welltest_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5], mapFn=maps[str(x[7])])
else:
welltest_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5])
elif str(x[1]) == 'custom':
if x[7]:
custom_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5], mapFn=maps[str(x[7])])
else:
custom_tags[x[0]] = Tag(str(x[0]), str(x[2]), x[6], str(x[3]), x[4], x[5])
with con:
cur = con.cursor()
query = "SELECT c.alarm_class as class, a.name as name, a.tag as tag, a.cond as condition, a.id as id FROM alarms a JOIN alarm_classes c ON a.class = c.id;"
cur.execute(query)
alarms = cur.fetchall()
for x in alarms:
# 0: class, 1: name, 2: tag, 3: condition
if str(x[0]) == 'analog':
safety_tags[x[1]] = AnalogAlarm(str(x[1]), str(x[2]), int(x[4]), device_type="CLX", ip_address=configProperties['PLC_IP_ADDRESS'])
elif str(x[0]) == 'bit':
bit_tags[x[1]] = bitAlarm(str(x[1]), str(x[2]), str(x[3]), int(x[4]), device_type="CLX", ip_address=configProperties['PLC_IP_ADDRESS'])
print('===== STROKE TAGS =====')
for t in stroke_tags:
print(t)
print('===== HISTORY TAGS =====')
for t in history_tags:
print(t)
print('===== WELLTEST TAGS =====')
for t in welltest_tags:
print(t)
print('===== GAUGEOFF TAGS =====')
for t in gaugeoff_tags:
print(t)
print('===== BIT SAFETIES =====')
for t in bit_tags:
print(t)
print('===== ANALOG SAFETIES =====')
for t in safety_tags:
print(t)
print('===== CUSTOM TAGS =====')
for t in custom_tags:
print(t)
setupTags()
def readPoints():
global configProperties
num_points = readTag(configProperties['PLC_IP_ADDRESS'], "Card_Past[1].Num_Points")[0]
surf_pos = readArray(configProperties['PLC_IP_ADDRESS'], "Card_Past[1].Surface_Position", num_points + 1)[1:]
surf_pos.append(surf_pos[0])
surf_lod = readArray(configProperties['PLC_IP_ADDRESS'], "Card_Past[1].Surface_Load", num_points + 1)[1:]
surf_lod.append(surf_lod[0])
down_pos = readArray(configProperties['PLC_IP_ADDRESS'], "Card_Past[1].Downhole_Position", num_points + 1)[1:]
down_pos.append(down_pos[0])
down_lod = readArray(configProperties['PLC_IP_ADDRESS'], "Card_Past[1].Downhole_Load", num_points + 1)[1:]
down_lod.append(down_lod[0])
return([surf_pos, surf_lod, down_pos, down_lod])
def evalTapers():
global configProperties
ts = time.time()
numTapers = int(readTag(configProperties['PLC_IP_ADDRESS'], 'Card_Current.Params.Num_Tapers')[0])
for t in range(1, numTapers + 1):
taper_length = readTag(configProperties['PLC_IP_ADDRESS'], 'Taper.Taper[{}].Setup.Length'.format(t))[0]
taper_diameter = readTag(configProperties['PLC_IP_ADDRESS'], 'Taper.Taper[{}].Setup.Diameter'.format(t))[0]
taper_material = readTag(configProperties['PLC_IP_ADDRESS'], 'Taper.Taper[{}].Setup.Material'.format(t))[0]
if (taper_material == 1):
taper_material = "Steel"
elif (taper_material == 2):
taper_material = "Fiberglass"
tStr = "{{'taper':{}, 'length': {}, 'diameter': {}, 'material':'{}'}}".format(t, taper_length, taper_diameter, taper_material)
tQuery = 'INSERT INTO well_config (tstamp, type, val) VALUES ({}, "taper", "{}")'.format(ts, tStr)
print tQuery
with con:
cur = con.cursor()
cur.execute(tQuery)
con.commit()
pump_diameter = readTag(configProperties['PLC_IP_ADDRESS'], 'UnitConfig.Pump_Diameter')[0]
cfgQuery = "INSERT INTO well_config (tstamp, type, val) VALUES ({}, 'pump_diameter', '{}')".format(ts, pump_diameter)
with con:
cur = con.cursor()
cur.execute(cfgQuery)
con.commit()
print "TAPER DATA READ!"
return True
def main():
global configProperties
read_tapers = False
already_gauged_off = False
already_entered_well_test = False
last_date = ""
last_stroke = 0
last_status = ""
statusChanged = False
while True:
try:
current_status = status.read("test")
statusChanged = not (current_status == last_status)
if statusChanged:
last_status = current_status
#############
# CARD DATA #
#############
# EOS = readTag(configProperties['PLC_IP_ADDRESS'], "End_Of_Stroke")[0]
stroke_tags['card_id'].read('test')
if not (last_stroke == stroke_tags['card_id'].value):
sData = {}
last_stroke = stroke_tags['card_id'].value
stroke_time = time.time()
dt = datetime.fromtimestamp(stroke_time)
sData['localtime'] = dt
sData['stroke_time'] = dt
sData['utctime'] = datetime.utcfromtimestamp(stroke_time)
for t in stroke_tags:
if not t == "card_id":
stroke_tags[t].read(True)
[sData['Surface_Position'], sData['Surface_Load'], sData['Downhole_Position'], sData['Downhole_Load']] = readPoints()
# st = datetime.strftime(dt, "%Y%m%d_%H%M%S")
date = datetime.strftime(dt, "%Y%m%d")
if not date == last_date:
checkDateInDB(date)
last_date = date
sData["card_type"] = stroke_tags['card_type'].value
sData["card_id"] = stroke_tags['card_id'].value
sData['sp_string'] = ', '.join(map(str, sData['Surface_Position']))
sData['sl_string'] = ', '.join(map(str, sData['Surface_Load']))
sData['dp_string'] = ', '.join(map(str, sData['Downhole_Position']))
sData['dl_string'] = ', '.join(map(str, sData['Downhole_Load']))
insert_query = "INSERT INTO card_history (Card_ID, Card_Type, Stroke_Time, Surface_Position, Surface_Load, Downhole_Position, Downhole_Load) VALUES (:card_id, :card_type, :stroke_time, :sp_string, :sl_string, :dp_string, :dl_string)"
with con:
cur = con.cursor()
cur.execute(insert_query, sData)
con.commit()
print "CARD NUMBER " + str(sData["card_id"]) + " READ!"
###################
# HISTORICAL DATA #
###################
for hist in history_tags:
h = history_tags[hist]
h.read("test")
for cust in custom_tags:
t = custom_tags[cust]
t.read("test")
##############
# TAPER DATA #
##############
update_taper = readTag(configProperties['PLC_IP_ADDRESS'], "Write_Tapers")[0] > 0
if (update_taper == 0):
if read_tapers:
read_tapers = False
print "Update Tapers = False"
if (update_taper and (not read_tapers)):
print "reading taper file"
read_tapers = evalTapers()
##################
# GAUGE OFF DATA #
##################
gauge_off = readTag(configProperties['PLC_IP_ADDRESS'], "Gauge_Off_Command")[0]
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..."
for goff in gaugeoff_tags:
g = gaugeoff_tags[goff]
g.read(True)
gauge_date = datetime(year=gaugeoff_tags['year'].value, month=gaugeoff_tags['month'].value, day=gaugeoff_tags['day'].value, hour=gaugeoff_tags['hour'].value, minute=gaugeoff_tags['min'].value, second=gaugeoff_tags['sec'].value)
with con:
cur = con.cursor()
con.execute("""INSERT INTO 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, gaugeoff_tags['percent_run'].value, gaugeoff_tags['kwh'].value, gaugeoff_tags['electricity_cost'].value, gaugeoff_tags['max_load'].value, gaugeoff_tags['min_load'].value, gaugeoff_tags['average_spm'].value, gaugeoff_tags['production_calculated'].value, gaugeoff_tags['full_card_production'].value, gaugeoff_tags['polished_rod_hp'].value, gaugeoff_tags['lifting_cost'].value, gaugeoff_tags['fluid_level'].value, gaugeoff_tags['pump_intake_pressure'].value, gaugeoff_tags['kwh_regen'].value, gaugeoff_tags['inflow_rate'].value))
con.commit()
already_gauged_off = True
print "Gauged off!"
##################
# WELL TEST DATA #
##################
well_test_entered = readTag(configProperties['PLC_IP_ADDRESS'], "Well_Test.Test_Submit")[0] > 0
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)):
for wtest in welltest_tags:
w = welltest_tags[wtest]
w.read(True)
print "Well Test Entered"
print('{}/{}/{} {}:{}:{}'.format(welltest_tags['year'].value, welltest_tags['month'].value, welltest_tags['day'].value, welltest_tags['hour'].value, welltest_tags['min'].value, welltest_tags['sec'].value))
test_date = datetime(year=welltest_tags['year'].value, month=welltest_tags['month'].value, day=welltest_tags['day'].value, hour=welltest_tags['hour'].value, minute=welltest_tags['min'].value, second=welltest_tags['sec'].value)
with con:
cur = con.cursor()
test_query = "INSERT INTO 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, welltest_tags['v_oil'].value, welltest_tags['v_water'].value, welltest_tags['v_gas'].value, welltest_tags['k_factor'].value, welltest_tags['p_v_oil'].value, welltest_tags['p_v_water'].value, welltest_tags['api_oil'].value, welltest_tags['sg_water'].value, welltest_tags['test_duration'].value)
# print test_query
con.execute(test_query)
con.commit()
already_entered_well_test = True
print "Well Test Stored!"
###################
# ALARMS & EVENTS #
###################
for t in safety_tags:
safety_tags[t].checkStatus(stroke_tags['card_id'].value)
for b in bit_tags:
bit_tags[b].checkStatus(stroke_tags['card_id'].value)
time.sleep(.20)
except Exception, e:
print("Error during loop: {}".format(e))
traceback.print_exc()
if __name__ == '__main__':
main()

View File

@@ -1,52 +0,0 @@
import sqlite3 as lite
con = lite.connect("/mnt/usb/data.db")
def readConfig():
configProperties = {}
configObj = {}
with con:
cur = con.cursor()
query = "SELECT parameter, val FROM config GROUP BY parameter;"
cur.execute(query)
config = cur.fetchall()
for x in config:
configObj[x[0]] = x[1]
try:
configProperties['PLC_IP_ADDRESS'] = str(configObj['ip_address'])
print("FYI, using PLC IP Address from the database {0}".format(configProperties['PLC_IP_ADDRESS']))
except KeyError:
print("FYI, there is no PLC IP Address stored in the database, defaulting to 192.168.1.10")
configProperties['PLC_IP_ADDRESS'] = "192.168.1.10"
try:
configProperties['plc_type'] = str(configObj['plc_type'])
print("FYI, using PLC Type from the database {0}".format(configProperties['plc_type']))
except KeyError:
print("FYI, there is no PLC Type stored in the database, defaulting to CLX")
configProperties['plc_type'] = "CLX"
try:
configProperties['scan_rate'] = int(configObj['scan_rate'])
print("FYI, using Scan Rate from the database {0}".format(configProperties['scan_rate']))
except KeyError:
print("FYI, there is no Scan Rate stored in the database, defaulting to 10 seconds")
configProperties['scan_rate'] = 10
try:
sa_test = str(configObj['save_all'])
if sa_test.lower() == "true":
configProperties['save_all'] = True
elif sa_test.lower() == "false":
configProperties['save_all'] = False
else:
configProperties['save_all'] = "test"
print("FYI, value for save_all is {0}".format(configProperties['save_all']))
except KeyError:
print("FYI, there is no save_all value stored in the database, using 'test'")
configProperties['save_all'] = 'test'
return configProperties

View File

@@ -1,73 +0,0 @@
from pycomm.ab_comm.clx import Driver as ClxDriver
import traceback
import math
from readConfig import readConfig
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"}
]
retry_attempts = 0
retries_allowed = 10
def readTag(addr, tag):
# logging.basicConfig(
# filename="clx.log",
# format="%(levelname)-10s %(asctime)s %(message)s",
# level=logging.DEBUG
# )
c = ClxDriver()
if c.open(addr):
try:
v = c.read_tag(tag)
# print(v)
return v
except Exception:
err = c.get_status()
c.close()
# print err
# pass
c.close()
def main():
global today_tags, retry_attempts, retries_allowed
try:
configProperties = readConfig()
outList = []
for tag in today_tags:
val = readTag(configProperties['PLC_IP_ADDRESS'], tag['tag'])[0]
if not math.isnan(val):
outList.append({'name':tag['name'], 'value':val})
print outList
return outList
except Exception, e:
# print("FATAL ERROR: Communication Error connecting to the PLC... ", e)
# traceback.print_exc()
retry_attempts = retry_attempts + 1
if retry_attempts < retries_allowed:
main()
else:
print {'status':'error', 'message':'{}'.format(e)}
return {'status':'error', 'message':'{}'.format(e)}
if __name__ == '__main__':
main()

37
init/loggers Normal file
View File

@@ -0,0 +1,37 @@
#! /bin/sh
# /etc/init.d/loggers
### BEGIN INIT INFO
# Provides: loggers
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Simple script to start a program at boot
# Description: A simple script from www.stuffaboutcode.com which will start / stop a program a boot / shutdown.
### END INIT INFO
# If you want a command to always run, put it here
# Carry out specific functions when asked to by the system
case "$1" in
start)
echo "Starting loggers"
kill -9 $(cat /root/dataLogger.pid)
# run application you want to start
/usr/bin/python /root/datalogger/dataLogger.py > /dev/null 2>&1 & echo $! > "/root/dataLogger.pid"
;;
stop)
echo "Stopping loggers"
# kill application you want to stop
kill -9 $(cat /root/dataLogger.pid)
;;
*)
echo "Usage: /etc/init.d/loggers {start|stop}"
exit 1
;;
esac
exit 0

View File

@@ -1,34 +0,0 @@
#!/usr/bin/env python
import sys
from pycomm.ab_comm.clx import Driver as ClxDriver
from readConfigimport readConfig
configProperties = readConfig()
def main(tagName):
global configProperties
c = ClxDriver()
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(configProperties['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

View File

@@ -1,70 +0,0 @@
#!/usr/bin/env python
import csv
from datetime import datetime
import os
import sys
from random import randint
from time import sleep
from readConfig import readConfig
from pycomm.ab_comm.clx import Driver as ClxDriver
def readTag(addr, tag):
time.sleep(0.01)
c = ClxDriver()
if c.open(addr):
try:
v = c.read_tag(tag)
# print(v)
return v
except Exception:
print("ERROR RETRIEVING TAG: {}".format(tag))
c.close()
print traceback.print_exc()
pass
c.close()
def writeTag(addr, tag, val, dtype):
time.sleep(0.01)
c = ClxDriver()
if c.open(addr):
try:
v = c.write_tag(tag, val, dtype)
# print(v)
return v
except Exception:
print("ERROR WRITING TAG: {}".format(tag))
c.close()
print traceback.print_exc()
pass
c.close()
def main(fullfilepath):
configProperties = readConfig()
errors = []
with open(fullfilepath, 'rb') as myfile:
wr = csv.reader(myfile)
for row in wr:
if len(row) == 3:
(tag, value, tagType) = row
writeTag(configProperties['PLC_IP_ADDRESS'], tag, value, tagType)
actual = readTag(configProperties['PLC_IP_ADDRESS'], tag)
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,")")
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])

View File

@@ -1,6 +0,0 @@
echo "Setting database type to MySQL"
cp dbMySQL/dataLogger_MySQL.py dataLogger.py
cp dbMySQL/readConfig_MySQL.py readConfig.py
cp dbMySQL/mysql_cfg.pickle mysql_cfg.pickle
echo "Done!"

View File

@@ -1,5 +0,0 @@
echo "Setting database type to MySQL"
cp dbSQLite/dataLogger_SQLite.py dataLogger.py
cp dbSQLite/readConfig_SQLite.py readConfig.py
echo "Done!"

3
start.sh Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
python /root/datalogger/dataLogger.py

1
tag

Submodule tag deleted from 10c044e3d2

View File

@@ -1,92 +0,0 @@
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec, map_function) VALUES ('card_type', 1, 'Card_Past[1].Card_Type', 'STRING', 0, 3600, 'card_type_map');
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('card_id', 1, 'Card_Past[1].ID', 'DINT', 0.5, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('polished_rod_hp', 2, 'Card_Past[1].Polished_Rod_HP', 'REAL', 1.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('drive_torque_mode', 2, 'DriveTorqueMode', 'BOOL', 1.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('downhole_max_load', 2, 'Card_Past[1].Downhole_Max_Load.Load', 'REAL', 400.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('downhole_gross_stroke', 2, 'Card_Past[1].Downhole_GrossStroke', 'REAL', 2.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('spm', 2, 'Card_Past[1].SPM', 'REAL', 0.5, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('fluid_gradient', 2, 'Card_Past[1].Params.Fluid_Gradient', 'REAL', 0.002, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('tubing_head_pressure', 2, 'Card_Past[1].Params.Tubing_Head_Pressure', 'REAL', 25.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('surface_min_load', 2, 'Card_Past[1].Surface_Min.Load', 'REAL', 400.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('downhole_fluid_load', 2, 'Card_Past[1].Downhole_FluidLoad', 'REAL', 400.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('downhole_max_position', 2, 'Card_Past[1].Downhole_Max_Position.Position', 'REAL', 2.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('downhole_net_stroke', 2, 'Card_Past[1].Downhole_NetStroke', 'REAL', 2.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('fillage_percent', 2, 'Card_Past[1].Fillage_Percent', 'REAL', 5.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('pump_hp', 2, 'Card_Past[1].Pump_HP', 'REAL', 1.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('surface_min_position', 2, 'Card_Past[1].Surface_Min.Position', 'REAL', 1.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('pump_intake_pressure', 2, 'Card_Past[1].Pump_Intake_Pressure', 'REAL', 200.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('surface_max_position', 2, 'Card_Past[1].Surface_Max.Position', 'REAL', 1.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('tubing_movement', 2, 'Card_Past[1].Tubing_Movement', 'REAL', 1.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('speed_reference', 2, 'Pump_PF755.PSet_SpeedRef', 'REAL', 10.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('downhole_min_position', 2, 'Card_Past[1].Downhole_Min_Position.Position', 'REAL', 2.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('surface_max_load', 2, 'Card_Past[1].Surface_Max.Load', 'REAL', 400.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('stuffing_box_friction', 2, 'Card_Past[1].Params.Stuffing_Box_Friction', 'REAL', 1.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('dt', 2, 'Card_Past[1].Params.dt', 'REAL', 0.001, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('downhole_min_load', 2, 'Card_Past[1].Downhole_Min_Load.Load', 'REAL', 400.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('torque_reference', 2, 'PF755_Drive:O.TrqRefAStpt', 'REAL', 1.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('surface_stroke_length', 2, 'Card_Past[1].Surface_StrokeLength', 'REAL', 1.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('downhole_adjusted_gross_stroke', 2, 'Card_Past[1].Downhole_AdjustedGrossStroke', 'REAL', 2.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('fluid_level', 2, 'Card_Past[1].Fluid_Above_Pump', 'REAL', 200.0, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('stroke_production', 2, 'Stroke_Production', 'REAL', 0.005, 3600);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('electricity_cost', 3, 'GAUGEOFF_Electricity_Cost', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('percent_run', 3, 'GAUGEOFF_Percent_Run', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('average_spm', 3, 'GAUGEOFF_Average_SPM', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('hour', 3, 'GAUGEOFF_DateTime.Hour', 'DINT', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('min', 3, 'GAUGEOFF_DateTime.Min', 'DINT', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('kwh', 3, 'GAUGEOFF_kWh', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('lifting_cost', 3, 'GAUGEOFF_Lifting_Cost', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('polished_rod_hp', 3, 'GAUGEOFF_Polished_Rod_HP', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('month', 3, 'GAUGEOFF_DateTime.Month', 'DINT', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('inflow_rate', 3, 'GAUGEOFF_Inflow_Rate', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('fluid_level', 3, 'GAUGEOFF_Fluid_Above_Pump', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('sec', 3, 'GAUGEOFF_DateTime.Sec', 'DINT', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('full_card_production', 3, 'GAUGEOFF_Full_Card_Production', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('year', 3, 'GAUGEOFF_DateTime.Year', 'DINT', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('kwh_regen', 3, 'GAUGEOFF_kWh_regen', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('max_load', 3, 'GAUGEOFF_Max_Load', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('pump_intake_pressure', 3, 'GAUGEOFF_pump_intake_pressure', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('day', 3, 'GAUGEOFF_DateTime.Day', 'DINT', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('production_calculated', 3, 'GAUGEOFF_Production_Calculated', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('min_load', 3, 'GAUGEOFF_Min_Load', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('v_gas', 4, 'Well_Test.Volume_Gas', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('test_duration', 4, 'Well_Test.Test_Duration', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('v_oil', 4, 'Well_Test.Volume_Oil', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('k_factor', 4, 'Well_Test.k_Factor', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('p_v_water', 4, 'Well_Test.Projected_Volume_Water', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('month', 4, 'Well_Test.DateTime_Complete.Month', 'INT', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('sec', 4, 'Well_Test.DateTime_Complete.Sec', 'INT', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('v_water', 4, 'Well_Test.Volume_Water', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('year', 4, 'Well_Test.DateTime_Complete.Year', 'INT', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('p_v_oil', 4, 'Well_Test.Projected_Volume_Oil', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('day', 4, 'Well_Test.DateTime_Complete.Day', 'INT', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('sg_water', 4, 'Well_Test.SG_Water', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('api_oil', 4, 'Well_Test.API_Oil', 'REAL', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('hour', 4, 'Well_Test.DateTime_Complete.Hour', 'INT', 0, 0);
INSERT INTO tags (name, class, tag, data_type, change_threshold, guarantee_sec) VALUES ('min', 4, 'Well_Test.DateTime_Complete.Min', 'INT', 0, 0);
INSERT INTO alarms (name, class, tag) VALUES ('Flow Line Pressure', 1, 'Safety_Flow_Line_Pressure');
INSERT INTO alarms (name, class, tag) VALUES ('Load HiHi', 1, 'Safety_Load_HiHi');
INSERT INTO alarms (name, class, tag) VALUES ('Load Lo', 1, 'Safety_Load_Lo');
INSERT INTO alarms (name, class, tag) VALUES ('Tubing Pressure', 1, 'Safety_Tubing_Pressure');
INSERT INTO alarms (name, class, tag) VALUES ('Load Hi', 1, 'Safety_Load_Hi');
INSERT INTO alarms (name, class, tag) VALUES ('Casing Pressure', 1, 'Safety_Casing_Pressure');
INSERT INTO alarms (name, class, tag) VALUES ('Fluid Load', 1, 'Safety_Fluid_Load');
INSERT INTO alarms (name, class, tag) VALUES ('Flowmeter', 1, 'Safety_Flowmeter');
INSERT INTO alarms (name, class, tag) VALUES ('Speed', 1, 'Safety_Speed');
INSERT INTO alarms (name, class, tag) VALUES ('Load LoLo', 1, 'Safety_Load_LoLo');
INSERT INTO alarms (name, class, tag) VALUES ('Inclinometer', 1, 'Safety_Inclinometer');
INSERT INTO alarms (name, class, tag, cond) VALUES ('Unit Jogged', 2, 'Pump.Jog', 'Unit Jog');
INSERT INTO alarms (name, class, tag, cond) VALUES ('Restart (Auto Mode)', 2, 'Pump.Auto_Restart', 'Unit Start');
INSERT INTO alarms (name, class, tag, cond) VALUES ('Pump Off (POC Mode)', 2, 'Pump.POC_Stop', 'Unit Stop');
INSERT INTO alarms (name, class, tag, cond) VALUES ('Restart (Timer Mode)', 2, 'Pump.Timed_Restart', 'Unit Start');
INSERT INTO alarms (name, class, tag, cond) VALUES ('Restart (POC Mode)', 2, 'Pump.POC_Restart', 'Unit Start');
INSERT INTO alarms (name, class, tag, cond) VALUES ('Pump Off (Auto Mode)', 2, 'Pump.Auto_Stop', 'Unit Stop');
INSERT INTO alarms (name, class, tag, cond) VALUES ('Peak Energy Restart', 2, 'PeakEnergy.Restart', 'Unit Start');
INSERT INTO alarms (name, class, tag, cond) VALUES ('Peak Energy Stop', 2, 'PeakEnergy.Stop', 'Unit Stop');
INSERT INTO alarms (name, class, tag, cond) VALUES ('User Initiated Start', 2, 'Pump.Start', 'Unit Start');
INSERT INTO alarms (name, class, tag, cond) VALUES ('User Initiated Stop', 2, 'Pump.Stop', 'Unit Stop');
INSERT INTO alarms (name, class, tag, cond) VALUES ('Pump Off (Timer Mode)', 2, 'Pump.Timed_Stop', 'Unit Stop');

View File

@@ -1,105 +0,0 @@
from pycomm.ab_comm.clx import Driver as ClxDriver
import sys
from time import sleep
from readConfig import readConfig
def closeEnough(a,b):
return abs(a - b) <= 0.1
configProperties = readConfig()
def readTag(addr, tag):
time.sleep(0.01)
c = ClxDriver()
if c.open(configProperties['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):
global configProperties
r = 0
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()
if c.open(configProperties['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"""
global configProperties
r = 0
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()
if c.open(configProperties['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])