Files
HenryPump-Drivers/multisensor/multisensor.py
2020-06-12 15:37:03 -05:00

374 lines
17 KiB
Python

"""Driver for multisensor"""
import threading
import json
import time
from random import randint
from device_base import deviceBase
from channel import PLCChannel, read_tag, write_tag
from utilities import get_public_ip_address
from file_logger import filelogger as log
import persistence
# PERSISTENCE FILE
PERSIST = persistence.load('persist.json')
if not PERSIST:
PERSIST = {'an0low': 1.0, 'an0high': 20.0, 'an0active': 0,
'an1low': 1.0, 'an1high': 20.0, 'an1active': 0,
'an2low': 1.0, 'an2high': 20.0, 'an2active': 0,
'an3low': 1.0, 'an3high': 20.0, 'an3active': 0,
'an4low': 1.0, 'an4high': 20.0, 'an4active': 0,
'an5low': 1.0, 'an5high': 20.0, 'an5active': 0,
'an6low': 1.0, 'an6high': 20.0, 'an6active': 0,
'an7low': 1.0, 'an7high': 20.0, 'an7active': 0}
persistence.store(PERSIST, 'persist.json')
_ = None
# log = file_logger.setup()
log.info("multisensor startup")
# GLOBAL VARIABLES
WAIT_FOR_CONNECTION_SECONDS = 60
PLC_IP_ADDRESS = "192.168.1.12"
CALIBRATION_TABLES = [[] for x in xrange(8)]
CHANNELS = [
PLCChannel(PLC_IP_ADDRESS, 'an0active', 'input0.active', 'BOOL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an1active', 'input1.active', 'BOOL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an2active', 'input2.active', 'BOOL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an3active', 'input3.active', 'BOOL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an4active', 'input4.active', 'BOOL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an5active', 'input5.active', 'BOOL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an6active', 'input6.active', 'BOOL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an7active', 'input7.active', 'BOOL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an0val', 'input0.scaledValue', 'REAL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an1val', 'input1.scaledValue', 'REAL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an2val', 'input2.scaledValue', 'REAL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an3val', 'input3.scaledValue', 'REAL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an4val', 'input4.scaledValue', 'REAL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an5val', 'input5.scaledValue', 'REAL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an6val', 'input6.scaledValue', 'REAL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'an7val', 'input7.scaledValue', 'REAL', 1.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'pond0volume', 'input0.pondVolume', 'REAL', 1000.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'pond1volume', 'input1.pondVolume', 'REAL', 1000.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'pond2volume', 'input2.pondVolume', 'REAL', 1000.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'pond3volume', 'input3.pondVolume', 'REAL', 1000.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'pond4volume', 'input4.pondVolume', 'REAL', 1000.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'pond5volume', 'input5.pondVolume', 'REAL', 1000.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'pond6volume', 'input6.pondVolume', 'REAL', 1000.0, 600, map_=False, write_enabled=False, plc_type="Micro800"),
PLCChannel(PLC_IP_ADDRESS, 'pond7volume', 'input7.pondVolume', 'REAL', 1000.0, 600, map_=False, write_enabled=False, plc_type="Micro800")
]
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 = "6"
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("multisensor driver will start in {} seconds".format(WAIT_FOR_CONNECTION_SECONDS - i))
time.sleep(1)
log.info("BOOM! Starting multisensor driver...")
self._check_ip_address()
self.nodes["multisensor_0199"] = self
send_loops = 0
ip_check_after = 60
for i in range(0,8):
self.read_pond_calibration(i)
while True:
now = time.time()
if self.force_send:
log.warning("FORCE SEND: TRUE")
for chan in CHANNELS:
val = chan.read()
if "active" in chan.plc_tag:
PERSIST[chan.mesh_name] = val
persistence.store(PERSIST,'persist.json')
if chan.check(val, self.force_send):
self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'multisensor')
if "scaledValue" in chan.plc_tag:
if val <= PERSIST[chan.mesh_name[:3]+"low"] and PERSIST[chan.mesh_name[:3]+"active"] == 1:
self.sendtodbDev(1, chan.mesh_name[:3]+"alarm", "LOW", 0, 'multisensor')
elif val >= PERSIST[chan.mesh_name[:3]+"high"] and PERSIST[chan.mesh_name[:3]+"active"] == 1:
self.sendtodbDev(1, chan.mesh_name[:3]+"alarm", "HIGH", 0, 'multisensor')
else:
self.sendtodbDev(1, chan.mesh_name[:3]+"alarm", "OK", 0, 'multisensor')
#time.sleep(5)
# print("multisensor driver still alive...")
if self.force_send:
if send_loops > 2:
log.warning("Turning off force_send")
self.force_send = False
send_loops = 0
for i in range(0,8):
self.read_pond_calibration(i)
else:
send_loops += 1
if (now - self.public_ip_address_last_checked) > ip_check_after:
self._check_ip_address()
def read_pond_calibration(self, input_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 = "input{}.calibrationLevel[{}]".format(input_number, cal_index)
cal_tag_volume = "input{}.calibrationVolume[{}]".format(input_number, cal_index)
read_height = read_tag(PLC_IP_ADDRESS, cal_tag_height, plc_type="Micro800")
time.sleep(5)
read_volume = read_tag(PLC_IP_ADDRESS, cal_tag_volume, plc_type="Micro800")
time.sleep(5)
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[input_number] or self.force_send:
calibration_channel = "pond{}calibration".format(input_number)
calibration_string = json.dumps(cal_values).replace('"', "'")
self.sendtodbDev(1, calibration_channel, calibration_string, 0, 'multisensor')
CALIBRATION_TABLES[input_number] = cal_values
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, 'multisensor')
self.public_ip_address = test_public_ip
def multisensor_addcalibrationpoint(self, name, value):
"""Add a calibration point to the calibration table"""
# value = {"input": int, "height": float, "volume": float}
value = value.replace("'", '"')
parsed = json.loads(value)
try:
# parse json values, throw an error if one is missing
input_number = int(parsed['input'])
height = float(parsed['height'])
volume = float(parsed['volume'])
# write values to the tags
write_height = write_tag(PLC_IP_ADDRESS, "input{}_cmd.inpCalLevel".format(input_number), height, plc_type="Micro800")
#time.sleep(2)
write_volume= write_tag(PLC_IP_ADDRESS, "input{}_cmd.inpCalVolume".format(input_number), volume, plc_type="Micro800")
#time.sleep(2)
if write_height and write_volume:
write_cmd = write_tag(PLC_IP_ADDRESS, "input{}_cmd.cmdInsertCalPoint".format(input_number), 1, plc_type="Micro800")
#time.sleep(2)
if write_cmd:
read_val = read_tag(PLC_IP_ADDRESS, "input{}.insertSuccess", plc_type="Micro800")
if read_val[0] == 1:
self.read_pond_calibration(input_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 multisensor_deletecalibrationpoint(self, name, value):
"""Delete a calibration point from a calibration table"""
# {"input": int, "point": int}
value = value.replace("'", '"')
parsed = json.loads(value)
try:
input_number = int(parsed['input'])
point_number = int(parsed['point'])
write_point = write_tag(PLC_IP_ADDRESS, "input{}_cmd.inpDeleteIndex".format(input_number), point_number, plc_type="Micro800")
#time.sleep(2)
if write_point:
write_cmd = write_tag(PLC_IP_ADDRESS, "input{}_cmd.cmdDeleteCalPoint".format(input_number), 1, plc_type="Micro800")
#time.sleep(2)
if write_cmd:
read_val = read_tag(PLC_IP_ADDRESS, "input{}.deleteSuccess", plc_type="Micro800")
if read_val[0] == 1:
self.read_pond_calibration(input_number)
return True
return "Wrote everything successfully, but delete didn't succeed (Check input and point values)."
return "Didn't write delete command correctly."
return "Didn't write input or point correctly."
except KeyError as e:
return "Couldn't parse input value: {} -- {}".format(value, e)
def multisensor_sync(self, name, value):
"""Sync all data from the driver."""
self.force_send = True
print("got sync({}, {})".format(name, value))
self.sendtodb("log", "synced", 0)
return True
def multisensor_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 multisensor_writeplctag(self, {}, {}) = {}".format(name, value, write_res))
if write_res is None:
write_res = "Error writing to PLC..."
if write_res:
if "scalingConfig" in tag_n:
if tag_n[-1] == "x":
self.sendtodbDev(1, 'an{}max'.format(tag_n[5]), val_n, 0, 'multisensor')
else:
self.sendtodbDev(1, 'an{}min'.format(tag_n[5]), val_n, 0, 'multisensor')
elif "isPondLevel" in tag_n:
self.sendtodbDev(1, 'an{}ispond'.format(tag_n[5]), val_n, 0, 'multisensor')
return write_res
def multisensor_an0lowpsialarm(self, name, value):
value = int(value)
PERSIST["an0low"] = value
self.sendtodbDev(1, 'an0lowpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an1lowpsialarm(self, name, value):
value = int(value)
PERSIST["an1low"] = value
self.sendtodbDev(1, 'an1lowpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an2lowpsialarm(self, name, value):
value = int(value)
PERSIST["an2low"] = value
self.sendtodbDev(1, 'an2lowpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an3lowpsialarm(self, name, value):
value = int(value)
PERSIST["an3low"] = value
self.sendtodbDev(1, 'an3lowpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an4lowpsialarm(self, name, value):
value = int(value)
PERSIST["an4low"] = value
self.sendtodbDev(1, 'an4lowpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an5lowpsialarm(self, name, value):
value = int(value)
PERSIST["an5low"] = value
self.sendtodbDev(1, 'an5lowpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an6lowpsialarm(self, name, value):
value = int(value)
PERSIST["an6low"] = value
self.sendtodbDev(1, 'an6lowpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an7lowpsialarm(self, name, value):
value = int(value)
PERSIST["an7low"] = value
self.sendtodbDev(1, 'an7lowpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an0highpsialarm(self, name, value):
value = int(value)
PERSIST["an0high"] = value
self.sendtodbDev(1, 'an0highpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an1highpsialarm(self, name, value):
value = int(value)
PERSIST["an1high"] = value
self.sendtodbDev(1, 'an1highpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an2highpsialarm(self, name, value):
value = int(value)
PERSIST["an2high"] = value
self.sendtodbDev(1, 'an2highpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an3highpsialarm(self, name, value):
value = int(value)
PERSIST["an3high"] = value
self.sendtodbDev(1, 'an3highpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an4highpsialarm(self, name, value):
value = int(value)
PERSIST["an4high"] = value
self.sendtodbDev(1, 'an4highpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an5highpsialarm(self, name, value):
value = int(value)
PERSIST["an5high"] = value
self.sendtodbDev(1, 'an5highpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an6highpsialarm(self, name, value):
value = int(value)
PERSIST["an6high"] = value
self.sendtodbDev(1, 'an6highpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")
def multisensor_an7highpsialarm(self, name, value):
value = int(value)
PERSIST["an7high"] = value
self.sendtodbDev(1, 'an7highpsialarm', value, 0, 'multisensor')
return persistence.store(PERSIST,"persist.json")