"""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")