255 lines
9.3 KiB
Python
255 lines
9.3 KiB
Python
#!/usr/bin/python
|
|
|
|
|
|
import threading
|
|
import time
|
|
import pickle
|
|
import traceback
|
|
|
|
from pycomm.ab_comm.clx import Driver as ClxDriver
|
|
from collections import deque
|
|
from device_base import deviceBase
|
|
|
|
PLC_IP_ADDRESS = '192.168.1.10'
|
|
|
|
|
|
def read_tag(addr, tag):
|
|
"""Read a tag from the PLC."""
|
|
plc = ClxDriver()
|
|
if plc.open(addr):
|
|
try:
|
|
v = plc.read_tag(tag)
|
|
# print(v)
|
|
return v
|
|
except Exception:
|
|
err = plc.get_status()
|
|
plc.close()
|
|
print err
|
|
plc.close()
|
|
|
|
|
|
def read_array(addr, tag, start, end):
|
|
"""Read an array from the PLC."""
|
|
plc = ClxDriver()
|
|
if plc.open(addr):
|
|
arr_vals = []
|
|
try:
|
|
for i in range(start, end):
|
|
tag_w_index = tag + "[{}]".format(i)
|
|
v = plc.read_tag(tag_w_index)
|
|
# print('{} - {}'.format(tag_w_index, v))
|
|
arr_vals.append(round(v[0], 4))
|
|
# print(v)
|
|
if arr_vals:
|
|
return arr_vals
|
|
else:
|
|
print("No length for {}".format(addr))
|
|
return False
|
|
except Exception:
|
|
err = plc.get_status()
|
|
plc.close()
|
|
print err
|
|
plc.close()
|
|
|
|
|
|
def write_tag(addr, tag, val):
|
|
"""Write a tag to the PLC."""
|
|
plc = ClxDriver()
|
|
if plc.open(addr):
|
|
try:
|
|
cv = plc.read_tag(tag)
|
|
wt = plc.write_tag(tag, val, cv[1])
|
|
return wt
|
|
except Exception:
|
|
err = plc.get_status()
|
|
plc.close()
|
|
print err
|
|
plc.close()
|
|
|
|
|
|
class Card(object):
|
|
"""Card class definition."""
|
|
|
|
def __init__(self, unified_time):
|
|
"""Initialize the Card."""
|
|
self.sc = []
|
|
self.dc = []
|
|
self.sent = False
|
|
self.read_time = unified_time
|
|
self.readCard()
|
|
self.card_id = 0
|
|
self.num_points = 0
|
|
|
|
def readCard(self):
|
|
"""Read the card data."""
|
|
self.card_id = read_tag(PLC_IP_ADDRESS, "Card_Past[1].ID")[0]
|
|
self.num_points = int(read_tag(PLC_IP_ADDRESS, "Card_Past[1].Num_Points")[0])
|
|
print("reading {} from card ID {}".format(self.num_points, self.card_id))
|
|
|
|
if self.num_points > 1:
|
|
surf_pos = False
|
|
while not surf_pos:
|
|
surf_pos = read_array(PLC_IP_ADDRESS, 'Card_Past[1].Surface_Position', 1, self.num_points)
|
|
|
|
surf_lod = False
|
|
while not surf_lod:
|
|
surf_lod = read_array(PLC_IP_ADDRESS, 'Card_Past[1].Surface_Load', 1, self.num_points)
|
|
|
|
down_pos = False
|
|
while not down_pos:
|
|
down_pos = read_array(PLC_IP_ADDRESS, 'Card_Past[1].Downhole_Position', 1, self.num_points)
|
|
|
|
down_lod = False
|
|
while not down_lod:
|
|
down_lod = read_array(PLC_IP_ADDRESS, 'Card_Past[1].Downhole_Load', 1, self.num_points)
|
|
|
|
if surf_pos and surf_lod and down_pos and down_lod:
|
|
for i in range(0, self.num_points-1):
|
|
if not (surf_pos[i] == 0.0) and not (surf_lod[i] == 0.0):
|
|
self.sc.append([surf_pos[i], surf_lod[i]])
|
|
if not (down_pos[i] == 0.0) and not (down_lod[i] == 0.0):
|
|
self.dc.append([down_pos[i], down_lod[i]])
|
|
return True
|
|
else:
|
|
print("couldn't get a full set of position/load pairs")
|
|
print("Here's what we got:")
|
|
print("SURFACE POS")
|
|
print(surf_pos)
|
|
print("SURFACE LOAD")
|
|
print(surf_lod)
|
|
print("DOWNHOLE POS")
|
|
print(down_pos)
|
|
print("DOWNHOLE LOAD")
|
|
print(down_lod)
|
|
return False
|
|
|
|
def stringify(self):
|
|
''' returns a list of two strings [surface card, downhole card]'''
|
|
# sc_str = "["
|
|
# dc_str = "["
|
|
# for i in range(0, len(self.sc)):
|
|
# this_sc_pair = self.sc[i]
|
|
# try:
|
|
# sc_str = sc_str + "[{},{}],".format(this_sc_pair[0], this_sc_pair[1])
|
|
# except IndexError, e:
|
|
# print("IndexError: {}\nFor {}".format(e, this_sc_pair))
|
|
|
|
# for j in range(0, len(self.dc)):
|
|
# dc_str = dc_str + "[{},{}],".format(self.dc[j][0], self.dc[j][1])
|
|
# dc_str = dc_str + "[{},{}]]".format(self.dc[0][0], self.dc[0][1])
|
|
sc_str = str(self.sc)
|
|
dc_str = str(self.dc)
|
|
return[sc_str, dc_str]
|
|
|
|
|
|
class start(threading.Thread, deviceBase):
|
|
|
|
def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None, companyId=None, offset=None, mqtt=None, Nodes=None):
|
|
threading.Thread.__init__(self)
|
|
deviceBase.__init__(self, name=name, number=number, mac=mac, Q=Q, mcu=mcu, companyId=companyId, offset=offset, mqtt=mqtt, Nodes=Nodes)
|
|
|
|
self.daemon = True
|
|
self.version = "5"
|
|
self.finished = threading.Event()
|
|
threading.Thread.start(self)
|
|
|
|
self.forceSend = False
|
|
self.cardLoopTimer = 600
|
|
self.statusChanged = False
|
|
self.al_status_last = False
|
|
self.dl_status_last = False
|
|
self.card_storage_limit = 5
|
|
self.last_card_sent_time = 0
|
|
self.runLoopStatus = ""
|
|
self.eventIds = []
|
|
self.wellSetup = []
|
|
|
|
# load stored event ID's
|
|
try:
|
|
with open('eventIds.p', 'rb') as handle:
|
|
self.eventIds = pickle.load(handle)
|
|
|
|
print "found pickled eventID dictionary: {0}".format(self.eventIds)
|
|
except Exception:
|
|
print "couldn't load enent ID's from pickle"
|
|
|
|
|
|
# load stored wellconfig's
|
|
try:
|
|
with open('wellSetup.p', 'rb') as handle:
|
|
self.wellSetup = pickle.load(handle)
|
|
print "Found pickled Well Setup (but it's going to be too long to print)"
|
|
except Exception:
|
|
print "couldn't load Well Setup from pickle"
|
|
|
|
# this is a required function for all drivers, its goal is to upload some piece of data
|
|
# about your device so it can be seen on the web
|
|
def register(self):
|
|
pass
|
|
|
|
|
|
def run(self):
|
|
wait_sec = 30
|
|
for i in range(0, wait_sec):
|
|
print("poc driver will start in {} seconds".format(wait_sec - i))
|
|
time.sleep(1)
|
|
|
|
|
|
card_storage = deque([]) # array of the last x cards
|
|
while True:
|
|
if self.forceSend:
|
|
print("FORCE SEND: TRUE")
|
|
try:
|
|
self.statusChanged = False
|
|
|
|
self.runLoopStatus = "Reading Cards"
|
|
if len(card_storage) > 0:
|
|
if not read_tag(PLC_IP_ADDRESS, "Card_Past[1].ID")[0] == card_storage[0].card_id:
|
|
current_time = time.time()
|
|
current_card = Card(current_time)
|
|
self.sendtodbDevJSON(1, "card_history", current_card.card_id, current_time, 'poc')
|
|
if (current_card.read_time - self.last_card_sent_time) > self.cardLoopTimer or self.forceSend:
|
|
cards = current_card.stringify()
|
|
self.sendtodbDev(1, 'sc', cards[0], current_time, "poc")
|
|
self.sendtodbDev(1, 'dc', cards[1], current_time, "poc")
|
|
self.last_card_sent_time = time.time()
|
|
current_card.sent = True
|
|
card_storage.appendleft(current_card)
|
|
while len(card_storage) > self.card_storage_limit:
|
|
card_storage.pop()
|
|
if self.statusChanged:
|
|
for c in card_storage:
|
|
if not c.sent:
|
|
cstr = c.stringify()
|
|
self.sendtodbDev(1, 'sc', cstr[0], c.read_time, "poc")
|
|
self.sendtodbDev(1, 'dc', cstr[1], c.read_time, "poc")
|
|
self.last_card_sent_time = time.time()
|
|
else:
|
|
current_time = time.time()
|
|
current_card = Card(current_time)
|
|
self.sendtodbDevJSON(1, "card_history", current_card.card_id, current_time, 'poc')
|
|
if (current_card.read_time - self.last_card_sent_time) > self.cardLoopTimer or self.forceSend:
|
|
cards = current_card.stringify()
|
|
self.sendtodbDev(1, 'sc', cards[0], current_time, "poc")
|
|
self.sendtodbDev(1, 'dc', cards[1], current_time, "poc")
|
|
self.last_card_sent_time = time.time()
|
|
current_card.sent = True
|
|
card_storage.appendleft(current_card)
|
|
self.runLoopStatus = "Complete"
|
|
time.sleep(3)
|
|
self.forceSend = False
|
|
except Exception, e:
|
|
sleep_timer = 20
|
|
print("Error during {0} of run loop: {1}\nWill try again in {2} seconds...".format(self.runLoopStatus, e, sleep_timer))
|
|
traceback.print_exc()
|
|
time.sleep(sleep_timer)
|
|
|
|
|
|
def poc_sync(self, name, value):
|
|
self.sendtodb(1, "connected", "true", 0, 'poc')
|
|
return True
|
|
|
|
def poc_refresh_data(self, name, value):
|
|
self.forceSend = True
|
|
return True
|