Files
HenryPump-Drivers/tenflowmeterskid/tenflowmeterskid.py
2020-07-09 13:34:34 -05:00

300 lines
12 KiB
Python

"""Driver for tenflowmeterskid"""
import threading
import json
import time
from random import randint
import os
from device_base import deviceBase
from Channel import PLCChannel, ModbusChannel,read_tag, write_tag, TAG_DATAERROR_SLEEPTIME
import persistence
from utilities import get_public_ip_address
from file_logger import filelogger as log
PLC_IP_ADDRESS = "192.168.1.12"
from Tags import tags
_ = None
log.info("tenflowmeterskid startup")
# GLOBAL VARIABLES
WAIT_FOR_CONNECTION_SECONDS = 20
IP_CHECK_PERIOD = 60
CHANNELS = tags
# PERSISTENCE FILE
PERSIST = persistence.load()
CALIBRATION_TABLES = [[],[], [], ]
class start(threading.Thread, deviceBase):
"""Start class required by Meshify."""
def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None,
companyId=None, offset=None, mqtt=None, Nodes=None):
"""Initialize the driver."""
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 = "1"
self.finished = threading.Event()
self.force_send = False
self.public_ip_address = ""
self.public_ip_address_last_checked = 0
threading.Thread.start(self)
# 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):
"""Register the driver."""
# self.sendtodb("log", "BOOM! Booted.", 0)
pass
def run(self):
"""Actually run the driver."""
for i in range(0, WAIT_FOR_CONNECTION_SECONDS):
print("tenflowmeterskid driver will start in {} seconds".format(WAIT_FOR_CONNECTION_SECONDS - i))
time.sleep(1)
log.info("BOOM! Starting tenflowmeterskid driver...")
self._check_ip_address()
self.nodes["tenflowmeterskid_0199"] = self
send_loops = 0
while True:
now = time.time()
if self.force_send:
log.warning("FORCE SEND: TRUE")
for chan in CHANNELS:
val = chan.read()
if chan.check(val, self.force_send):
self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'tenflowmeterskid')
#time.sleep(TAG_DATAERROR_SLEEPTIME) # sleep to allow Micro800 to handle ENET requests
for pond_index in range(1, 3):
self.read_pond_calibration(pond_index)
# print("tenflowmeterskid driver still alive...")
if self.force_send:
if send_loops > 2:
log.warning("Turning off force_send")
self.force_send = False
send_loops = 0
else:
send_loops += 1
if (now - self.public_ip_address_last_checked) > IP_CHECK_PERIOD:
self._check_ip_address()
def _check_ip_address(self):
"""Check the public IP address and send to Meshify if changed."""
self.public_ip_address_last_checked = time.time()
test_public_ip = get_public_ip_address()
if not test_public_ip == self.public_ip_address:
self.sendtodbDev(1, 'public_ip_address', test_public_ip, 0, 'tenflowmeterskid')
self.public_ip_address = test_public_ip
hostname = "google.com"
response = os.system("ping -c 1 " + hostname)
#and then check the response...
if response == 0:
print hostname, 'is up!'
self.ping_counter = 0
else:
print hostname, 'is down!'
self.ping_counter += 1
if self.ping_counter >= 3:
log.info("Rebooting because no internet detected")
os.system('reboot')
def tenflowmeterskid_sync(self, name, value):
"""Sync all data from the driver."""
self.force_send = True
# self.sendtodb("log", "synced", 0)
return True
def read_pond_calibration(self, pond_number):
"""Read all calibration values for a specific pond."""
last_read_height = -1.0
cal_values = []
cal_index = 1
while last_read_height != 0 and cal_index <=10:
cal_tag_height = "pond{}CalibrationHeight[{}]".format(pond_number, cal_index)
cal_tag_volume = "pond{}CalibrationVolume[{}]".format(pond_number, cal_index)
read_height = read_tag(PLC_IP_ADDRESS, cal_tag_height, plc_type="Micro800")
#time.sleep(2)
read_volume = read_tag(PLC_IP_ADDRESS, cal_tag_volume, plc_type="Micro800")
#time.sleep(2)
if read_height and read_volume:
if read_height[0] > 0.0:
cal_values.append({"height": read_height[0], "volume": read_volume[0]})
last_read_height = read_height[0]
cal_index += 1
if cal_values != CALIBRATION_TABLES[pond_number] or self.force_send:
calibration_channel = "pond_{}_calibration".format(pond_number)
calibration_string = json.dumps(cal_values).replace('"', "'")
self.sendtodbDev(1, calibration_channel, calibration_string, 0, 'tenflowmeterskid')
CALIBRATION_TABLES[pond_number] = cal_values
def tenflowmeterskid_deletecalibrationpoint(self, name, value):
"""Delete a calibration point from a calibration table"""
# {"pond": int, "point": int}
value = value.replace("'", '"')
parsed = json.loads(value)
try:
pond_number = int(parsed['pond'])
point_number = int(parsed['point'])
write_pond = write_tag(PLC_IP_ADDRESS, "inpPondNumber", pond_number, plc_type="Micro800")
#time.sleep(2)
write_point = write_tag(PLC_IP_ADDRESS, "inpDeletePointIndex", point_number, plc_type="Micro800")
#time.sleep(2)
if write_pond and write_point:
write_cmd = write_tag(PLC_IP_ADDRESS, "cmdDeleteCalibrationPoint", 1, plc_type="Micro800")
#time.sleep(2)
if write_cmd:
read_val = read_tag(PLC_IP_ADDRESS, "deleteSuccess", plc_type="Micro800")
if read_val[0] == 1:
self.read_pond_calibration(pond_number)
return True
return "Wrote everything successfully, but delete didn't succeed (Check pond and point values)."
return "Didn't write delete command correctly."
return "Didn't write pond or point correctly."
except KeyError as e:
return "Couldn't parse input value: {} -- {}".format(value, e)
def tenflowmeterskid_addcalibrationpoint(self, name, value):
"""Add a calibration point to the calibration table"""
# value = {"pond": int, "height": float, "volume": float}
value = value.replace("'", '"')
parsed = json.loads(value)
try:
# parse json values, throw an error if one is missing
pond_number = int(parsed['pond'])
height = float(parsed['height'])
volume = float(parsed['volume'])
# write values to the tags
write_pond = write_tag(PLC_IP_ADDRESS, "inpPondNumber", pond_number, plc_type="Micro800")
#time.sleep(2)
write_height = write_tag(PLC_IP_ADDRESS, "inpPondHeight", height, plc_type="Micro800")
#time.sleep(2)
write_volume= write_tag(PLC_IP_ADDRESS, "inpPondVolume", volume, plc_type="Micro800")
#time.sleep(2)
if write_pond and write_height and write_volume:
write_cmd = write_tag(PLC_IP_ADDRESS, "cmdAddCalibrationPoint", 1, plc_type="Micro800")
#time.sleep(2)
if write_cmd:
read_val = read_tag(PLC_IP_ADDRESS, "addSuccess", plc_type="Micro800")
if read_val[0] == 1:
self.read_pond_calibration(pond_number)
return True
return "Wrote everything successfully, but delete didn't succeed (Check pond and point values)."
return "Didn't write delete command correctly."
return "Didn't write pond or point correctly."
except KeyError as e:
return "Couldn't parse input value: {} -- {}".format(value, e)
def tenflowmeterskid_setrawmin(self, name, value):
new_val = json.loads(str(value).replace("'", '"'))
tag_n = str(new_val['tag']) # "cmd_Start"
pond_num = tag_n[9]
tag_n = 'pond{}scaling.rawmin'.format(pond_num)
val_n = new_val['val']
print("Raw Min Value: {}".format(val_n))
try:
write_resp = write_tag(str(PLC_IP_ADDRESS), tag_n, val_n, plc_type="Micro800")
print("Result of tenflowmeterskid_writeplctag(self, {}, {}) = {}".format(name, value, write_resp))
self.sendtodbDev(1, 'pond_{}_raw_min'.format(pond_num), val_n, 0, 'tenflowmeterskid')
return True
except Exception as e:
print(e)
return False
def tenflowmeterskid_setrawmax(self, name, value):
new_val = json.loads(str(value).replace("'", '"'))
tag_n = str(new_val['tag']) # "cmd_Start"
pond_num = tag_n[9]
tag_n = 'pond{}scaling.rawmax'.format(pond_num)
val_n = new_val['val']
print("Raw Max Value: {}".format(val_n))
try:
write_resp = write_tag(str(PLC_IP_ADDRESS), tag_n, val_n, plc_type="Micro800")
print("Result of tenflowmeterskid_writeplctag(self, {}, {}) = {}".format(name, value, write_resp))
self.sendtodbDev(1, 'pond_{}_raw_max'.format(pond_num), val_n, 0, 'tenflowmeterskid')
return True
except Exception as e:
print(e)
return False
def tenflowmeterskid_seteumin(self, name, value):
new_val = json.loads(str(value).replace("'", '"'))
tag_n = str(new_val['tag']) # "cmd_Start"
pond_num = tag_n[9]
tag_n = 'pond{}scaling.eumin'.format(pond_num)
val_n = new_val['val']
print("EU Min Value: {}".format(val_n))
try:
write_resp = write_tag(str(PLC_IP_ADDRESS), tag_n, val_n, plc_type="Micro800")
print("Result of tenflowmeterskid_writeplctag(self, {}, {}) = {}".format(name, value, write_resp))
self.sendtodbDev(1, 'pond_{}_eu_min'.format(pond_num), val_n, 0, 'tenflowmeterskid')
return True
except Exception as e:
print(e)
return False
def tenflowmeterskid_seteumax(self, name, value):
new_val = json.loads(str(value).replace("'", '"'))
tag_n = str(new_val['tag']) # "cmd_Start"
pond_num = tag_n[9]
tag_n = 'pond{}scaling.eumax'.format(pond_num)
val_n = new_val['val']
print("EU Max Value: {}".format(val_n))
try:
write_resp = write_tag(str(PLC_IP_ADDRESS), tag_n, val_n, plc_type="Micro800")
print("Result of tenflowmeterskid_writeplctag(self, {}, {}) = {}".format(name, value, write_resp))
self.sendtodbDev(1, 'pond_{}_eu_max'.format(pond_num), val_n, 0, 'tenflowmeterskid')
return True
except Exception as e:
print(e)
return False
def tenflowmeterskid_setoffset(self, name, value):
new_val = json.loads(str(value).replace("'", '"'))
tag_n = str(new_val['tag']) # "cmd_Start"
pond_num = tag_n[9]
val_n = new_val['val']
print("Offset Value: {}".format(val_n))
try:
write_resp = write_tag(str(PLC_IP_ADDRESS), tag_n, val_n, plc_type="Micro800")
print("Result of tenflowmeterskid_writeplctag(self, {}, {}) = {}".format(name, value, write_resp))
self.sendtodbDev(1, 'pond_{}_offset'.format(pond_num), val_n, 0, 'tenflowmeterskid')
return True
except Exception as e:
print(e)
return False
def tenflowmeterskid_writeplctag(self, name, value):
"""Write a value to the PLC."""
new_val = json.loads(str(value).replace("'", '"'))
tag_n = str(new_val['tag']) # "cmd_Start"
val_n = new_val['val']
write_res = write_tag(str(PLC_IP_ADDRESS), tag_n, val_n, plc_type="Micro800")
print("Result of tenflowmeterskid_writeplctag(self, {}, {}) = {}".format(name, value, write_res))
if write_res is None:
write_res = "Error writing to PLC..."
return write_res