"""Driver for prostarsolar.""" import threading from device_base import deviceBase from Channel import read_tag, write_tag from Channel import ModbusChannel from Maps import charge_state, array_faults import persistence from random import randint from utilities import get_public_ip_address, int_to_float16 import json import time import minimalmodbus import minimalmodbusM1 _ = None # GLOBAL VARIABLES WATCHDOG_SEND_PERIOD = 3600 # Seconds, the longest amount of time before sending the watchdog status PLC_IP_ADDRESS = "192.168.1.10" CHANNELS = [ ModbusChannel("adc_ia", 17, "REAL", 0.5, 3600, transformFn=int_to_float16), ModbusChannel("adc_vbterm", 18, "REAL", 0.5, 3600, transformFn=int_to_float16), ModbusChannel("adc_va", 19, "REAL", 0.5, 3600, transformFn=int_to_float16), ModbusChannel("adc_vl", 20, "REAL", 0.5, 3600, transformFn=int_to_float16), ModbusChannel("adc_il", 22, "REAL", 0.5, 3600, transformFn=int_to_float16), ModbusChannel("t_amb", 28, "REAL", 2.0, 3600, transformFn=int_to_float16), ModbusChannel("vb_min_daily", 65, "REAL", 2.0, 3600, transformFn=int_to_float16), ModbusChannel("vb_max_daily", 66, "REAL", 2.0, 3600, transformFn=int_to_float16), ModbusChannel('charge_state', 33, "STRING", 1, 3600, transformFn=charge_state), ModbusChannel('array_fault', 34, "STRING", 1, 3600, transformFn=array_faults) ] # PERSISTENCE FILE persist = persistence.load() 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.forceSend = False 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.""" global persist wait_sec = 60 for i in range(0, wait_sec): print("prostarsolar driver will start in {} seconds".format(wait_sec - i)) time.sleep(1) print("BOOM! Starting prostarsolar driver...") self.nodes["prostarsolar_0199"] = self public_ip_address = get_public_ip_address() self.sendtodbDev(1, 'public_ip_address', public_ip_address, 0, 'prostarsolar') # watchdog = self.prostarsolar_watchdog() # self.sendtodbDev(1, 'watchdog', watchdog, 0, 'prostarsolar') # watchdog_send_timestamp = time.time() connected_to_485 = False while connected_to_485 is False: connected_to_485 = self.mcu.set485Baud(9600) serial_485 = self.mcu.rs485 instrument_485 = minimalmodbusM1.Instrument(1, serial_485) instrument_485.address = 1 send_loops = 0 watchdog_loops = 0 watchdog_check_after = 5000 while True: if self.forceSend: print "FORCE SEND: TRUE" for chan in CHANNELS: try: val = chan.read(instrument_485.read_register(chan.register_number, functioncode=4)) if chan.check(val, self.forceSend): self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'prostarsolar') time.sleep(0.1) except IOError as e: print("IO Error: {}".format(e)) print("Attempting to reconnect to rs485 device") connected_to_485 = False while connected_to_485 is False: connected_to_485 = self.mcu.set485Baud(9600) serial_485 = self.mcu.rs485 instrument_485 = minimalmodbusM1.Instrument(1, serial_485) instrument_485.address = 1 # print("prostarsolar driver still alive...") if self.forceSend: if send_loops > 2: print("Turning off forceSend") self.forceSend = False send_loops = 0 else: send_loops += 1 watchdog_loops += 1 if (watchdog_loops >= watchdog_check_after): # test_watchdog = self.prostarsolar_watchdog() # if not test_watchdog == watchdog or (time.time() - watchdog_send_timestamp) > WATCHDOG_SEND_PERIOD: # self.sendtodbDev(1, 'watchdog', test_watchdog, 0, 'prostarsolar') # watchdog = test_watchdog test_public_ip = get_public_ip_address() if not test_public_ip == public_ip_address: self.sendtodbDev(1, 'public_ip_address', test_public_ip, 0, 'prostarsolar') public_ip_address = test_public_ip watchdog_loops = 0 time.sleep(10) def prostarsolar_watchdog(self): """Write a random integer to the PLC and then 1 seconds later check that it has been decremented by 1.""" randval = randint(0, 32767) write_tag(str(PLC_IP_ADDRESS), 'watchdog_INT', randval) time.sleep(1) watchdog_val = read_tag(str(PLC_IP_ADDRESS), 'watchdog_INT') try: return (randval - 1) == watchdog_val[0] except (KeyError, TypeError): return False def prostarsolar_sync(self, name, value): """Sync all data from the driver.""" self.forceSend = True # self.sendtodb("log", "synced", 0) return True def prostarsolar_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'] w = write_tag(str(PLC_IP_ADDRESS), tag_n, val_n) print("Result of prostarsolar_writeplctag(self, {}, {}) = {}".format(name, value, w)) if w is None: w = "Error writing to PLC..." return w