diff --git a/python-driver/Channel.py b/python-driver/Channel.py index 0862eae..3814368 100644 --- a/python-driver/Channel.py +++ b/python-driver/Channel.py @@ -155,18 +155,21 @@ class Channel(object): """Read the value.""" pass + def identity(sent): - """Returns exactly what was sent to it.""" + """Return exactly what was sent to it.""" return sent + class ModbusChannel(Channel): """Modbus channel object.""" - def __init__(self, mesh_name, register_number, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False, transformFn=identity): + def __init__(self, mesh_name, register_number, data_type, chg_threshold, guarantee_sec, channel_size=1, map_=False, write_enabled=False, transformFn=identity): """Initialize the channel.""" super(ModbusChannel, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled) self.mesh_name = mesh_name self.register_number = register_number + self.channel_size = channel_size self.data_type = data_type self.last_value = None self.value = None @@ -178,6 +181,7 @@ class ModbusChannel(Channel): self.transformFn = transformFn def read(self, mbsvalue): + """Return the transformed read value.""" return self.transformFn(mbsvalue) @@ -209,8 +213,10 @@ class PLCChannel(Channel): return plc_value + class BoolArrayChannels(Channel): """Hold the configuration for a set of boolean array channels.""" + def __init__(self, ip, mesh_name, plc_tag, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False): """Initialize the channel.""" self.plc_ip = ip diff --git a/python-driver/Maps.py b/python-driver/Maps.py deleted file mode 100644 index 049acda..0000000 --- a/python-driver/Maps.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Holds map values for prostarsolar.""" - -def charge_state(inp_state): - """Map function for charge state.""" - states = { - 0: "Start", - 1: "Night Check", - 2: "Disconnect", - 3: "Night", - 4: "Fault", - 5: "Bulk", - 6: "Absorption", - 7: "Float", - 8: "Equalize" - } - if inp_state in range(0,9): - return states[inp_state] - else: - return inp_state - - -def array_faults(inp_array_faults): - """Form a string for the array_faults.""" - fault_string = "" - faults = { - 0: "Overcurrent Phase 1", - 1: "FETs Shorted", - 2: "Software Bug", - 3: "Battery HVD (High Voltage Disconnect)", - 4: "Array HVD (High Voltage Disconnect)", - 5: "EEPROM Setting Edit (reset required)", - 6: "RTS Shorted", - 7: "RTS was valid now disconnected", - 8: "Local temp. sensor failed", - 9: "Battery LVD (Low Voltage Disconect)", - 10: "DIP Switch Changed (excl. DIP 8)", - 11: "Processor Supply Fault" - } - - bit_string = ("0" * 16 + "{0:b}".format(inp_array_faults))[-16:] - for i in range(0, 12): - if int(bit_string[i]) == 1: - fault_string += faults[i] + ", " - if fault_string: - return fault_string[:-2] - else: - return "None" \ No newline at end of file diff --git a/python-driver/driverConfig.json b/python-driver/driverConfig.json index efbeb72..5562fee 100644 --- a/python-driver/driverConfig.json +++ b/python-driver/driverConfig.json @@ -1,13 +1,12 @@ { - "name": "prostarsolar", - "driverFilename": "prostarsolar.py", - "driverId": "0000", + "name": "prostarsolar", + "driverFilename": "prostarsolar.py", + "driverId": "0000", "additionalDriverFiles": [ "utilities.py", - "persistence.py", - "Channel.py", - "Maps.py" - ], - "version": 1, + "persistence.py", + "Channel.py" + ], + "version": 1, "s3BucketName": "prostarsolar" -} \ No newline at end of file +} diff --git a/python-driver/prostarsolar.py b/python-driver/prostarsolar.py index 1878d35..2d923a0 100644 --- a/python-driver/prostarsolar.py +++ b/python-driver/prostarsolar.py @@ -2,20 +2,67 @@ 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 +minimalmodbusM1.CLOSE_PORT_AFTER_EACH_CALL = True +minimalmodbusM1.STOPBITS = 2 + _ = None + +def charge_state(inp_state): + """Map function for charge state.""" + states = { + 0: "Start", + 1: "Night Check", + 2: "Disconnect", + 3: "Night", + 4: "Fault", + 5: "Bulk", + 6: "Absorption", + 7: "Float", + 8: "Equalize" + } + if inp_state in range(0, 9): + return states[inp_state] + else: + return inp_state + + +def array_faults(inp_array_faults): + """Form a string for the array_faults.""" + fault_string = "" + faults = { + 0: "Overcurrent Phase 1", + 1: "FETs Shorted", + 2: "Software Bug", + 3: "Battery HVD (High Voltage Disconnect)", + 4: "Array HVD (High Voltage Disconnect)", + 5: "EEPROM Setting Edit (reset required)", + 6: "RTS Shorted", + 7: "RTS was valid now disconnected", + 8: "Local temp. sensor failed", + 9: "Battery LVD (Low Voltage Disconect)", + 10: "DIP Switch Changed (excl. DIP 8)", + 11: "Processor Supply Fault" + } + + bit_string = ("0" * 16 + "{0:b}".format(inp_array_faults))[-16:] + for i in range(0, 12): + if int(bit_string[i]) == 1: + fault_string += faults[i] + ", " + if fault_string: + return fault_string[:-2] + else: + return "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" @@ -78,8 +125,8 @@ class start(threading.Thread, deviceBase): connected_to_485 = self.mcu.set485Baud(9600) serial_485 = self.mcu.rs485 - instrument_485 = minimalmodbusM1.Instrument(1, serial_485) - instrument_485.address = 1 + instrument_485 = minimalmodbusM1.Instrument(21, serial_485) + instrument_485.address = 21 send_loops = 0 watchdog_loops = 0 @@ -95,17 +142,19 @@ class start(threading.Thread, deviceBase): self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'prostarsolar') time.sleep(0.1) except IOError as e: - print("IO Error: {}".format(e)) + print("prostarsolar 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 + instrument_485 = minimalmodbusM1.Instrument(21, serial_485) + instrument_485.address = 21 + except Exception as e: + print("prostarsolar Non-IO Error: {}".format(e)) - # print("prostarsolar driver still alive...") + print("prostarsolar driver still alive...") if self.forceSend: if send_loops > 2: print("Turning off forceSend") @@ -128,30 +177,8 @@ class start(threading.Thread, deviceBase): 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