diff --git a/abbflow/pi/abbflow/python-driver/Channel.py b/abbflow/pi/Channel.py similarity index 100% rename from abbflow/pi/abbflow/python-driver/Channel.py rename to abbflow/pi/Channel.py diff --git a/abbflow/pi/abbflow/python-driver/Tags.py b/abbflow/pi/Tags.py similarity index 100% rename from abbflow/pi/abbflow/python-driver/Tags.py rename to abbflow/pi/Tags.py diff --git a/abbflow/pi/abbflow/python-driver/abbflow.py b/abbflow/pi/abbflow.py similarity index 100% rename from abbflow/pi/abbflow/python-driver/abbflow.py rename to abbflow/pi/abbflow.py diff --git a/abbflow/pi/abbflow/html-templates/Alerts.html b/abbflow/pi/abbflow/html-templates/Alerts.html deleted file mode 100644 index 2971cab..0000000 --- a/abbflow/pi/abbflow/html-templates/Alerts.html +++ /dev/null @@ -1 +0,0 @@ -Alerts diff --git a/abbflow/pi/abbflow/html-templates/Device.html b/abbflow/pi/abbflow/html-templates/Device.html deleted file mode 100644 index 5feeb9b..0000000 --- a/abbflow/pi/abbflow/html-templates/Device.html +++ /dev/null @@ -1,42 +0,0 @@ -
-
-

Public IP Address

-

<%= channels["abbflow.public_ip_address"].value %>

-

-
- - diff --git a/abbflow/pi/abbflow/html-templates/NodeDetailHeader.html b/abbflow/pi/abbflow/html-templates/NodeDetailHeader.html deleted file mode 100644 index 28262a3..0000000 --- a/abbflow/pi/abbflow/html-templates/NodeDetailHeader.html +++ /dev/null @@ -1,6 +0,0 @@ -
-
-
-
-

<%= node.vanityname %>

-
diff --git a/abbflow/pi/abbflow/html-templates/Nodelist.html b/abbflow/pi/abbflow/html-templates/Nodelist.html deleted file mode 100644 index 756a869..0000000 --- a/abbflow/pi/abbflow/html-templates/Nodelist.html +++ /dev/null @@ -1,31 +0,0 @@ - - -
-
-
-
- -
- -
- -
-

<%= node.vanityname %>

-
-
diff --git a/abbflow/pi/abbflow/html-templates/Overview.html b/abbflow/pi/abbflow/html-templates/Overview.html deleted file mode 100644 index 1526000..0000000 --- a/abbflow/pi/abbflow/html-templates/Overview.html +++ /dev/null @@ -1,121 +0,0 @@ - -
-
-

HEADER 1

-
-
-

CHANNEL 1

-
-
-
-
- - - -
- - <%= channels["abbflow.channel_1"].timestamp %> - -
-
-
- - - - - - - - diff --git a/abbflow/pi/abbflow/html-templates/Sidebar.html b/abbflow/pi/abbflow/html-templates/Sidebar.html deleted file mode 100644 index 72532e2..0000000 --- a/abbflow/pi/abbflow/html-templates/Sidebar.html +++ /dev/null @@ -1,15 +0,0 @@ -" - class="data-table btn-block btn btn-theme animated" - title="Device Log"> Device Log - -" - data-techname="<%=channels["abbflow.sync"].techName %>" - data-name="<%= channels["abbflow.sync"].name%>" - data-nodechannelcurrentId="<%= channels["abbflow.sync"].nodechannelcurrentId %>" - id="<%= channels["abbflow.sync"].channelId %>" - class="btn btn-large btn-block btn-theme animated setstatic mqtt"> - Sync All Data diff --git a/abbflow/pi/abbflow/html-templates/Trends.html b/abbflow/pi/abbflow/html-templates/Trends.html deleted file mode 100644 index 8a7a806..0000000 --- a/abbflow/pi/abbflow/html-templates/Trends.html +++ /dev/null @@ -1,37 +0,0 @@ -
-
- - to - - - Run - -
-
-
-
-
- diff --git a/abbflow/pi/abbflow/python-driver/config.txt b/abbflow/pi/config.txt similarity index 100% rename from abbflow/pi/abbflow/python-driver/config.txt rename to abbflow/pi/config.txt diff --git a/abbflow/pi/abbflow/python-driver/device_base.py b/abbflow/pi/device_base.py similarity index 100% rename from abbflow/pi/abbflow/python-driver/device_base.py rename to abbflow/pi/device_base.py diff --git a/abbflow/pi/abbflow/python-driver/file_logger.py b/abbflow/pi/file_logger.py similarity index 100% rename from abbflow/pi/abbflow/python-driver/file_logger.py rename to abbflow/pi/file_logger.py diff --git a/abbflow/pi/abbflow/python-driver/persistence.py b/abbflow/pi/persistence.py similarity index 100% rename from abbflow/pi/abbflow/python-driver/persistence.py rename to abbflow/pi/persistence.py diff --git a/abbflow/pi/abbflow/python-driver/utilities.py b/abbflow/pi/utilities.py similarity index 100% rename from abbflow/pi/abbflow/python-driver/utilities.py rename to abbflow/pi/utilities.py diff --git a/dual_flowmeter/Tags.py b/dual_flowmeter/Tags.py index d7788d0..f9219e3 100644 --- a/dual_flowmeter/Tags.py +++ b/dual_flowmeter/Tags.py @@ -3,7 +3,7 @@ from dual_flowmeter import PLC_IP_ADDRESS tags = [ PLCChannel(PLC_IP_ADDRESS, "pump_1_daily_total","Pump_1_Daily_Flow_Rate_Total","REAL", 100, 3600, plc_type="Micro800"), - PLCChannel(PLC_IP_ADDRESS, "pump_1_run_status","Pump_1_Run_Status","BOOL", 1, 3600, plc_type="Micro800", map_={0: "Off", 1: "On"}), + PLCChannel(PLC_IP_ADDRESS, "pump_1_run_status","Pump_1_Run_Status","BOOL", 1, 3600, plc_type="Micro800", map_={0: "Off", 1: "On", None: "N/A"}), PLCChannel(PLC_IP_ADDRESS, "pump_1_flowrate","Pump_1_SCL_Flow_Meter","REAL", 1000, 3600, plc_type="Micro800"), PLCChannel(PLC_IP_ADDRESS, "pump_1_yesterdays_total","Pump_1_Yesterdays_Total","REAL", 1000, 3600, plc_type="Micro800"), PLCChannel(PLC_IP_ADDRESS, "pump_1_prevmonth_total","Pump_1_PrevMonth_Total","REAL", 1000, 3600, plc_type="Micro800"), @@ -11,7 +11,7 @@ tags = [ PLCChannel(PLC_IP_ADDRESS, "pump_1_lifetime_total","Pump_1_Lifetime_Flow","REAL", 1000, 3600, plc_type="Micro800"), PLCChannel(PLC_IP_ADDRESS, "pump_1_suction","Suction_PSI_TP1_Scaled","REAL", 10, 3600, plc_type="Micro800"), PLCChannel(PLC_IP_ADDRESS, "pump_2_daily_total","Pump_2_Daily_Flow_Rate_Total","REAL", 100, 3600, plc_type="Micro800"), - PLCChannel(PLC_IP_ADDRESS, "pump_2_run_status","Pump_2_Run_Status","BOOL", 1, 3600, plc_type="Micro800", map_={0: "Off", 1: "On"}), + PLCChannel(PLC_IP_ADDRESS, "pump_2_run_status","Pump_2_Run_Status","BOOL", 1, 3600, plc_type="Micro800", map_={0: "Off", 1: "On", None: "N/A"}), PLCChannel(PLC_IP_ADDRESS, "pump_2_flowrate","Pump_2_SCL_Flow_Meter","REAL", 1000, 3600, plc_type="Micro800"), PLCChannel(PLC_IP_ADDRESS, "pump_2_yesterdays_total","Pump_2_Yesterdays_Total","REAL", 1000, 3600, plc_type="Micro800"), PLCChannel(PLC_IP_ADDRESS, "pump_2_prevmonth_total","Pump_2_PrevMonth_Total","REAL", 1000, 3600, plc_type="Micro800"), @@ -21,5 +21,5 @@ tags = [ PLCChannel(PLC_IP_ADDRESS, "pump_charge_psi_tp1", "Charge_PSI_TP1_Scaled", "REAL", 10, 3600, plc_type="Micro800"), PLCChannel(PLC_IP_ADDRESS, "pond_1_height", "Pond_level_tp1_scaled", "REAL", 2, 3600, plc_type="Micro800"), PLCChannel(PLC_IP_ADDRESS, "pond_1_volume", "pond1volume", "REAL", 100000, 3600, plc_type="Micro800"), - PLCChannel(PLC_IP_ADDRESS, "charge_pump_run_status","CHARGE_PUMP_Run_Status","BOOL", 1, 3600, plc_type="Micro800", map_={0: "Off", 1: "On"}) + PLCChannel(PLC_IP_ADDRESS, "charge_pump_run_status","CHARGE_PUMP_Run_Status","BOOL", 1, 3600, plc_type="Micro800", map_={0: "Off", 1: "On", None: "N/A"}) ] \ No newline at end of file diff --git a/dual_flowmeter/config.txt b/dual_flowmeter/config.txt index 800e0a5..9600d41 100644 --- a/dual_flowmeter/config.txt +++ b/dual_flowmeter/config.txt @@ -8,7 +8,7 @@ "file4": "Tags.py" }, "deviceName": "dual_flowmeter", - "releaseVersion": "8", + "releaseVersion": "9", "driverFileName": "dual_flowmeter.py", "driverId": "0100" } \ No newline at end of file diff --git a/dual_flowmeter/dual_flowmeter.py b/dual_flowmeter/dual_flowmeter.py index 2324759..f7ea875 100644 --- a/dual_flowmeter/dual_flowmeter.py +++ b/dual_flowmeter/dual_flowmeter.py @@ -10,7 +10,19 @@ from Channel import PLCChannel, ModbusChannel,read_tag, write_tag, TAG_DATAERROR import persistence from utilities import get_public_ip_address from file_logger import filelogger as log -PLC_IP_ADDRESS = "192.168.1.12" + +# PERSISTENCE FILE +PERSIST = persistence.load('persist.json') +if not PERSIST: + PERSIST = { "plc_ip" : "192.168.1.12" } + persistence.store(PERSIST, 'persist.json') +try: + PLC_IP_ADDRESS = PERSIST["plc_ip"] +except Exception as e: + PERSIST["plc_ip"] = "192.168.1.12" + PLC_IP_ADDRESS = PERSIST["plc_ip"] + persistence.store(PERSIST,"persist.json") + from Tags import tags _ = None @@ -26,8 +38,6 @@ WATCHDOG_SEND_PERIOD = 3600 # Seconds, the longest amount of time before sendin CHANNELS = tags -# PERSISTENCE FILE -PERSIST = persistence.load() class start(threading.Thread, deviceBase): @@ -42,7 +52,7 @@ class start(threading.Thread, deviceBase): mqtt=mqtt, Nodes=Nodes) self.daemon = True - self.version = "8" + self.version = "9" self.finished = threading.Event() self.force_send = False self.public_ip_address = "" diff --git a/dualactuator/alt/dualactuator/python-driver/Channel.py b/dualactuator/alt/Channel.py similarity index 100% rename from dualactuator/alt/dualactuator/python-driver/Channel.py rename to dualactuator/alt/Channel.py diff --git a/dualactuator/alt/dualactuator/python-driver/Tags.py b/dualactuator/alt/Tags.py similarity index 91% rename from dualactuator/alt/dualactuator/python-driver/Tags.py rename to dualactuator/alt/Tags.py index 8a9e838..dfe4351 100644 --- a/dualactuator/alt/dualactuator/python-driver/Tags.py +++ b/dualactuator/alt/Tags.py @@ -16,5 +16,6 @@ tags = [ PLCChannel(PLC_IP_ADDRESS, "fm2_lastmonth","Val_FlowmeterLastMonthTotal","REAL", 1000, 86400, plc_type="Micro800"), PLCChannel(PLC_IP_ADDRESS, "v1_open_fbk","FBK_Valve_Open","STRING", 1, 3600, plc_type="Micro800"), PLCChannel(PLC_IP_ADDRESS, "v2_open_fbk","FBK_Valve_Open","STRING", 1, 86400, plc_type="Micro800"), - PLCChannel(PLC_IP_ADDRESS, "single_control","single_control","STRING", 1, 86400, plc_type="Micro800") + PLCChannel(PLC_IP_ADDRESS, "single_control","single_control","STRING", 1, 86400, plc_type="Micro800"), + PLCChannel(PLC_IP_ADDRESS, "flowrate_setpoint", "SPT_DailyMaxSetpoint", "REAL", 1, 3600, plc_type="Micro800") ] \ No newline at end of file diff --git a/dualactuator/alt/dualactuator/python-driver/config.txt b/dualactuator/alt/config.txt similarity index 92% rename from dualactuator/alt/dualactuator/python-driver/config.txt rename to dualactuator/alt/config.txt index 1126cdc..1706b9f 100644 --- a/dualactuator/alt/dualactuator/python-driver/config.txt +++ b/dualactuator/alt/config.txt @@ -8,7 +8,7 @@ "file4": "Tags.py" }, "deviceName": "dualactuator", - "releaseVersion": "2", + "releaseVersion": "3", "driverFileName": "dualactuator.py", "driverId": "0100" } \ No newline at end of file diff --git a/dualactuator/alt/dualactuator/python-driver/device_base.py b/dualactuator/alt/device_base.py similarity index 100% rename from dualactuator/alt/dualactuator/python-driver/device_base.py rename to dualactuator/alt/device_base.py diff --git a/dualactuator/alt/dualactuator/python-driver/dualactuator.py b/dualactuator/alt/dualactuator.py similarity index 99% rename from dualactuator/alt/dualactuator/python-driver/dualactuator.py rename to dualactuator/alt/dualactuator.py index 80db173..2d751b7 100644 --- a/dualactuator/alt/dualactuator/python-driver/dualactuator.py +++ b/dualactuator/alt/dualactuator.py @@ -40,7 +40,7 @@ class start(threading.Thread, deviceBase): mqtt=mqtt, Nodes=Nodes) self.daemon = True - self.version = "2" + self.version = "3" self.finished = threading.Event() self.force_send = False self.public_ip_address = "" diff --git a/dualactuator/alt/dualactuator/html-templates/Alerts.html b/dualactuator/alt/dualactuator/html-templates/Alerts.html deleted file mode 100644 index 2971cab..0000000 --- a/dualactuator/alt/dualactuator/html-templates/Alerts.html +++ /dev/null @@ -1 +0,0 @@ -Alerts diff --git a/dualactuator/alt/dualactuator/html-templates/Device.html b/dualactuator/alt/dualactuator/html-templates/Device.html deleted file mode 100644 index cb73349..0000000 --- a/dualactuator/alt/dualactuator/html-templates/Device.html +++ /dev/null @@ -1,42 +0,0 @@ -
-
-

Public IP Address

-

<%= channels["dualactuator.public_ip_address"].value %>

-

-
- - diff --git a/dualactuator/alt/dualactuator/html-templates/NodeDetailHeader.html b/dualactuator/alt/dualactuator/html-templates/NodeDetailHeader.html deleted file mode 100644 index 28262a3..0000000 --- a/dualactuator/alt/dualactuator/html-templates/NodeDetailHeader.html +++ /dev/null @@ -1,6 +0,0 @@ -
-
-
-
-

<%= node.vanityname %>

-
diff --git a/dualactuator/alt/dualactuator/html-templates/Nodelist.html b/dualactuator/alt/dualactuator/html-templates/Nodelist.html deleted file mode 100644 index 756a869..0000000 --- a/dualactuator/alt/dualactuator/html-templates/Nodelist.html +++ /dev/null @@ -1,31 +0,0 @@ - - -
-
-
-
- -
- -
- -
-

<%= node.vanityname %>

-
-
diff --git a/dualactuator/alt/dualactuator/html-templates/Overview.html b/dualactuator/alt/dualactuator/html-templates/Overview.html deleted file mode 100644 index eaf2bc2..0000000 --- a/dualactuator/alt/dualactuator/html-templates/Overview.html +++ /dev/null @@ -1,121 +0,0 @@ - -
-
-

HEADER 1

-
-
-

CHANNEL 1

-
-
-
-
- - - -
- - <%= channels["dualactuator.channel_1"].timestamp %> - -
-
-
- - - - - - - - diff --git a/dualactuator/alt/dualactuator/html-templates/Sidebar.html b/dualactuator/alt/dualactuator/html-templates/Sidebar.html deleted file mode 100644 index 5a1dbd3..0000000 --- a/dualactuator/alt/dualactuator/html-templates/Sidebar.html +++ /dev/null @@ -1,15 +0,0 @@ -" - class="data-table btn-block btn btn-theme animated" - title="Device Log"> Device Log - -" - data-techname="<%=channels["dualactuator.sync"].techName %>" - data-name="<%= channels["dualactuator.sync"].name%>" - data-nodechannelcurrentId="<%= channels["dualactuator.sync"].nodechannelcurrentId %>" - id="<%= channels["dualactuator.sync"].channelId %>" - class="btn btn-large btn-block btn-theme animated setstatic mqtt"> - Sync All Data diff --git a/dualactuator/alt/dualactuator/html-templates/Trends.html b/dualactuator/alt/dualactuator/html-templates/Trends.html deleted file mode 100644 index 72c633c..0000000 --- a/dualactuator/alt/dualactuator/html-templates/Trends.html +++ /dev/null @@ -1,37 +0,0 @@ -
-
- - to - - - Run - -
-
-
-
-
- diff --git a/dualactuator/alt/dualactuator/python-driver/file_logger.py b/dualactuator/alt/file_logger.py similarity index 100% rename from dualactuator/alt/dualactuator/python-driver/file_logger.py rename to dualactuator/alt/file_logger.py diff --git a/dualactuator/alt/dualactuator/python-driver/persistence.py b/dualactuator/alt/persistence.py similarity index 100% rename from dualactuator/alt/dualactuator/python-driver/persistence.py rename to dualactuator/alt/persistence.py diff --git a/dualactuator/alt/dualactuator/python-driver/utilities.py b/dualactuator/alt/utilities.py similarity index 100% rename from dualactuator/alt/dualactuator/python-driver/utilities.py rename to dualactuator/alt/utilities.py diff --git a/multisensor/multisensor.py b/multisensor/multisensor.py index 28e4ffe..d860e64 100644 --- a/multisensor/multisensor.py +++ b/multisensor/multisensor.py @@ -201,7 +201,7 @@ class start(threading.Thread, deviceBase): if write_cmd: read_val = read_tag(PLC_IP_ADDRESS, "input{}.insertSuccess", plc_type="Micro800") if read_val[0] == 1: - self.read_pond_calibration(pond_number) + 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." diff --git a/piflow/Channel.py b/piflow/Channel.py index 6c6ccbb..b86f607 100644 --- a/piflow/Channel.py +++ b/piflow/Channel.py @@ -26,6 +26,7 @@ def read_tag(addr, tag, plc_type="CLX"): if clx.open(addr, direct_connection=direct): try: val = clx.read_tag(tag) + clx.close() return val except DataError as err: clx.close() @@ -54,9 +55,11 @@ def read_array(addr, tag, start, end, plc_type="CLX"): val = clx.read_tag(tag_w_index) arr_vals.append(round(val[0], 4)) if arr_vals: + clx.close() return arr_vals else: log.error("No length for {}".format(addr)) + clx.close() return False except Exception: log.error("Error during readArray({}, {}, {}, {})".format(addr, tag, start, end)) @@ -75,6 +78,7 @@ def write_tag(addr, tag, val, plc_type="CLX"): try: initial_val = clx.read_tag(tag) write_status = clx.write_tag(tag, val, initial_val[1]) + clx.close() return write_status except DataError as err: clx_err = clx.get_status() diff --git a/piflow/PiFlow.py b/piflow/PiFlow.py index 2fffab1..2f80ccc 100644 --- a/piflow/PiFlow.py +++ b/piflow/PiFlow.py @@ -9,6 +9,19 @@ from device_base import deviceBase import persistence from utilities import get_public_ip_address, get_private_ip_address from file_logger import filelogger as log +import RPi.GPIO as GPIO + +Relay_Ch1 = 26 +Relay_Ch2 = 20 +Relay_Ch3 = 21 + +GPIO.setwarnings(False) +GPIO.setmode(GPIO.BCM) + +GPIO.setup(Relay_Ch1,GPIO.OUT) +GPIO.setup(Relay_Ch2,GPIO.OUT) +GPIO.setup(Relay_Ch3,GPIO.OUT) + _ = None os.system('sudo timedatectl set-timezone America/Chicago') @@ -22,13 +35,39 @@ IP_CHECK_PERIOD = 60 # PERSISTENCE FILE PERSIST = persistence.load('persist.json') if not PERSIST: - PERSIST = {'flowmeter': 1, 'drive': 1, 'drive_enabled': False, 'yesterday_totalizer_1': dt.today().day, 'yesterday_totalizer_2': dt.today().day,'yesterday_totalizer_3': dt.today().day, - 'yesterday_total_totalizer_1': 0, 'yesterday_total_midnight_totalizer_1': 0, - 'yesterday_total_totalizer_2': 0, 'yesterday_total_midnight_totalizer_2': 0, - 'yesterday_total_totalizer_3': 0, 'yesterday_total_midnight_totalizer_3': 0} + PERSIST = { + 'flowmeter': 247, + 'drive': 1, + 'isVFD': False, + 'drive_enabled': True, + 'plc_ip': '192.168.1.12', + 'yesterday_totalizer_1': dt.today().day, + 'yesterday_totalizer_2': dt.today().day, + 'yesterday_totalizer_3': dt.today().day, + 'yesterday_total_totalizer_1': 0, + 'yesterday_total_midnight_totalizer_1': 0, + 'yesterday_total_totalizer_2': 0, + 'yesterday_total_midnight_totalizer_2': 0, + 'yesterday_total_totalizer_3': 0, + 'yesterday_total_midnight_totalizer_3': 0 + } persistence.store(PERSIST, 'persist.json') drive_enabled = PERSIST['drive_enabled'] +try: + isVFD = PERSIST['isVFD'] +except: + PERSIST['isVFD'] = False + isVFD = PERSIST['isVFD'] + persistence.store(PERSIST) + +try: + plc_ip = PERSIST['plc_ip'] +except: + PERSIST['plc_ip'] = '192.168.1.12' + plc_ip = PERSIST['plc_ip'] + persistence.store(PERSIST) + from Tags import tags CHANNELS = tags @@ -45,12 +84,14 @@ class start(threading.Thread, deviceBase): mqtt=mqtt, Nodes=Nodes) self.daemon = True - self.version = "20" + self.version = "25" self.finished = threading.Event() self.force_send = False self.public_ip_address = "" self.private_ip_address = "" self.public_ip_address_last_checked = 0 + self.status = "" + self.alarm = "" threading.Thread.start(self) # this is a required function for all drivers, its goal is to upload some piece of data @@ -78,30 +119,66 @@ class start(threading.Thread, deviceBase): now = time.time() if self.force_send: log.warning("FORCE SEND: TRUE") - - for chan in CHANNELS: - try: - for x in range(3): + if isVFD: + status = {} + for chan in CHANNELS[:24]: #build status/alarm strings + try: val = chan.read() - if not val == None: - break - if val == None: - log.info("No modbus read sending previous value") - val = chan.value - if chan.mesh_name in ['totalizer_1','totalizer_2','totalizer_3']: - right_now = dt.today() - today_total, yesterday_total = self.totalize(val, PERSIST['yesterday_'+chan.mesh_name], right_now.day, right_now.hour, right_now.minute, PERSIST['yesterday_total_midnight_'+chan.mesh_name], PERSIST['yesterday_total_'+chan.mesh_name], chan.mesh_name) - if chan.check(val, self.force_send): - self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'PiFlow') - self.sendtodbDev(1,"today_"+chan.mesh_name, today_total,0,'PiFlow') - self.sendtodbDev(1,"yesterday_"+chan.mesh_name, yesterday_total,0,'PiFlow') - else: - if chan.check(val, self.force_send): - self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'PiFlow') - + chan.check(val, self.force_send) + status[chan.mesh_name] = chan.value + except Exception as e: + log.warning("An error occured in status check: {}".format(e)) + try: + self.sendStatus(status) except Exception as e: - log.warning("An error occured: {}".format(e)) - time.sleep(3) + log.warning("An error occured in send status: {}".format(e)) + for chan in CHANNELS[24:]: + try: + val = chan.read() + if chan.mesh_name in ['totalizer_1','totalizer_2','totalizer_3']: + right_now = dt.today() + today_total, yesterday_total = self.totalize(val, PERSIST['yesterday_'+chan.mesh_name], right_now.day, right_now.hour, right_now.minute, PERSIST['yesterday_total_midnight_'+chan.mesh_name], PERSIST['yesterday_total_'+chan.mesh_name], chan.mesh_name) + if chan.check(val, self.force_send): + self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'PiFlow') + self.sendtodbDev(1,"today_"+chan.mesh_name, today_total,0,'PiFlow') + self.sendtodbDev(1,"yesterday_"+chan.mesh_name, yesterday_total,0,'PiFlow') + self.sendtodbDev(1, chan.mesh_name + "_units", "BBL",0,'PiFlow') + else: + if chan.check(val, self.force_send): + self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'PiFlow') + except Exception as e: + log.warning("An error occured in data collection: {}".format(e)) + else: + for chan in CHANNELS: + try: + for x in range(3): + val = chan.read() + if not val == None: + break + if val == None: + log.info("No modbus read sending previous value") + val = chan.value + if chan.mesh_name in ['totalizer_1','totalizer_2','totalizer_3']: + right_now = dt.today() + today_total, yesterday_total = self.totalize(val, PERSIST['yesterday_'+chan.mesh_name], right_now.day, right_now.hour, right_now.minute, PERSIST['yesterday_total_midnight_'+chan.mesh_name], PERSIST['yesterday_total_'+chan.mesh_name], chan.mesh_name) + if chan.check(val, self.force_send): + self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'PiFlow') + self.sendtodbDev(1,"today_"+chan.mesh_name, today_total,0,'PiFlow') + self.sendtodbDev(1,"yesterday_"+chan.mesh_name, yesterday_total,0,'PiFlow') + elif chan.mesh_name == "volume_flow" and not PERSIST['drive_enabled']: + if chan.check(val, self.force_send): + self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'PiFlow') + if chan.value > 0: + self.sendtodbDev(1, "run_status", "Running", 0, 'PiFlow') + else: + self.sendtodbDev(1,"run_status", "Stopped", 0, 'PiFlow') + else: + if chan.check(val, self.force_send): + self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'PiFlow') + + except Exception as e: + log.warning("An error occured: {}".format(e)) + time.sleep(3) # print("PiFlow driver still alive...") @@ -193,6 +270,24 @@ class start(threading.Thread, deviceBase): log.info("Result of PiFlow_write(self, {}, {}) = {}".format(name, value, write_res)) return write_res + + def PiFlow_start(self, name, value): + if isVFD: + #do something with the plc + log.info("Sending START signal to PLC") + else: + log.info("Sending START signal to Drive via relay {}".format(Relay_Ch1)) + GPIO.output(Relay_Ch1,GPIO.LOW) + return True + + def PiFlow_stop(self, name, value): + if isVFD: + log.info("Sending STOP signal to PLC") + #do something with the plc + else: + log.info("Sending STOP signal to Drive") + GPIO.output(Relay_Ch1,GPIO.HIGH) + return True def totalize(self,val, yesterday, day, hour, minute, yesterday_total_midnight, yesterday_total,channel): if (yesterday_total == 0 and yesterday_total_midnight == 0) or (yesterday_total == None or yesterday_total_midnight == None): @@ -210,4 +305,179 @@ class start(threading.Thread, deviceBase): PERSIST['yesterday_total_midnight_'+channel] = yesterday_total_midnight persistence.store(PERSIST,'persist.json') - return today_total,yesterday_total \ No newline at end of file + return today_total,yesterday_total + + def sendStatus(self,status): + status_string = "" + + fault_codes = { + 0: "", + 2: "Auxiliary Input", + 3: "Power Loss", + 4: "UnderVoltage", + 5: "OverVoltage", + 7: "Motor Overload", + 8: "Heatsink OvrTemp", + 9: "Thermister OvrTemp", + 10: "DynBrake OverTemp", + 12: "HW OverCurrent", + 13: "Ground Fault", + 14: "Ground Warning", + 15: "Load Loss", + 17: "Input Phase Loss", + 18: "Motor PTC Trip", + 19: "Task Overrun", + 20: "TorqPrv Spd Band", + 21: "Output PhaseLoss", + 24: "Decel Inhibit", + 25: "OverSpeed Limit", + 26: "Brake Slipped", + 27: "Torq Prove Cflct", + 28: "TP Encls Config", + 29: "Analog In Loss", + 33: "AuRsts Exhausted", + 35: "IPM OverCurrent", + 36: "SW OverCurrent", + 38: "Phase U to Grnd", + 39: "Phase V to Grnd", + 40: "Phase W to Grnd", + 41: "Phase UV Short", + 42: "Phase VW Short", + 43: "Phase WU Short", + 44: "Phase UNegToGrnd", + 45: "Phase VNegToGrnd", + 46: "Phase WNegToGrnd", + 48: "System Defaulted", + 49: "Drive Powerup", + 51: "Clr Fault Queue", + 55: "Ctrl Bd Overtemp", + 59: "Invalid Code", + 61: "Shear Pin 1", + 62: "Shear Pin 2", + 64: "Drive Overload", + 67: "Pump Off", + 71: "Port 1 Adapter", + 72: "Port 2 Adapter", + 73: "Port 3 Adapter", + 74: "Port 4 Adapter", + 75: "Port 5 Adapter", + 76: "Port 6 Adapter", + 77: "IR Volts Range", + 78: "FluxAmpsRef Rang", + 79: "Excessive Load", + 80: "AutoTune Aborted", + 81: "Port 1 DPI Loss", + 82: "Port 2 DPI Loss", + 83: "Port 3 DPI Loss", + 84: "Port 4 DPI Loss", + 85: "Port 5 DPI Loss", + 86: "Port 6 DPI Loss", + 87: "Ixo VoltageRange", + 91: "Pri VelFdbk Loss", + 93: "Hw Enable Check", + 94: "Alt VelFdbk Loss", + 95: "Aux VelFdbk Loss", + 96: "PositionFdbkLoss", + 97: "Auto Tach Switch", + 100: "Parameter Chksum", + 101: "PwrDn NVS Blank", + 102: "NVS Not Blank", + 103: "PwrDn Nvs Incomp", + 104: "Pwr Brd Checksum", + 106: "Incompat MCB-PB", + 107: "Replaced MCB-PB", + 108: "Anlg Cal Chksum", + 110: "Ivld Pwr Bd Data", + 111: "PwrBd Invalid ID", + 112: "PwrBd App MinVer", + 113: "Tracking DataErr", + 115: "PwrDn Table Full", + 116: "PwrDnEntry2Large", + 117: "PwrDn Data Chksm", + 118: "PwrBd PwrDn Chks", + 124: "App ID Changed", + 125: "Using Backup App", + 134: "Start on PowerUp", + 137: "Ext Prechrg Err", + 138: "Precharge Open", + 141: "Autn Enc Angle", + 142: "Autn Spd Rstrct", + 143: "AutoTune CurReg", + 144: "AutoTune Inertia", + 145: "AutoTune Travel", + 13037: "Net IO Timeout" + } + + if status['vfd_active'] == "Stopped": + status_string = status_string + status['vfd_active'] + "; " + status['vfd_ready'] + else: + status_string = status_string + status['vfd_active'] + if status['vfd_rev']: + status_string = status_string + '; ' + status['vfd_rev'] + if status['vfd_fwd']: + status_string = status_string + '; ' + status['vfd_fwd'] + if status['vfd_atreference']: + status_string = status_string + '; ' + status['vfd_atreference'] + alarm_string = "" + if status['vfd_faulted'] == "Drive Faulted": + status_string = status_string + '; ' + status['vfd_faulted'] + if status['vfd_commloss']: + alarm_string = alarm_string + '; ' + status['vfd_commloss'] + if status['vfd_fbkalarm']: + alarm_string = alarm_string + '; ' + status['vfd_fbkalarm'] + if status['vfd_faultcode']: + alarm_string = alarm_string + '; ' + "Fault: {} Fault code: {}".format(fault_codes[status['vfd_faultcode']],str(status['vfd_faultcode'])) + if status['minspeedalarm']: + alarm_string = alarm_string + '; ' + status['minspeedalarm'] + if status['pumpedoff']: + alarm_string = alarm_string + '; ' + status['pumpedoff'] + if status['lockedout']: + alarm_string = alarm_string + '; ' + status['lockedout'] + if status['tubingpressurehi']: + alarm_string = alarm_string + '; ' + status['tubingpressurehi'] + if status['tubingpressurehihi']: + alarm_string = alarm_string + '; ' + status['tubingpressurehihi'] + if status['tubingpressurelo']: + alarm_string = alarm_string + '; ' + status['tubingpressurelo'] + if status['tubingpressurelolo']: + alarm_string = alarm_string + '; ' + status['tubingpressurelolo'] + if status['flowmeterhihi']: + alarm_string = alarm_string + '; ' + status['flowmeterhihi'] + if status['flowmeterhi']: + alarm_string = alarm_string + '; ' + status['flowmeterhi'] + if status['flowmeterlolo']: + alarm_string = alarm_string + '; ' + status['flowmeterlolo'] + if status['flowmeterlo']: + alarm_string = alarm_string + '; ' + status['flowmeterlo'] + if status['fluidlevellolo']: + alarm_string = alarm_string + '; ' + status['fluidlevellolo'] + if status['fluidlevello']: + alarm_string = alarm_string + '; ' + status['fluidlevello'] + if status['fluidlevelhi']: + alarm_string = alarm_string + '; ' + status['fluidlevelhi'] + if status['fluidlevelhihi']: + alarm_string = alarm_string + '; ' + status['fluidlevelhihi'] + try: + if status_string and status_string[0] == '; ': + status_string = status_string[1:] + if status_string and status_string[-1] == '; ': + status_string = status_string[:-1] + if alarm_string and alarm_string[0] == '; ': + alarm_string = alarm_string[1:] + if alarm_string and alarm_string[-1] == '; ': + alarm_string = alarm_string[:-1] + except Exception as e: + log.warning("Error in send status semicolon: {}".format(e)) + + if self.status != status_string: + self.status = status_string + log.info("Sending {} for {}".format(status_string, 'run_status')) + self.sendtodbDev(1, 'run_status', status_string, 0, 'PiFlow') + if self.alarm != alarm_string: + self.alarm = alarm_string + log.info("Sending {} for {}".format(alarm_string, 'fault_a')) + self.sendtodbDev(1, 'fault_a', alarm_string, 0 , 'PiFlow') + + + + diff --git a/piflow/Tags.py b/piflow/Tags.py index 46d00a0..4a98d54 100644 --- a/piflow/Tags.py +++ b/piflow/Tags.py @@ -1,45 +1,84 @@ from Channel import PLCChannel,Channel, ModbusChannel, status_codes, fault_code_a, fault_code_b, volume_units, totalizer_units import persistence -data = persistence.load('persist.json') -flowmeter_unit_number = data['flowmeter'] -drive_enabled = data['drive_enabled'] -if drive_enabled: - drive_unit_number = data['drive'] - - +PERSIST = persistence.load('persist.json') +flowmeter_unit_number = PERSIST['flowmeter'] +drive_enabled = PERSIST['drive_enabled'] +isVFD = PERSIST['isVFD'] if drive_enabled: + drive_unit_number = PERSIST['drive'] +try: + plc_ip = PERSIST['plc_ip'] +except: + PERSIST['plc_ip'] = '192.168.1.12' + persistence.store(PERSIST) +if isVFD: tags = [ - ModbusChannel('volume_flow', 3873, 'FLOAT', 1,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_1', 2609, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_2', 2809, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_3', 3009, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('volume_flow_units', 2102, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=volume_units), - ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - - ModbusChannel('run_status', 772, 'STRING', 0, 3600, channel_size=1, unit_number=drive_unit_number, transform_fn=status_codes), - ModbusChannel('frequency', 784, 'INTEGER', 0.5, 600, channel_size=2, unit_number=drive_unit_number,scaling=2 ), - ModbusChannel('current', 783, 'INTEGER', 0.5, 600, channel_size=2, unit_number=drive_unit_number,scaling=1 ), - ModbusChannel('fault_a', 815, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_a), - ModbusChannel('fault_b', 816, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_b), - ModbusChannel('pid_ref', 791, 'INTEGER', 1, 600, channel_size=1, unit_number=drive_unit_number,scaling=1), - ModbusChannel('pid_feedback', 792, 'INTEGER', 1, 600, channel_size=1, unit_number=drive_unit_number,scaling=1), - ModbusChannel('motor_rated_current', 4896, 'INTEGER', 0, 3600, channel_size=1, unit_number=drive_unit_number,scaling=1), - ModbusChannel('sleep_delay', 4924, 'INTEGER', 1, 600, channel_size=1, unit_number=drive_unit_number, scaling=1) - ] -else: - tags = [ - ModbusChannel('volume_flow', 3873, 'FLOAT', 1,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_1', 2609, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_2', 2809, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_3', 3009, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('volume_flow_units', 2102, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=volume_units), - ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units) + PLCChannel(plc_ip,'vfd_atreference','sts_VFD_AtReference','BOOL',0,3600,map_={0: "", 1: "At speed"},plc_type='Micro800'), + PLCChannel(plc_ip,'vfd_rev','sts_VFD_REV','BOOL',0,3600,map_={0: "", 1: "Operating in Reverse"},plc_type='Micro800'), + PLCChannel(plc_ip,'vfd_fwd','sts_VFD_FWD','BOOL',0,3600,map_={0: "", 1: "Operating in Forward"},plc_type='Micro800'), + PLCChannel(plc_ip,'vfd_active','sts_VFD_Active','BOOL',0,3600,map_={0: "Stopped", 1: "Running"},plc_type='Micro800'), + PLCChannel(plc_ip,'vfd_ready','sts_VFD_Ready','BOOL',0,3600,map_={0: "Drive Not Ready", 1: "Drive Ready"},plc_type='Micro800'), + PLCChannel(plc_ip,'vfd_faultcode','sts_VFD_FaultCode','REAL',0,3600, plc_type='Micro800'), + PLCChannel(plc_ip,'vfd_faulted','AL0_VFD','BOOL',0,3600,map_={0: "", 1: "Drive Faulted"},plc_type='Micro800'), + PLCChannel(plc_ip,'vfd_commloss','AL0_VFDComLoss','BOOL',0,3600,map_={0: "", 1: "Drive Comms Loss"},plc_type='Micro800'), + PLCChannel(plc_ip,'vfd_fbkalarm','AL0_VFD_FBAlarm','BOOL',0,3600,map_={0: "", 1: "Drive Lost Feedback"},plc_type='Micro800'), + PLCChannel(plc_ip,'tubingpressurehi','AL0_TubingPressureHi','BOOL',0,3600,map_={0: "", 1: "High Tubing Pressure"},plc_type='Micro800'), + PLCChannel(plc_ip,'tubingpressurehihi','AL0_TubingPressureHiHi','BOOL',0,3600,map_={0: "", 1: "High High Tubing Pressure"},plc_type='Micro800'), + PLCChannel(plc_ip,'tubingpressurelo','AL0_TubingPressureLo','BOOL',0,3600,map_={0: "", 1: "Low Tubing Pressure"},plc_type='Micro800'), + PLCChannel(plc_ip,'tubingpressurelolo','AL0_TubingPressureLoLo','BOOL',0,3600,map_={0: "", 1: "Low Low Tubing Pressure"},plc_type='Micro800'), + PLCChannel(plc_ip,'flowmeterhihi','AL0_FlowMeterHiHi','BOOL',0,3600,map_={0: "", 1: "High High FM Flow Rate"},plc_type='Micro800'), + PLCChannel(plc_ip,'flowmeterhi','AL0_FlowMeterHi','BOOL',0,3600,map_={0: "", 1: "High FM Flow Rate"},plc_type='Micro800'), + PLCChannel(plc_ip,'flowmeterlolo','AL0_FlowMeterLoLo','BOOL',0,3600,map_={0: "", 1: "Low Low FM Flow Rate"},plc_type='Micro800'), + PLCChannel(plc_ip,'flowmeterlo','AL0_FlowMeterLo','BOOL',0,3600,map_={0: "", 1: "Low FM Flow Rate"},plc_type='Micro800'), + PLCChannel(plc_ip,'minspeedalarm','AL0_MinSpeedAlarm','BOOL',0,3600,map_={0: "", 1: "Drive not able to maintain min speed"},plc_type='Micro800'), + PLCChannel(plc_ip,'pumpedoff','AL0_PumpedOff','BOOL',0,3600,map_={0: "", 1: "Pumped Off"},plc_type='Micro800'), + PLCChannel(plc_ip,'fluidlevellolo','AL0_FluidLevelLoLo','BOOL',0,3600,map_={0: "", 1: "Low Low Fluid Level"},plc_type='Micro800'), + PLCChannel(plc_ip,'fluidlevello','AL0_FluidLevelLo','BOOL',0,3600,map_={0: "", 1: "Low Fluid Level"},plc_type='Micro800'), + PLCChannel(plc_ip,'fluidlevelhi','AL0_FluidLevelHi','BOOL',0,3600,map_={0: "", 1: "High Fluid Level"},plc_type='Micro800'), + PLCChannel(plc_ip,'fluidlevelhihi','AL0_FluidLevelHiHi','BOOL',0,3600,map_={0: "", 1: "High High Fluid Level"},plc_type='Micro800'), + PLCChannel(plc_ip,'lockedout','AlarmLockOut','BOOL',0,3600,map_={0: "", 1: "Locked Out Repeated Alarms"},plc_type='Micro800'), + PLCChannel(plc_ip,'volume_flow','Val_FlowmeterFR','REAL',5,3600,plc_type='Micro800'), + PLCChannel(plc_ip,'current','val_VFD_OutputCurrent','REAL',5,3600,plc_type='Micro800'), + PLCChannel(plc_ip,'frequency','val_VFD_ActualSpeed','REAL',5,3600,plc_type='Micro800'), + PLCChannel(plc_ip,'pid_feedback','val_FluidLevel','REAL',5,3600,plc_type='Micro800'), + PLCChannel(plc_ip,'totalizer_1','Val_FlowMeterT1','REAL',5,3600,plc_type='Micro800'), + PLCChannel(plc_ip,'totalizer_2','Val_FlowMeterT2','REAL',5,3600,plc_type='Micro800'), + PLCChannel(plc_ip,'totalizer_3','Val_FlowMeterT3','REAL',5,3600,plc_type='Micro800'), + PLCChannel(plc_ip,'volume_flow_units','CMD_FlowMeterUnit','BOOL',1,3600,map_={0: "GPM", 1: "BPD"},plc_type='Micro800') ] +else: + if drive_enabled: + tags = [ + ModbusChannel('volume_flow', 3873, 'FLOAT', 10, 3600,channel_size=2, unit_number=flowmeter_unit_number), + ModbusChannel('totalizer_1', 2609, 'FLOAT', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number), + ModbusChannel('totalizer_2', 2809, 'FLOAT', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number), + ModbusChannel('totalizer_3', 3009, 'FLOAT', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number), + ModbusChannel('volume_flow_units', 2102, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=volume_units), + ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), + ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), + ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), + ModbusChannel('run_status', 772, 'STRING', 0, 3600, channel_size=1, unit_number=drive_unit_number, transform_fn=status_codes), + ModbusChannel('frequency', 784, 'INTEGER', 2, 3600, channel_size=2, unit_number=drive_unit_number,scaling=2 ), + ModbusChannel('current', 783, 'INTEGER', 2, 3600, channel_size=2, unit_number=drive_unit_number,scaling=1 ), + ModbusChannel('fault_a', 815, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_a), + ModbusChannel('fault_b', 816, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_b), + ModbusChannel('pid_ref', 791, 'INTEGER', 5, 3600, channel_size=1, unit_number=drive_unit_number,scaling=1), + ModbusChannel('pid_feedback', 792, 'INTEGER', 5, 3600, channel_size=1, unit_number=drive_unit_number,scaling=1), + ModbusChannel('motor_rated_current', 4896, 'INTEGER', 300, 86400, channel_size=1, unit_number=drive_unit_number,scaling=1), + ModbusChannel('sleep_delay', 4924, 'INTEGER', 5, 86400, channel_size=1, unit_number=drive_unit_number, scaling=1) + ] + else: + tags = [ + ModbusChannel('volume_flow', 3873, 'FLOAT', 10, 3600,channel_size=2, unit_number=flowmeter_unit_number), + ModbusChannel('totalizer_1', 2609, 'FLOAT', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number), + ModbusChannel('totalizer_2', 2809, 'FLOAT', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number), + ModbusChannel('totalizer_3', 3009, 'FLOAT', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number), + ModbusChannel('volume_flow_units', 2102, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=volume_units), + ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), + ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), + ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units) + ] diff --git a/piflow/VFD525/.vscode/.ropeproject/config.py b/piflow/VFD525/.vscode/.ropeproject/config.py deleted file mode 100644 index dee2d1a..0000000 --- a/piflow/VFD525/.vscode/.ropeproject/config.py +++ /dev/null @@ -1,114 +0,0 @@ -# The default ``config.py`` -# flake8: noqa - - -def set_prefs(prefs): - """This function is called before opening the project""" - - # Specify which files and folders to ignore in the project. - # Changes to ignored resources are not added to the history and - # VCSs. Also they are not returned in `Project.get_files()`. - # Note that ``?`` and ``*`` match all characters but slashes. - # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' - # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' - # '.svn': matches 'pkg/.svn' and all of its children - # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' - # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' - prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', - '.hg', '.svn', '_svn', '.git', '.tox'] - - # Specifies which files should be considered python files. It is - # useful when you have scripts inside your project. Only files - # ending with ``.py`` are considered to be python files by - # default. - # prefs['python_files'] = ['*.py'] - - # Custom source folders: By default rope searches the project - # for finding source folders (folders that should be searched - # for finding modules). You can add paths to that list. Note - # that rope guesses project source folders correctly most of the - # time; use this if you have any problems. - # The folders should be relative to project root and use '/' for - # separating folders regardless of the platform rope is running on. - # 'src/my_source_folder' for instance. - # prefs.add('source_folders', 'src') - - # You can extend python path for looking up modules - # prefs.add('python_path', '~/python/') - - # Should rope save object information or not. - prefs['save_objectdb'] = True - prefs['compress_objectdb'] = False - - # If `True`, rope analyzes each module when it is being saved. - prefs['automatic_soa'] = True - # The depth of calls to follow in static object analysis - prefs['soa_followed_calls'] = 0 - - # If `False` when running modules or unit tests "dynamic object - # analysis" is turned off. This makes them much faster. - prefs['perform_doa'] = True - - # Rope can check the validity of its object DB when running. - prefs['validate_objectdb'] = True - - # How many undos to hold? - prefs['max_history_items'] = 32 - - # Shows whether to save history across sessions. - prefs['save_history'] = True - prefs['compress_history'] = False - - # Set the number spaces used for indenting. According to - # :PEP:`8`, it is best to use 4 spaces. Since most of rope's - # unit-tests use 4 spaces it is more reliable, too. - prefs['indent_size'] = 4 - - # Builtin and c-extension modules that are allowed to be imported - # and inspected by rope. - prefs['extension_modules'] = [] - - # Add all standard c-extensions to extension_modules list. - prefs['import_dynload_stdmods'] = True - - # If `True` modules with syntax errors are considered to be empty. - # The default value is `False`; When `False` syntax errors raise - # `rope.base.exceptions.ModuleSyntaxError` exception. - prefs['ignore_syntax_errors'] = False - - # If `True`, rope ignores unresolvable imports. Otherwise, they - # appear in the importing namespace. - prefs['ignore_bad_imports'] = False - - # If `True`, rope will insert new module imports as - # `from import ` by default. - prefs['prefer_module_from_imports'] = False - - # If `True`, rope will transform a comma list of imports into - # multiple separate import statements when organizing - # imports. - prefs['split_imports'] = False - - # If `True`, rope will remove all top-level import statements and - # reinsert them at the top of the module when making changes. - prefs['pull_imports_to_top'] = True - - # If `True`, rope will sort imports alphabetically by module name instead - # of alphabetically by import statement, with from imports after normal - # imports. - prefs['sort_imports_alphabetically'] = False - - # Location of implementation of - # rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general - # case, you don't have to change this value, unless you're an rope expert. - # Change this value to inject you own implementations of interfaces - # listed in module rope.base.oi.type_hinting.providers.interfaces - # For example, you can add you own providers for Django Models, or disable - # the search type-hinting in a class hierarchy, etc. - prefs['type_hinting_factory'] = ( - 'rope.base.oi.type_hinting.factory.default_type_hinting_factory') - - -def project_opened(project): - """This function is called after opening the project""" - # Do whatever you like here! diff --git a/piflow/VFD525/.vscode/.ropeproject/objectdb b/piflow/VFD525/.vscode/.ropeproject/objectdb deleted file mode 100644 index 9022e6d..0000000 --- a/piflow/VFD525/.vscode/.ropeproject/objectdb +++ /dev/null @@ -1,4 +0,0 @@ -}qUpersistence.pyq}qUloadqcrope.base.oi.memorydb -ScopeInfo -q)q}qUbuiltinqUstrq q -Uunknownq q s}q bss. \ No newline at end of file diff --git a/piflow/VFD525/Channel.py b/piflow/VFD525/Channel.py deleted file mode 100644 index b86f607..0000000 --- a/piflow/VFD525/Channel.py +++ /dev/null @@ -1,615 +0,0 @@ -"""Define Meshify channel class.""" -import time -from pycomm.ab_comm.clx import Driver as ClxDriver -from pycomm.cip.cip_base import CommError, DataError -from file_logger import filelogger as log -import minimalmodbus - -minimalmodbus.BAUDRATE = 9600 -minimalmodbus.STOPBITS = 1 - -TAG_DATAERROR_SLEEPTIME = 5 - -def binarray(intval): - """Split an integer into its bits.""" - bin_string = '{0:08b}'.format(intval) - bin_arr = [i for i in bin_string] - bin_arr.reverse() - return bin_arr - - -def read_tag(addr, tag, plc_type="CLX"): - """Read a tag from the PLC.""" - direct = plc_type == "Micro800" - clx = ClxDriver() - try: - if clx.open(addr, direct_connection=direct): - try: - val = clx.read_tag(tag) - clx.close() - return val - except DataError as err: - clx.close() - time.sleep(TAG_DATAERROR_SLEEPTIME) - log.error("Data Error during readTag({}, {}): {}".format(addr, tag, err)) - except CommError: - # err = c.get_status() - clx.close() - log.error("Could not connect during readTag({}, {})".format(addr, tag)) - except AttributeError as err: - clx.close() - log.error("AttributeError during readTag({}, {}): \n{}".format(addr, tag, err)) - clx.close() - return False - - -def read_array(addr, tag, start, end, plc_type="CLX"): - """Read an array from the PLC.""" - direct = plc_type == "Micro800" - clx = ClxDriver() - if clx.open(addr, direct_connection=direct): - arr_vals = [] - try: - for i in range(start, end): - tag_w_index = tag + "[{}]".format(i) - val = clx.read_tag(tag_w_index) - arr_vals.append(round(val[0], 4)) - if arr_vals: - clx.close() - return arr_vals - else: - log.error("No length for {}".format(addr)) - clx.close() - return False - except Exception: - log.error("Error during readArray({}, {}, {}, {})".format(addr, tag, start, end)) - err = clx.get_status() - clx.close() - log.error(err) - clx.close() - - -def write_tag(addr, tag, val, plc_type="CLX"): - """Write a tag value to the PLC.""" - direct = plc_type == "Micro800" - clx = ClxDriver() - try: - if clx.open(addr, direct_connection=direct): - try: - initial_val = clx.read_tag(tag) - write_status = clx.write_tag(tag, val, initial_val[1]) - clx.close() - return write_status - except DataError as err: - clx_err = clx.get_status() - clx.close() - log.error("--\nDataError during writeTag({}, {}, {}, plc_type={}) -- {}\n{}\n".format(addr, tag, val, plc_type, err, clx_err)) - - except CommError as err: - clx_err = clx.get_status() - log.error("--\nCommError during write_tag({}, {}, {}, plc_type={})\n{}\n--".format(addr, tag, val, plc_type, err)) - clx.close() - return False - - -class Channel(object): - """Holds the configuration for a Meshify channel.""" - - def __init__(self, mesh_name, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False): - """Initialize the channel.""" - self.mesh_name = mesh_name - self.data_type = data_type - self.last_value = None - self.value = None - self.last_send_time = 0 - self.chg_threshold = chg_threshold - self.guarantee_sec = guarantee_sec - self.map_ = map_ - self.write_enabled = write_enabled - - def __str__(self): - """Create a string for the channel.""" - return "{}\nvalue: {}, last_send_time: {}".format(self.mesh_name, self.value, self.last_send_time) - - def check(self, new_value, force_send=False): - """Check to see if the new_value needs to be stored.""" - send_needed = False - send_reason = "" - if self.data_type == 'BOOL' or self.data_type == 'STRING' or type(new_value) == str: - if self.last_send_time == 0: - send_needed = True - send_reason = "no send time" - elif self.value is None: - send_needed = True - send_reason = "no value" - elif self.value != new_value: - if self.map_: - if not self.value == self.map_[new_value]: - send_needed = True - send_reason = "value change" - else: - send_needed = True - send_reason = "value change" - elif (time.time() - self.last_send_time) > self.guarantee_sec: - send_needed = True - send_reason = "guarantee sec" - elif force_send: - send_needed = True - send_reason = "forced" - else: - if self.last_send_time == 0: - send_needed = True - send_reason = "no send time" - elif self.value is None: - send_needed = True - send_reason = "no value" - elif abs(self.value - new_value) > self.chg_threshold: - send_needed = True - send_reason = "change threshold" - elif (time.time() - self.last_send_time) > self.guarantee_sec: - send_needed = True - send_reason = "guarantee sec" - elif force_send: - send_needed = True - send_reason = "forced" - if send_needed: - self.last_value = self.value - if self.map_: - try: - self.value = self.map_[new_value] - except KeyError: - log.error("Cannot find a map value for {} in {} for {}".format(new_value, self.map_, self.mesh_name)) - self.value = new_value - else: - self.value = new_value - self.last_send_time = time.time() - log.info("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) - return send_needed - - def read(self): - """Read the value.""" - pass - - -def identity(sent): - """Return exactly what was sent to it.""" - return sent - -def volume_units(vunit): - units = { - 0: "cm cubed/s", - 1: "cm cubed/min", - 2: "cm cubed/h", - 3: "cm cubed/d", - 4: "dm cubed/s", - 5: "dm cubed/min", - 6: "dm cubed/h", - 7: "dm cubed/d", - 8: "m cubed/s", - 9: "m cubed/min", - 10: "m cubed/h", - 11: "m cubed/d", - 12: "ml/s", - 13: "ml/min", - 14: "ml/h", - 15: "ml/d", - 16: "l/s", - 17: "l/min", - 18: "l/h (+)", - 19: "l/d", - 20: "hl/s", - 21: "hl/min", - 22: "hl/h", - 23: "hl/d", - 24: "Ml/s", - 25: "Ml/min", - 26: "Ml/h", - 27: "Ml/d", - 32: "af/s", - 33: "af/min", - 34: "af/h", - 35: "af/d", - 36: "ft cubed/s", - 37: "ft cubed/min", - 38: "ft cubed/h", - 39: "ft cubed/d", - 40: "fl oz/s (us)", - 41: "fl oz/min (us)", - 42: "fl oz/h (us)", - 43: "fl oz/d (us)", - 44: "gal/s (us)", - 45: "gal/min (us)", - 46: "gal/h (us)", - 47: "gal/d (us)", - 48: "Mgal/s (us)", - 49: "Mgal/min (us)", - 50: "Mgal/h (us)", - 51: "Mgal/d (us)", - 52: "bbl/s (us;liq.)", - 53: "bbl/min (us;liq.)", - 54: "bbl/h (us;liq.)", - 55: "bbl/d (us;liq.)", - 56: "bbl/s (us;beer)", - 57: "bbl/min (us;beer)", - 58: "bbl/h (us;beer)", - 59: "bbl/d (us;beer)", - 60: "bbl/s (us;oil)", - 61: "bbl/min (us;oil)", - 62: "bbl/h (us;oil)", - 63: "bbl/d (us;oil)", - 64: "bbl/s (us;tank)", - 65: "bbl/min (us;tank)", - 66: "bbl/h (us;tank)", - 67: "bbl/d (us;tank)", - 68: "gal/s (imp)", - 69: "gal/min (imp)", - 70: "gal/h (imp)", - 71: "gal/d (imp)", - 72: "Mgal/s (imp)", - 73: "Mgal/min (imp)", - 74: "Mgal/h (imp)", - 75: "Mgal/d (imp)", - 76: "bbl/s (imp;beer)", - 77: "bbl/min (imp;beer)", - 78: "bbl/h (imp;beer)", - 79: "bbl/d (imp;beer)", - 80: "bbl/s (imp;oil)", - 81: "bbl/min (imp;oil)", - 82: "bbl/h (imp;oil)", - 83: "bbl/d (imp;oil)", - 88: "kgal/s (us)", - 89: "kgal/min (us)", - 90: "kgal/h (us)", - 91: "kgal/d (us)", - 92: "MMft cubed/s", - 93: "MMft cubed/min", - 94: "MMft cubed/h", - 96: "Mft cubed/d" - } - return units[vunit] - -def totalizer_units(tunit): - - units = { - 0: "cm cubed", - 1: "dm cubed", - 2: "m cubed", - 3: "ml", - 4: "l", - 5: "hl", - 6: "Ml Mega", - 8: "af", - 9: "ft cubed", - 10: "fl oz (us)", - 11: "gal (us)", - 12: "Mgal (us)", - 13: "bbl (us;liq.)", - 14: "bbl (us;beer)", - 15: "bbl (us;oil)", - 16: "bbl (us;tank)", - 17: "gal (imp)", - 18: "Mgal (imp)", - 19: "bbl (imp;beer)", - 20: "bbl (imp;oil)", - 22: "kgal (us)", - 23: "Mft cubed", - 50: "g", - 51: "kg", - 52: "t", - 53: "oz", - 54: "lb", - 55: "STon", - 100: "Nl", - 101: "Nm cubed", - 102: "Sm cubed", - 103: "Sft cubed", - 104: "Sl", - 105: "Sgal (us)", - 106: "Sbbl (us;liq.)", - 107: "Sgal (imp)", - 108: "Sbbl (us;oil)", - 109: "MMSft cubed", - 110: "Nhl", - 251: "None" - } - return units[tunit] - -def int_to_bits(n,x): - return pad_to_x([int(digit) for digit in bin(n)[2:]],x) # [2:] to chop off the "0b" part - -def pad_to_x(n,x): - while len(n) < x: - n = [0] + n - return n - -def status_codes(n): - - status_array = int_to_bits(n,16) - status_low = { - 0: "Stopped;", - 1: "Operating in Forward;", - 2: "Operating in Reverse;", - 3: "DC operating;" - } - status_mid = { - 0: "", - 1: "Speed searching;", - 2: "Accelerating;", - 3: "At constant speed;", - 4: "Decelerating;", - 5: "Decelerating to stop;", - 6: "H/W OCS;", - 7: "S/W OCS;", - 8: "Dwell operating;" - } - status_high = { - 0: "Normal state", - 4: "Warning occurred", - 8: "Fault occurred" - } - values = { - 0: 8, - 1: 4, - 2: 2, - 3: 1 - } - - stats_low = status_array[12:] - stats_mid = status_array[8:12] - stats_high = status_array[:4] - low = 0 - mid = 0 - high = 0 - for x in range(4): - if stats_low[x] == 1: - low = low + values[x] - if stats_mid[x] == 1: - mid = mid + values[x] - if stats_high[x] == 1: - high = high + values[x] - - return status_low[low] + " " + status_mid[mid] + ' ' + status_high[high] - -def fault_code_a(n): - - fault_code_array = int_to_bits(n,16) - - """ fault = { - 0: "OCT", - 1: "OVT", - 2: "EXT-A", - 3: "EST", - 4: "COL", - 5: "GFT", - 6: "OHT", - 7: "ETH", - 8: "OLT", - 9: "Reserved", - 10: "EXT-B", - 11: "EEP", - 12: "FAN", - 13: "POT", - 14: "IOLT", - 15: "LVT" - } """ - fault = { - 0: "Overload Trip", - 1: "Underload Trip", - 2: "Inverter Overload Trip", - 3: "E-Thermal Trip", - 4: "Ground Fault Trip", - 5: "Output Image Trip", - 6: "Inmput Imaging Trip", - 7: "Reserved", - 8: "Reserved", - 9: "NTC Trip", - 10: "Overcurrent Trip", - 11: "Overvoltage Trip", - 12: "External Trip", - 13: "Arm Short", - 14: "Over Heat Trip", - 15: "Fuse Open Trip" - } - - faults = [] - counter = 15 - for x in range(16): - if fault_code_array[x] == 1: - faults = [fault[counter]] + faults - counter = counter - 1 - return ' '.join(faults) - -def fault_code_b(n): - - fault_code_array = int_to_bits(n,8) - - """ fault = { - 0: "COM", - 1: "Reserved", - 2: "NTC", - 3: "REEP", - 4: "OC2", - 5: "NBR", - 6: "SAFA", - 7: "SAFB" - } """ - fault = { - 0: "Reserved", - 1: "Reserved", - 2: "Reserved", - 3: "FAN Trip", - 4: "Reserved", - 5: "Reserved", - 6: "Pre PID Fail", - 7: "Bad contact at basic I/O board", - 8: "External Brake Trip", - 9: "No Motor Trip", - 10: "Bad Option Card", - 11: "Reserved", - 12: "Reserved", - 13: "Reserved", - 14: "Pre Over Heat Trip", - 15: "Reserved" - } - - faults = [] - counter = 7 - for x in range(8): - if fault_code_array[x] == 1: - faults = [fault[counter]] + faults - counter = counter - 1 - return ' '.join(faults) - -class ModbusChannel(Channel): - """Modbus channel object.""" - - def __init__(self, mesh_name, register_number, data_type, chg_threshold, guarantee_sec, channel_size=1, map_=False, write_enabled=False, transform_fn=identity, unit_number=1, scaling=0): - """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 - self.last_send_time = 0 - self.chg_threshold = chg_threshold - self.guarantee_sec = guarantee_sec - self.map_ = map_ - self.write_enabled = write_enabled - self.transform_fn = transform_fn - self.unit_number = unit_number - self.instrument = minimalmodbus.Instrument('/dev/ttyS0', self.unit_number) - self.scaling= scaling - - def read(self): - """Return the transformed read value.""" - if self.data_type == "FLOAT": - try: - read_value = self.instrument.read_float(self.register_number,4,self.channel_size) - except IOError as e: - log.info(e) - return None - - elif self.data_type == "INTEGER" or self.data_type == "STRING": - try: - read_value = self.instrument.read_register(self.register_number, self.scaling, 4) - except IOError as e: - log.info(e) - return None - read_value = self.transform_fn(read_value) - return read_value - - def write(self, value): - """Write a value to a register""" - if self.data_type == "FLOAT": - value = float(value) - elif self.data_type == "INTEGER": - value = int(value) - else: - value = str(value) - try: - self.instrument.write_register(self.register_number,value, self.scaling, 16 if self.channel_size > 1 else 6 ) - return True - except Exception as e: - log.info("Failed to write value: {}".format(e)) - return False - - -class PLCChannel(Channel): - """PLC Channel Object.""" - - def __init__(self, ip, mesh_name, plc_tag, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False, plc_type='CLX'): - """Initialize the channel.""" - super(PLCChannel, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled) - self.plc_ip = ip - self.mesh_name = mesh_name - self.plc_tag = plc_tag - self.data_type = data_type - self.last_value = None - self.value = None - self.last_send_time = 0 - self.chg_threshold = chg_threshold - self.guarantee_sec = guarantee_sec - self.map_ = map_ - self.write_enabled = write_enabled - self.plc_type = plc_type - - def read(self): - """Read the value.""" - plc_value = None - if self.plc_tag and self.plc_ip: - read_value = read_tag(self.plc_ip, self.plc_tag, plc_type=self.plc_type) - if read_value: - plc_value = read_value[0] - - 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.""" - super(BoolArrayChannels, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled) - self.plc_ip = ip - self.mesh_name = mesh_name - self.plc_tag = plc_tag - self.data_type = data_type - self.last_value = None - self.value = None - self.last_send_time = 0 - self.chg_threshold = chg_threshold - self.guarantee_sec = guarantee_sec - self.map_ = map_ - self.write_enabled = write_enabled - - def compare_values(self, new_val_dict): - """Compare new values to old values to see if the values need storing.""" - send = False - for idx in new_val_dict: - try: - if new_val_dict[idx] != self.last_value[idx]: - send = True - except KeyError: - log.error("Key Error in self.compare_values for index {}".format(idx)) - send = True - return send - - def read(self, force_send=False): - """Read the value and check to see if needs to be stored.""" - send_needed = False - send_reason = "" - if self.plc_tag: - val = read_tag(self.plc_ip, self.plc_tag) - if val: - bool_arr = binarray(val[0]) - new_val = {} - for idx in self.map_: - try: - new_val[self.map_[idx]] = bool_arr[idx] - except KeyError: - log.error("Not able to get value for index {}".format(idx)) - - if self.last_send_time == 0: - send_needed = True - send_reason = "no send time" - elif self.value is None: - send_needed = True - send_reason = "no value" - elif self.compare_values(new_val): - send_needed = True - send_reason = "value change" - elif (time.time() - self.last_send_time) > self.guarantee_sec: - send_needed = True - send_reason = "guarantee sec" - elif force_send: - send_needed = True - send_reason = "forced" - - if send_needed: - self.value = new_val - self.last_value = self.value - self.last_send_time = time.time() - log.info("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) - return send_needed \ No newline at end of file diff --git a/piflow/VFD525/PiFlow.py b/piflow/VFD525/PiFlow.py deleted file mode 100644 index 297c819..0000000 --- a/piflow/VFD525/PiFlow.py +++ /dev/null @@ -1,452 +0,0 @@ -"""Driver for PiFlow""" -import os -import threading -import json -import time -from random import randint -from datetime import datetime as dt -from device_base import deviceBase -import persistence -from utilities import get_public_ip_address, get_private_ip_address -from file_logger import filelogger as log - -_ = None -os.system('sudo timedatectl set-timezone America/Chicago') -log.info("PiFlow startup") - -# GLOBAL VARIABLES -WAIT_FOR_CONNECTION_SECONDS = 5 -IP_CHECK_PERIOD = 60 - - -# PERSISTENCE FILE -PERSIST = persistence.load('persist.json') -if not PERSIST: - PERSIST = { - 'flowmeter': 247, - 'drive': 1, - 'isVFD': False, - 'drive_enabled': True, - 'plc_ip': '192.168.1.12', - 'yesterday_totalizer_1': dt.today().day, - 'yesterday_totalizer_2': dt.today().day, - 'yesterday_totalizer_3': dt.today().day, - 'yesterday_total_totalizer_1': 0, - 'yesterday_total_midnight_totalizer_1': 0, - 'yesterday_total_totalizer_2': 0, - 'yesterday_total_midnight_totalizer_2': 0, - 'yesterday_total_totalizer_3': 0, - 'yesterday_total_midnight_totalizer_3': 0 - } - persistence.store(PERSIST, 'persist.json') - -drive_enabled = PERSIST['drive_enabled'] -try: - isVFD = PERSIST['isVFD'] -except: - PERSIST['isVFD'] = False - isVFD = PERSIST['isVFD'] - persistence.store(PERSIST) - -try: - plc_ip = PERSIST['plc_ip'] -except: - PERSIST['plc_ip'] = '192.168.1.12' - plc_ip = PERSIST['plc_ip'] - persistence.store(PERSIST) - -from Tags import tags - -CHANNELS = tags - -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 = "25" - self.finished = threading.Event() - self.force_send = False - self.public_ip_address = "" - self.private_ip_address = "" - self.public_ip_address_last_checked = 0 - self.status = "" - self.alarm = "" - 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("PiFlow driver will start in {} seconds".format(WAIT_FOR_CONNECTION_SECONDS - i)) - time.sleep(1) - log.info("BOOM! Starting PiFlow driver...") - - #self._check_watchdog() - self._check_ip_address() - - self.nodes["PiFlow_0199"] = self - - send_loops = 0 - - while True: - now = time.time() - if self.force_send: - log.warning("FORCE SEND: TRUE") - if isVFD: - status = {} - for chan in CHANNELS[:24]: #build status/alarm strings - try: - val = chan.read() - chan.check(val, self.force_send) - status[chan.mesh_name] = chan.value - except Exception as e: - log.warning("An error occured in status check: {}".format(e)) - try: - self.sendStatus(status) - except Exception as e: - log.warning("An error occured in send status: {}".format(e)) - for chan in CHANNELS[24:]: - try: - val = chan.read() - if chan.mesh_name in ['totalizer_1','totalizer_2','totalizer_3']: - right_now = dt.today() - today_total, yesterday_total = self.totalize(val, PERSIST['yesterday_'+chan.mesh_name], right_now.day, right_now.hour, right_now.minute, PERSIST['yesterday_total_midnight_'+chan.mesh_name], PERSIST['yesterday_total_'+chan.mesh_name], chan.mesh_name) - if chan.check(val, self.force_send): - self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'PiFlow') - self.sendtodbDev(1,"today_"+chan.mesh_name, today_total,0,'PiFlow') - self.sendtodbDev(1,"yesterday_"+chan.mesh_name, yesterday_total,0,'PiFlow') - self.sendtodbDev(1, chan.mesh_name + "_units", "BBL",0,'PiFlow') - else: - if chan.check(val, self.force_send): - self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'PiFlow') - except Exception as e: - log.warning("An error occured in data collection: {}".format(e)) - else: - for chan in CHANNELS: - try: - for x in range(3): - val = chan.read() - if not val == None: - break - if val == None: - log.info("No modbus read sending previous value") - val = chan.value - if chan.mesh_name in ['totalizer_1','totalizer_2','totalizer_3']: - right_now = dt.today() - today_total, yesterday_total = self.totalize(val, PERSIST['yesterday_'+chan.mesh_name], right_now.day, right_now.hour, right_now.minute, PERSIST['yesterday_total_midnight_'+chan.mesh_name], PERSIST['yesterday_total_'+chan.mesh_name], chan.mesh_name) - if chan.check(val, self.force_send): - self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'PiFlow') - self.sendtodbDev(1,"today_"+chan.mesh_name, today_total,0,'PiFlow') - self.sendtodbDev(1,"yesterday_"+chan.mesh_name, yesterday_total,0,'PiFlow') - elif chan.mesh_name == "volume_flow" and not PERSIST['drive_enabled']: - if chan.check(val, self.force_send): - self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'PiFlow') - if chan.value > 0: - self.sendtodbDev(1, "run_status", "Running", 0, 'PiFlow') - else: - self.sendtodbDev(1,"run_status", "Stopped", 0, 'PiFlow') - else: - if chan.check(val, self.force_send): - self.sendtodbDev(1, chan.mesh_name, chan.value, 0, 'PiFlow') - - except Exception as e: - log.warning("An error occured: {}".format(e)) - time.sleep(3) - - - # print("PiFlow 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() - time.sleep(10) - - 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() - test_public_ip = test_public_ip[:-1] - test_private_ip = get_private_ip_address() - if not test_public_ip == self.public_ip_address and not test_public_ip == "0.0.0.0": - self.sendtodbDev(1, 'public_ip_address', test_public_ip, 0, 'PiFlow') - self.public_ip_address = test_public_ip - if not test_private_ip == self.private_ip_address: - self.sendtodbDev(1, 'private_ip_address', test_private_ip, 0, 'PiFlow') - self.private_ip_address = test_private_ip - - def PiFlow_sync(self, name, value): - """Sync all data from the driver.""" - self.force_send = True - # self.sendtodb("log", "synced", 0) - return True - - def PiFlow_flowmeternumber(self, name, unit_number): - """Change the unit number for the PiFlow flow meter""" - unit_number = int(unit_number) - if drive_enabled: - for chan in CHANNELS[0:8]: - chan.unit_number = unit_number - PERSIST['flowmeter'] = unit_number - persistence.store(PERSIST, 'persist.json') - return True - else: - for chan in CHANNELS: - chan.unit_number = unit_number - PERSIST['flowmeter'] = unit_number - persistence.store(PERSIST, 'persist.json') - self.sendtodbDev(1, 'flowmeternumber', unit_number, 0,'PiFlow') - return True - return False - - def PiFlow_drivenumber(self, name, unit_number): - """Change the unit number for the PiFlow drive""" - unit_number = int(unit_number) - for chan in CHANNELS[8:]: - chan.unit_number = unit_number - - PERSIST['drive'] = unit_number - persistence.store(PERSIST, 'persist.json') - self.sendtodbDev(1, 'drivenumber', unit_number, 0,'PiFlow') - return True - - def PiFlow_reboot(self, name, value): - os.system('reboot') - return True - - def PiFlow_drive_enabled(self, name, value): - value = int(value) - if value == 1: - PERSIST['drive_enabled'] = True - else: - PERSIST['drive_enabled'] = False - - persistence.store(PERSIST, 'persist.json') - self.sendtodbDev(1, 'drive_enabled', value, 0,'PiFlow') - return True - - def PiFlow_write(self, name, value): - """Write a value to the device via modbus""" - new_val = json.loads(str(value).replace("'", '"')) - addr_n = int(new_val['addr']) - reg_n = int(new_val['reg']) - val_n = new_val['val'] - for chan in CHANNELS: - if chan.unit_number == addr_n and chan.register_number == reg_n: - write_res = chan.write(val_n) - - log.info("Result of PiFlow_write(self, {}, {}) = {}".format(name, value, write_res)) - return write_res - - def totalize(self,val, yesterday, day, hour, minute, yesterday_total_midnight, yesterday_total,channel): - if (yesterday_total == 0 and yesterday_total_midnight == 0) or (yesterday_total == None or yesterday_total_midnight == None): - yesterday_total_midnight = val - PERSIST['yesterday_total_midnight_'+channel] = yesterday_total_midnight - persistence.store(PERSIST, 'persist.json') - today_total = val - yesterday_total_midnight - if hour == 0 and minute == 0 and not(day == yesterday): - yesterday_total = today_total - yesterday_total_midnight = val - today_total = val - yesterday_total_midnight - yesterday = day - PERSIST['yesterday_'+channel] = yesterday - PERSIST['yesterday_total_'+channel] = yesterday_total - PERSIST['yesterday_total_midnight_'+channel] = yesterday_total_midnight - persistence.store(PERSIST,'persist.json') - - return today_total,yesterday_total - - def sendStatus(self,status): - status_string = "" - - fault_codes = { - 0: "", - 2: "Auxiliary Input", - 3: "Power Loss", - 4: "UnderVoltage", - 5: "OverVoltage", - 7: "Motor Overload", - 8: "Heatsink OvrTemp", - 9: "Thermister OvrTemp", - 10: "DynBrake OverTemp", - 12: "HW OverCurrent", - 13: "Ground Fault", - 14: "Ground Warning", - 15: "Load Loss", - 17: "Input Phase Loss", - 18: "Motor PTC Trip", - 19: "Task Overrun", - 20: "TorqPrv Spd Band", - 21: "Output PhaseLoss", - 24: "Decel Inhibit", - 25: "OverSpeed Limit", - 26: "Brake Slipped", - 27: "Torq Prove Cflct", - 28: "TP Encls Config", - 29: "Analog In Loss", - 33: "AuRsts Exhausted", - 35: "IPM OverCurrent", - 36: "SW OverCurrent", - 38: "Phase U to Grnd", - 39: "Phase V to Grnd", - 40: "Phase W to Grnd", - 41: "Phase UV Short", - 42: "Phase VW Short", - 43: "Phase WU Short", - 44: "Phase UNegToGrnd", - 45: "Phase VNegToGrnd", - 46: "Phase WNegToGrnd", - 48: "System Defaulted", - 49: "Drive Powerup", - 51: "Clr Fault Queue", - 55: "Ctrl Bd Overtemp", - 59: "Invalid Code", - 61: "Shear Pin 1", - 62: "Shear Pin 2", - 64: "Drive Overload", - 67: "Pump Off", - 71: "Port 1 Adapter", - 72: "Port 2 Adapter", - 73: "Port 3 Adapter", - 74: "Port 4 Adapter", - 75: "Port 5 Adapter", - 76: "Port 6 Adapter", - 77: "IR Volts Range", - 78: "FluxAmpsRef Rang", - 79: "Excessive Load", - 80: "AutoTune Aborted", - 81: "Port 1 DPI Loss", - 82: "Port 2 DPI Loss", - 83: "Port 3 DPI Loss", - 84: "Port 4 DPI Loss", - 85: "Port 5 DPI Loss", - 86: "Port 6 DPI Loss", - 87: "Ixo VoltageRange", - 91: "Pri VelFdbk Loss", - 93: "Hw Enable Check", - 94: "Alt VelFdbk Loss", - 95: "Aux VelFdbk Loss", - 96: "PositionFdbkLoss", - 97: "Auto Tach Switch", - 100: "Parameter Chksum", - 101: "PwrDn NVS Blank", - 102: "NVS Not Blank", - 103: "PwrDn Nvs Incomp", - 104: "Pwr Brd Checksum", - 106: "Incompat MCB-PB", - 107: "Replaced MCB-PB", - 108: "Anlg Cal Chksum", - 110: "Ivld Pwr Bd Data", - 111: "PwrBd Invalid ID", - 112: "PwrBd App MinVer", - 113: "Tracking DataErr", - 115: "PwrDn Table Full", - 116: "PwrDnEntry2Large", - 117: "PwrDn Data Chksm", - 118: "PwrBd PwrDn Chks", - 124: "App ID Changed", - 125: "Using Backup App", - 134: "Start on PowerUp", - 137: "Ext Prechrg Err", - 138: "Precharge Open", - 141: "Autn Enc Angle", - 142: "Autn Spd Rstrct", - 143: "AutoTune CurReg", - 144: "AutoTune Inertia", - 145: "AutoTune Travel", - 13037: "Net IO Timeout" - } - - if status['vfd_active'] == "Stopped": - status_string = status_string + status['vfd_active'] + "; " + status['vfd_ready'] - else: - status_string = status_string + status['vfd_active'] - if status['vfd_rev']: - status_string = status_string + '; ' + status['vfd_rev'] - if status['vfd_fwd']: - status_string = status_string + '; ' + status['vfd_fwd'] - if status['vfd_atreference']: - status_string = status_string + '; ' + status['vfd_atreference'] - alarm_string = "" - if status['vfd_faulted'] == "Drive Faulted": - status_string = status_string + '; ' + status['vfd_faulted'] - if status['vfd_commloss']: - alarm_string = alarm_string + '; ' + status['vfd_commloss'] - if status['vfd_fbkalarm']: - alarm_string = alarm_string + '; ' + status['vfd_fbkalarm'] - if status['vfd_faultcode']: - alarm_string = alarm_string + '; ' + "Fault: {} Fault code: {}".format(fault_codes[status['vfd_faultcode']],str(status['vfd_faultcode'])) - if status['minspeedalarm']: - alarm_string = alarm_string + '; ' + status['minspeedalarm'] - if status['pumpedoff']: - alarm_string = alarm_string + '; ' + status['pumpedoff'] - if status['lockedout']: - alarm_string = alarm_string + '; ' + status['lockedout'] - if status['tubingpressurehi']: - alarm_string = alarm_string + '; ' + status['tubingpressurehi'] - if status['tubingpressurehihi']: - alarm_string = alarm_string + '; ' + status['tubingpressurehihi'] - if status['tubingpressurelo']: - alarm_string = alarm_string + '; ' + status['tubingpressurelo'] - if status['tubingpressurelolo']: - alarm_string = alarm_string + '; ' + status['tubingpressurelolo'] - if status['flowmeterhihi']: - alarm_string = alarm_string + '; ' + status['flowmeterhihi'] - if status['flowmeterhi']: - alarm_string = alarm_string + '; ' + status['flowmeterhi'] - if status['flowmeterlolo']: - alarm_string = alarm_string + '; ' + status['flowmeterlolo'] - if status['flowmeterlo']: - alarm_string = alarm_string + '; ' + status['flowmeterlo'] - if status['fluidlevellolo']: - alarm_string = alarm_string + '; ' + status['fluidlevellolo'] - if status['fluidlevello']: - alarm_string = alarm_string + '; ' + status['fluidlevello'] - if status['fluidlevelhi']: - alarm_string = alarm_string + '; ' + status['fluidlevelhi'] - if status['fluidlevelhihi']: - alarm_string = alarm_string + '; ' + status['fluidlevelhihi'] - try: - if status_string and status_string[0] == '; ': - status_string = status_string[1:] - if status_string and status_string[-1] == '; ': - status_string = status_string[:-1] - if alarm_string and alarm_string[0] == '; ': - alarm_string = alarm_string[1:] - if alarm_string and alarm_string[-1] == '; ': - alarm_string = alarm_string[:-1] - except Exception as e: - log.warning("Error in send status semicolon: {}".format(e)) - - if self.status != status_string: - self.status = status_string - log.info("Sending {} for {}".format(status_string, 'run_status')) - self.sendtodbDev(1, 'run_status', status_string, 0, 'PiFlow') - if self.alarm != alarm_string: - self.alarm = alarm_string - log.info("Sending {} for {}".format(alarm_string, 'fault_a')) - self.sendtodbDev(1, 'fault_a', alarm_string, 0 , 'PiFlow') - - - - \ No newline at end of file diff --git a/piflow/VFD525/Tags.py b/piflow/VFD525/Tags.py deleted file mode 100644 index 4a98d54..0000000 --- a/piflow/VFD525/Tags.py +++ /dev/null @@ -1,90 +0,0 @@ -from Channel import PLCChannel,Channel, ModbusChannel, status_codes, fault_code_a, fault_code_b, volume_units, totalizer_units -import persistence - -PERSIST = persistence.load('persist.json') -flowmeter_unit_number = PERSIST['flowmeter'] -drive_enabled = PERSIST['drive_enabled'] -isVFD = PERSIST['isVFD'] -if drive_enabled: - drive_unit_number = PERSIST['drive'] -try: - plc_ip = PERSIST['plc_ip'] -except: - PERSIST['plc_ip'] = '192.168.1.12' - persistence.store(PERSIST) -if isVFD: - tags = [ - PLCChannel(plc_ip,'vfd_atreference','sts_VFD_AtReference','BOOL',0,3600,map_={0: "", 1: "At speed"},plc_type='Micro800'), - PLCChannel(plc_ip,'vfd_rev','sts_VFD_REV','BOOL',0,3600,map_={0: "", 1: "Operating in Reverse"},plc_type='Micro800'), - PLCChannel(plc_ip,'vfd_fwd','sts_VFD_FWD','BOOL',0,3600,map_={0: "", 1: "Operating in Forward"},plc_type='Micro800'), - PLCChannel(plc_ip,'vfd_active','sts_VFD_Active','BOOL',0,3600,map_={0: "Stopped", 1: "Running"},plc_type='Micro800'), - PLCChannel(plc_ip,'vfd_ready','sts_VFD_Ready','BOOL',0,3600,map_={0: "Drive Not Ready", 1: "Drive Ready"},plc_type='Micro800'), - PLCChannel(plc_ip,'vfd_faultcode','sts_VFD_FaultCode','REAL',0,3600, plc_type='Micro800'), - PLCChannel(plc_ip,'vfd_faulted','AL0_VFD','BOOL',0,3600,map_={0: "", 1: "Drive Faulted"},plc_type='Micro800'), - PLCChannel(plc_ip,'vfd_commloss','AL0_VFDComLoss','BOOL',0,3600,map_={0: "", 1: "Drive Comms Loss"},plc_type='Micro800'), - PLCChannel(plc_ip,'vfd_fbkalarm','AL0_VFD_FBAlarm','BOOL',0,3600,map_={0: "", 1: "Drive Lost Feedback"},plc_type='Micro800'), - PLCChannel(plc_ip,'tubingpressurehi','AL0_TubingPressureHi','BOOL',0,3600,map_={0: "", 1: "High Tubing Pressure"},plc_type='Micro800'), - PLCChannel(plc_ip,'tubingpressurehihi','AL0_TubingPressureHiHi','BOOL',0,3600,map_={0: "", 1: "High High Tubing Pressure"},plc_type='Micro800'), - PLCChannel(plc_ip,'tubingpressurelo','AL0_TubingPressureLo','BOOL',0,3600,map_={0: "", 1: "Low Tubing Pressure"},plc_type='Micro800'), - PLCChannel(plc_ip,'tubingpressurelolo','AL0_TubingPressureLoLo','BOOL',0,3600,map_={0: "", 1: "Low Low Tubing Pressure"},plc_type='Micro800'), - PLCChannel(plc_ip,'flowmeterhihi','AL0_FlowMeterHiHi','BOOL',0,3600,map_={0: "", 1: "High High FM Flow Rate"},plc_type='Micro800'), - PLCChannel(plc_ip,'flowmeterhi','AL0_FlowMeterHi','BOOL',0,3600,map_={0: "", 1: "High FM Flow Rate"},plc_type='Micro800'), - PLCChannel(plc_ip,'flowmeterlolo','AL0_FlowMeterLoLo','BOOL',0,3600,map_={0: "", 1: "Low Low FM Flow Rate"},plc_type='Micro800'), - PLCChannel(plc_ip,'flowmeterlo','AL0_FlowMeterLo','BOOL',0,3600,map_={0: "", 1: "Low FM Flow Rate"},plc_type='Micro800'), - PLCChannel(plc_ip,'minspeedalarm','AL0_MinSpeedAlarm','BOOL',0,3600,map_={0: "", 1: "Drive not able to maintain min speed"},plc_type='Micro800'), - PLCChannel(plc_ip,'pumpedoff','AL0_PumpedOff','BOOL',0,3600,map_={0: "", 1: "Pumped Off"},plc_type='Micro800'), - PLCChannel(plc_ip,'fluidlevellolo','AL0_FluidLevelLoLo','BOOL',0,3600,map_={0: "", 1: "Low Low Fluid Level"},plc_type='Micro800'), - PLCChannel(plc_ip,'fluidlevello','AL0_FluidLevelLo','BOOL',0,3600,map_={0: "", 1: "Low Fluid Level"},plc_type='Micro800'), - PLCChannel(plc_ip,'fluidlevelhi','AL0_FluidLevelHi','BOOL',0,3600,map_={0: "", 1: "High Fluid Level"},plc_type='Micro800'), - PLCChannel(plc_ip,'fluidlevelhihi','AL0_FluidLevelHiHi','BOOL',0,3600,map_={0: "", 1: "High High Fluid Level"},plc_type='Micro800'), - PLCChannel(plc_ip,'lockedout','AlarmLockOut','BOOL',0,3600,map_={0: "", 1: "Locked Out Repeated Alarms"},plc_type='Micro800'), - PLCChannel(plc_ip,'volume_flow','Val_FlowmeterFR','REAL',5,3600,plc_type='Micro800'), - PLCChannel(plc_ip,'current','val_VFD_OutputCurrent','REAL',5,3600,plc_type='Micro800'), - PLCChannel(plc_ip,'frequency','val_VFD_ActualSpeed','REAL',5,3600,plc_type='Micro800'), - PLCChannel(plc_ip,'pid_feedback','val_FluidLevel','REAL',5,3600,plc_type='Micro800'), - PLCChannel(plc_ip,'totalizer_1','Val_FlowMeterT1','REAL',5,3600,plc_type='Micro800'), - PLCChannel(plc_ip,'totalizer_2','Val_FlowMeterT2','REAL',5,3600,plc_type='Micro800'), - PLCChannel(plc_ip,'totalizer_3','Val_FlowMeterT3','REAL',5,3600,plc_type='Micro800'), - PLCChannel(plc_ip,'volume_flow_units','CMD_FlowMeterUnit','BOOL',1,3600,map_={0: "GPM", 1: "BPD"},plc_type='Micro800') - ] -else: - if drive_enabled: - tags = [ - ModbusChannel('volume_flow', 3873, 'FLOAT', 10, 3600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_1', 2609, 'FLOAT', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_2', 2809, 'FLOAT', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_3', 3009, 'FLOAT', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('volume_flow_units', 2102, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=volume_units), - ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1,86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('run_status', 772, 'STRING', 0, 3600, channel_size=1, unit_number=drive_unit_number, transform_fn=status_codes), - ModbusChannel('frequency', 784, 'INTEGER', 2, 3600, channel_size=2, unit_number=drive_unit_number,scaling=2 ), - ModbusChannel('current', 783, 'INTEGER', 2, 3600, channel_size=2, unit_number=drive_unit_number,scaling=1 ), - ModbusChannel('fault_a', 815, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_a), - ModbusChannel('fault_b', 816, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_b), - ModbusChannel('pid_ref', 791, 'INTEGER', 5, 3600, channel_size=1, unit_number=drive_unit_number,scaling=1), - ModbusChannel('pid_feedback', 792, 'INTEGER', 5, 3600, channel_size=1, unit_number=drive_unit_number,scaling=1), - ModbusChannel('motor_rated_current', 4896, 'INTEGER', 300, 86400, channel_size=1, unit_number=drive_unit_number,scaling=1), - ModbusChannel('sleep_delay', 4924, 'INTEGER', 5, 86400, channel_size=1, unit_number=drive_unit_number, scaling=1) - ] - else: - tags = [ - ModbusChannel('volume_flow', 3873, 'FLOAT', 10, 3600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_1', 2609, 'FLOAT', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_2', 2809, 'FLOAT', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_3', 3009, 'FLOAT', 100, 3600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('volume_flow_units', 2102, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=volume_units), - ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1, 86400,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units) - ] - - - - - - - - - \ No newline at end of file diff --git a/piflow/VFD525/config.txt b/piflow/VFD525/config.txt deleted file mode 100644 index be442e9..0000000 --- a/piflow/VFD525/config.txt +++ /dev/null @@ -1,16 +0,0 @@ -{ - -"driverFileName":"PiFlow.py", -"deviceName":"piflow", -"driverId":"0280", -"releaseVersion":"25", -"files": { - "file1":"PiFlow.py", - "file2":"Channel.py", - "file3":"file_logger.py", - "file4":"Tags.py", - "file5":"utilities.py", - "file6":"persistence.py" - } - -} \ No newline at end of file diff --git a/piflow/VFD525/file_logger.py b/piflow/VFD525/file_logger.py deleted file mode 100644 index fd8c432..0000000 --- a/piflow/VFD525/file_logger.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Logging setup for PiFlow""" -import logging -from logging.handlers import RotatingFileHandler -import sys - -log_formatter = logging.Formatter('%(asctime)s %(levelname)s %(funcName)s(%(lineno)d) %(message)s') -log_file = './PiFlow.log' -my_handler = RotatingFileHandler(log_file, mode='a', maxBytes=500*1024, - backupCount=2, encoding=None, delay=0) -my_handler.setFormatter(log_formatter) -my_handler.setLevel(logging.INFO) -filelogger = logging.getLogger('PiFlow') -filelogger.setLevel(logging.INFO) -filelogger.addHandler(my_handler) - -console_out = logging.StreamHandler(sys.stdout) -console_out.setFormatter(log_formatter) -filelogger.addHandler(console_out) diff --git a/piflow/VFD525/utilities.py b/piflow/VFD525/utilities.py deleted file mode 100644 index f9b2081..0000000 --- a/piflow/VFD525/utilities.py +++ /dev/null @@ -1,71 +0,0 @@ -"""Utility functions for the driver.""" -import socket -import struct -import urllib -import contextlib -def get_private_ip_address(): - """Find the private IP Address of the host device.""" - try: - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.connect(("8.8.8.8", 80)) - ip_address = sock.getsockname()[0] - sock.close() - except Exception as e: - return e - - return ip_address - -def get_public_ip_address(): - ip_address = "0.0.0.0" - try: - with contextlib.closing(urllib.urlopen("httpd://checkip.amazonaws.com")) as url: - ip_address = url.read() - except Exception as e: - print("Could not resolve address: {}".format(e)) - return ip_address - return ip_address[:-1] - - -def int_to_float16(int_to_convert): - """Convert integer into float16 representation.""" - bin_rep = ('0' * 16 + '{0:b}'.format(int_to_convert))[-16:] - sign = 1.0 - if int(bin_rep[0]) == 1: - sign = -1.0 - exponent = float(int(bin_rep[1:6], 2)) - fraction = float(int(bin_rep[6:17], 2)) - - if exponent == float(0b00000): - return sign * 2 ** -14 * fraction / (2.0 ** 10.0) - elif exponent == float(0b11111): - if fraction == 0: - return sign * float("inf") - return float("NaN") - frac_part = 1.0 + fraction / (2.0 ** 10.0) - return sign * (2 ** (exponent - 15)) * frac_part - - -def ints_to_float(int1, int2): - """Convert 2 registers into a floating point number.""" - mypack = struct.pack('>HH', int1, int2) - f_unpacked = struct.unpack('>f', mypack) - print("[{}, {}] >> {}".format(int1, int2, f_unpacked[0])) - return f_unpacked[0] - - -def degf_to_degc(temp_f): - """Convert deg F to deg C.""" - return (temp_f - 32.0) * (5.0/9.0) - - -def degc_to_degf(temp_c): - """Convert deg C to deg F.""" - return temp_c * 1.8 + 32.0 - -def get_public_ip_address(): - try: - url = urllib.urlopen("http://checkip.amazonaws.com") - ip_address = url.read() - except Exception as e: - return e - return ip_address diff --git a/piflow/config.txt b/piflow/config.txt index aaedc0d..be442e9 100644 --- a/piflow/config.txt +++ b/piflow/config.txt @@ -3,7 +3,7 @@ "driverFileName":"PiFlow.py", "deviceName":"piflow", "driverId":"0280", -"releaseVersion":"20", +"releaseVersion":"25", "files": { "file1":"PiFlow.py", "file2":"Channel.py", diff --git a/piflow/v1/Channel.py b/piflow/v1/Channel.py deleted file mode 100644 index 48961c8..0000000 --- a/piflow/v1/Channel.py +++ /dev/null @@ -1,557 +0,0 @@ -"""Define Meshify channel class.""" -import time -from pycomm.ab_comm.clx import Driver as ClxDriver -from pycomm.cip.cip_base import CommError, DataError -from file_logger import filelogger as log -import minimalmodbus - -minimalmodbus.BAUDRATE = 9600 -minimalmodbus.STOPBITS = 1 - -TAG_DATAERROR_SLEEPTIME = 5 - -def binarray(intval): - """Split an integer into its bits.""" - bin_string = '{0:08b}'.format(intval) - bin_arr = [i for i in bin_string] - bin_arr.reverse() - return bin_arr - - -def read_tag(addr, tag, plc_type="CLX"): - """Read a tag from the PLC.""" - direct = plc_type == "Micro800" - clx = ClxDriver() - try: - if clx.open(addr, direct_connection=direct): - try: - val = clx.read_tag(tag) - return val - except DataError as err: - clx.close() - time.sleep(TAG_DATAERROR_SLEEPTIME) - log.error("Data Error during readTag({}, {}): {}".format(addr, tag, err)) - except CommError: - # err = c.get_status() - clx.close() - log.error("Could not connect during readTag({}, {})".format(addr, tag)) - except AttributeError as err: - clx.close() - log.error("AttributeError during readTag({}, {}): \n{}".format(addr, tag, err)) - clx.close() - return False - - -def read_array(addr, tag, start, end, plc_type="CLX"): - """Read an array from the PLC.""" - direct = plc_type == "Micro800" - clx = ClxDriver() - if clx.open(addr, direct_connection=direct): - arr_vals = [] - try: - for i in range(start, end): - tag_w_index = tag + "[{}]".format(i) - val = clx.read_tag(tag_w_index) - arr_vals.append(round(val[0], 4)) - if arr_vals: - return arr_vals - else: - log.error("No length for {}".format(addr)) - return False - except Exception: - log.error("Error during readArray({}, {}, {}, {})".format(addr, tag, start, end)) - err = clx.get_status() - clx.close() - log.error(err) - clx.close() - - -def write_tag(addr, tag, val, plc_type="CLX"): - """Write a tag value to the PLC.""" - direct = plc_type == "Micro800" - clx = ClxDriver() - try: - if clx.open(addr, direct_connection=direct): - try: - initial_val = clx.read_tag(tag) - write_status = clx.write_tag(tag, val, initial_val[1]) - return write_status - except DataError as err: - clx_err = clx.get_status() - clx.close() - log.error("--\nDataError during writeTag({}, {}, {}, plc_type={}) -- {}\n{}\n".format(addr, tag, val, plc_type, err, clx_err)) - - except CommError as err: - clx_err = clx.get_status() - log.error("--\nCommError during write_tag({}, {}, {}, plc_type={})\n{}\n--".format(addr, tag, val, plc_type, err)) - clx.close() - return False - - -class Channel(object): - """Holds the configuration for a Meshify channel.""" - - def __init__(self, mesh_name, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False): - """Initialize the channel.""" - self.mesh_name = mesh_name - self.data_type = data_type - self.last_value = None - self.value = None - self.last_send_time = 0 - self.chg_threshold = chg_threshold - self.guarantee_sec = guarantee_sec - self.map_ = map_ - self.write_enabled = write_enabled - - def __str__(self): - """Create a string for the channel.""" - return "{}\nvalue: {}, last_send_time: {}".format(self.mesh_name, self.value, self.last_send_time) - - def check(self, new_value, force_send=False): - """Check to see if the new_value needs to be stored.""" - send_needed = False - send_reason = "" - if self.data_type == 'BOOL' or self.data_type == 'STRING' or type(new_value) == str: - if self.last_send_time == 0: - send_needed = True - send_reason = "no send time" - elif self.value is None: - send_needed = True - send_reason = "no value" - elif self.value != new_value: - if self.map_: - if not self.value == self.map_[new_value]: - send_needed = True - send_reason = "value change" - else: - send_needed = True - send_reason = "value change" - elif (time.time() - self.last_send_time) > self.guarantee_sec: - send_needed = True - send_reason = "guarantee sec" - elif force_send: - send_needed = True - send_reason = "forced" - else: - if self.last_send_time == 0: - send_needed = True - send_reason = "no send time" - elif self.value is None: - send_needed = True - send_reason = "no value" - elif abs(self.value - new_value) > self.chg_threshold: - send_needed = True - send_reason = "change threshold" - elif (time.time() - self.last_send_time) > self.guarantee_sec: - send_needed = True - send_reason = "guarantee sec" - elif force_send: - send_needed = True - send_reason = "forced" - if send_needed: - self.last_value = self.value - if self.map_: - try: - self.value = self.map_[new_value] - except KeyError: - log.error("Cannot find a map value for {} in {} for {}".format(new_value, self.map_, self.mesh_name)) - self.value = new_value - else: - self.value = new_value - self.last_send_time = time.time() - log.info("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) - return send_needed - - def read(self): - """Read the value.""" - pass - - -def identity(sent): - """Return exactly what was sent to it.""" - return sent - -def volume_units(vunit): - units = { - 0: "cm cubed/s", - 1: "cm cubed/min", - 2: "cm cubed/h", - 3: "cm cubed/d", - 4: "dm cubed/s", - 5: "dm cubed/min", - 6: "dm cubed/h", - 7: "dm cubed/d", - 8: "m cubed/s", - 9: "m cubed/min", - 10: "m cubed/h", - 11: "m cubed/d", - 12: "ml/s", - 13: "ml/min", - 14: "ml/h", - 15: "ml/d", - 16: "l/s", - 17: "l/min", - 18: "l/h (+)", - 19: "l/d", - 20: "hl/s", - 21: "hl/min", - 22: "hl/h", - 23: "hl/d", - 24: "Ml/s", - 25: "Ml/min", - 26: "Ml/h", - 27: "Ml/d", - 32: "af/s", - 33: "af/min", - 34: "af/h", - 35: "af/d", - 36: "ft cubed/s", - 37: "ft cubed/min", - 38: "ft cubed/h", - 39: "ft cubed/d", - 40: "fl oz/s (us)", - 41: "fl oz/min (us)", - 42: "fl oz/h (us)", - 43: "fl oz/d (us)", - 44: "gal/s (us)", - 45: "gal/min (us)", - 46: "gal/h (us)", - 47: "gal/d (us)", - 48: "Mgal/s (us)", - 49: "Mgal/min (us)", - 50: "Mgal/h (us)", - 51: "Mgal/d (us)", - 52: "bbl/s (us;liq.)", - 53: "bbl/min (us;liq.)", - 54: "bbl/h (us;liq.)", - 55: "bbl/d (us;liq.)", - 56: "bbl/s (us;beer)", - 57: "bbl/min (us;beer)", - 58: "bbl/h (us;beer)", - 59: "bbl/d (us;beer)", - 60: "bbl/s (us;oil)", - 61: "bbl/min (us;oil)", - 62: "bbl/h (us;oil)", - 63: "bbl/d (us;oil)", - 64: "bbl/s (us;tank)", - 65: "bbl/min (us;tank)", - 66: "bbl/h (us;tank)", - 67: "bbl/d (us;tank)", - 68: "gal/s (imp)", - 69: "gal/min (imp)", - 70: "gal/h (imp)", - 71: "gal/d (imp)", - 72: "Mgal/s (imp)", - 73: "Mgal/min (imp)", - 74: "Mgal/h (imp)", - 75: "Mgal/d (imp)", - 76: "bbl/s (imp;beer)", - 77: "bbl/min (imp;beer)", - 78: "bbl/h (imp;beer)", - 79: "bbl/d (imp;beer)", - 80: "bbl/s (imp;oil)", - 81: "bbl/min (imp;oil)", - 82: "bbl/h (imp;oil)", - 83: "bbl/d (imp;oil)", - 88: "kgal/s (us)", - 89: "kgal/min (us)", - 90: "kgal/h (us)", - 91: "kgal/d (us)", - 92: "MMft cubed/s", - 93: "MMft cubed/min", - 94: "MMft cubed/h", - 96: "Mft cubed/d" - } - return units[vunit] - -def totalizer_units(tunit): - - units = { - 0: "cm cubed", - 1: "dm cubed", - 2: "m cubed", - 3: "ml", - 4: "l", - 5: "hl", - 6: "Ml Mega", - 8: "af", - 9: "ft cubed", - 10: "fl oz (us)", - 11: "gal (us)", - 12: "Mgal (us)", - 13: "bbl (us;liq.)", - 14: "bbl (us;beer)", - 15: "bbl (us;oil)", - 16: "bbl (us;tank)", - 17: "gal (imp)", - 18: "Mgal (imp)", - 19: "bbl (imp;beer)", - 20: "bbl (imp;oil)", - 22: "kgal (us)", - 23: "Mft cubed", - 50: "g", - 51: "kg", - 52: "t", - 53: "oz", - 54: "lb", - 55: "STon", - 100: "Nl", - 101: "Nm cubed", - 102: "Sm cubed", - 103: "Sft cubed", - 104: "Sl", - 105: "Sgal (us)", - 106: "Sbbl (us;liq.)", - 107: "Sgal (imp)", - 108: "Sbbl (us;oil)", - 109: "MMSft cubed", - 110: "Nhl", - 251: "None" - } - return units[tunit] - -def int_to_bits(n,x): - return pad_to_x([int(digit) for digit in bin(n)[2:]],x) # [2:] to chop off the "0b" part - -def pad_to_x(n,x): - while len(n) < x: - n = [0] + n - return n - -def status_codes(n): - - status_array = int_to_bits(n,16) - - status = { - 0: "Stopped", - 1: "Operating Forward", - 2: "Operating Reverse", - 3: "Fault Trip", - 4: "Accelerating", - 5: "Decelerating", - 6: "Speed Reached", - 7: "DC Braking", - 8: "Drive Stopped", - 9: "Not Used", - 10: "Brake Release Signal", - 11: "Forward Cmd", - 12: "Reverse Cmd", - 13: "REM, R/S", - 14: "REM, Freq", - 15: "Reversed" - } - stats = [] - counter = 15 - for x in range(16): - if status_array[x] == 1: - stats = [status[counter]] + stats - counter = counter - 1 - return '; '.join(stats) - -def fault_code_a(n): - - fault_code_array = int_to_bits(n,16) - - fault = { - 0: "OCT", - 1: "OVT", - 2: "EXT-A", - 3: "EST", - 4: "COL", - 5: "GFT", - 6: "OHT", - 7: "ETH", - 8: "OLT", - 9: "Reserved", - 10: "EXT-B", - 11: "EEP", - 12: "FAN", - 13: "POT", - 14: "IOLT", - 15: "LVT" - } - - faults = [] - counter = 15 - for x in range(16): - if fault_code_array[x] == 1: - faults = [fault[counter]] + faults - counter = counter - 1 - return '; '.join(faults) - -def fault_code_b(n): - - fault_code_array = int_to_bits(n,8) - - fault = { - 0: "COM", - 1: "Reserved", - 2: "NTC", - 3: "REEP", - 4: "OC2", - 5: "NBR", - 6: "SAFA", - 7: "SAFB" - } - - faults = [] - counter = 7 - for x in range(8): - if fault_code_array[x] == 1: - faults = [fault[counter]] + faults - counter = counter - 1 - return '; '.join(faults) - -class ModbusChannel(Channel): - """Modbus channel object.""" - - def __init__(self, mesh_name, register_number, data_type, chg_threshold, guarantee_sec, channel_size=1, map_=False, write_enabled=False, transform_fn=identity, unit_number=1, scaling=0): - """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 - self.last_send_time = 0 - self.chg_threshold = chg_threshold - self.guarantee_sec = guarantee_sec - self.map_ = map_ - self.write_enabled = write_enabled - self.transform_fn = transform_fn - self.unit_number = unit_number - self.instrument = minimalmodbus.Instrument('/dev/ttyS0', self.unit_number) - self.scaling= scaling - - def read(self): - """Return the transformed read value.""" - if self.data_type == "FLOAT": - try: - read_value = self.instrument.read_float(self.register_number,4,self.channel_size) - except IOError as e: - log.info(e) - return None - - elif self.data_type == "INTEGER" or self.data_type == "STRING": - try: - read_value = self.instrument.read_register(self.register_number, self.scaling, 4) - except IOError as e: - log.info(e) - return None - read_value = self.transform_fn(read_value) - return read_value - - def write(self, value): - """Write a value to a register""" - if self.data_type == "FLOAT": - value = float(value) - elif self.data_type == "INTEGER": - value = int(value) - else: - value = str(value) - try: - self.instrument.write_register(self.register_number,value, self.scaling, 16 if self.channel_size > 1 else 6 ) - return True - except Exception as e: - log.info("Failed to write value: {}".format(e)) - return False - - -class PLCChannel(Channel): - """PLC Channel Object.""" - - def __init__(self, ip, mesh_name, plc_tag, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False, plc_type='CLX'): - """Initialize the channel.""" - super(PLCChannel, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled) - self.plc_ip = ip - self.mesh_name = mesh_name - self.plc_tag = plc_tag - self.data_type = data_type - self.last_value = None - self.value = None - self.last_send_time = 0 - self.chg_threshold = chg_threshold - self.guarantee_sec = guarantee_sec - self.map_ = map_ - self.write_enabled = write_enabled - self.plc_type = plc_type - - def read(self): - """Read the value.""" - plc_value = None - if self.plc_tag and self.plc_ip: - read_value = read_tag(self.plc_ip, self.plc_tag, plc_type=self.plc_type) - if read_value: - plc_value = read_value[0] - - 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.""" - super(BoolArrayChannels, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled) - self.plc_ip = ip - self.mesh_name = mesh_name - self.plc_tag = plc_tag - self.data_type = data_type - self.last_value = None - self.value = None - self.last_send_time = 0 - self.chg_threshold = chg_threshold - self.guarantee_sec = guarantee_sec - self.map_ = map_ - self.write_enabled = write_enabled - - def compare_values(self, new_val_dict): - """Compare new values to old values to see if the values need storing.""" - send = False - for idx in new_val_dict: - try: - if new_val_dict[idx] != self.last_value[idx]: - send = True - except KeyError: - log.error("Key Error in self.compare_values for index {}".format(idx)) - send = True - return send - - def read(self, force_send=False): - """Read the value and check to see if needs to be stored.""" - send_needed = False - send_reason = "" - if self.plc_tag: - val = read_tag(self.plc_ip, self.plc_tag) - if val: - bool_arr = binarray(val[0]) - new_val = {} - for idx in self.map_: - try: - new_val[self.map_[idx]] = bool_arr[idx] - except KeyError: - log.error("Not able to get value for index {}".format(idx)) - - if self.last_send_time == 0: - send_needed = True - send_reason = "no send time" - elif self.value is None: - send_needed = True - send_reason = "no value" - elif self.compare_values(new_val): - send_needed = True - send_reason = "value change" - elif (time.time() - self.last_send_time) > self.guarantee_sec: - send_needed = True - send_reason = "guarantee sec" - elif force_send: - send_needed = True - send_reason = "forced" - - if send_needed: - self.value = new_val - self.last_value = self.value - self.last_send_time = time.time() - log.info("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) - return send_needed \ No newline at end of file diff --git a/piflow/v1/Tags.py b/piflow/v1/Tags.py deleted file mode 100644 index aeb6d4d..0000000 --- a/piflow/v1/Tags.py +++ /dev/null @@ -1,50 +0,0 @@ -from Channel import PLCChannel,Channel, ModbusChannel, status_codes, fault_code_a, fault_code_b, volume_units, totalizer_units -import persistence - -data = persistence.load('persist.json') -flowmeter_unit_number = data['flowmeter'] -drive_enabled = data['drive_enabled'] -if drive_enabled: - drive_unit_number = data['drive'] - - -if drive_enabled: - tags = [ - ModbusChannel('volume_flow', 3873, 'FLOAT', 1,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_1', 2609, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_2', 2809, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_3', 3009, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('volume_flow_units', 2102, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=volume_units), - ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('run_status', 13, 'STRING', 0, 3600, channel_size=1, unit_number=drive_unit_number, transform_fn=status_codes), - ModbusChannel('frequency', 9, 'INTEGER', 0.5, 600, channel_size=2, unit_number=drive_unit_number,scaling=2 ), - ModbusChannel('current', 8, 'INTEGER', 0.5, 600, channel_size=2, unit_number=drive_unit_number,scaling=1 ), - ModbusChannel('fault_a', 14, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_a), - ModbusChannel('fault_b', 28, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_b), - ModbusChannel('pid_ref', 4367, 'INTEGER', 1, 600, channel_size=1, unit_number=drive_unit_number,scaling=1), - ModbusChannel('pid_feedback', 4368, 'INTEGER', 1, 600, channel_size=1, unit_number=drive_unit_number,scaling=1), - ModbusChannel('motor_rated_current', 4896, 'INTEGER', 0, 3600, channel_size=1, unit_number=drive_unit_number,scaling=1), - ModbusChannel('sleep_delay', 4924, 'INTEGER', 1, 600, channel_size=1, unit_number=drive_unit_number, scaling=1) - ] -else: - tags = [ - ModbusChannel('volume_flow', 3873, 'FLOAT', 1,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_1', 2609, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_2', 2809, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_3', 3009, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('volume_flow_units', 2102, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=volume_units), - ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units) - ] - - - - - - - - - \ No newline at end of file diff --git a/piflow/v2/Channel.py b/piflow/v2/Channel.py deleted file mode 100644 index 43435fd..0000000 --- a/piflow/v2/Channel.py +++ /dev/null @@ -1,610 +0,0 @@ -"""Define Meshify channel class.""" -import time -from pycomm.ab_comm.clx import Driver as ClxDriver -from pycomm.cip.cip_base import CommError, DataError -from file_logger import filelogger as log -import minimalmodbus - -minimalmodbus.BAUDRATE = 9600 -minimalmodbus.STOPBITS = 1 - -TAG_DATAERROR_SLEEPTIME = 5 - -def binarray(intval): - """Split an integer into its bits.""" - bin_string = '{0:08b}'.format(intval) - bin_arr = [i for i in bin_string] - bin_arr.reverse() - return bin_arr - - -def read_tag(addr, tag, plc_type="CLX"): - """Read a tag from the PLC.""" - direct = plc_type == "Micro800" - clx = ClxDriver() - try: - if clx.open(addr, direct_connection=direct): - try: - val = clx.read_tag(tag) - return val - except DataError as err: - clx.close() - time.sleep(TAG_DATAERROR_SLEEPTIME) - log.error("Data Error during readTag({}, {}): {}".format(addr, tag, err)) - except CommError: - # err = c.get_status() - clx.close() - log.error("Could not connect during readTag({}, {})".format(addr, tag)) - except AttributeError as err: - clx.close() - log.error("AttributeError during readTag({}, {}): \n{}".format(addr, tag, err)) - clx.close() - return False - - -def read_array(addr, tag, start, end, plc_type="CLX"): - """Read an array from the PLC.""" - direct = plc_type == "Micro800" - clx = ClxDriver() - if clx.open(addr, direct_connection=direct): - arr_vals = [] - try: - for i in range(start, end): - tag_w_index = tag + "[{}]".format(i) - val = clx.read_tag(tag_w_index) - arr_vals.append(round(val[0], 4)) - if arr_vals: - return arr_vals - else: - log.error("No length for {}".format(addr)) - return False - except Exception: - log.error("Error during readArray({}, {}, {}, {})".format(addr, tag, start, end)) - err = clx.get_status() - clx.close() - log.error(err) - clx.close() - - -def write_tag(addr, tag, val, plc_type="CLX"): - """Write a tag value to the PLC.""" - direct = plc_type == "Micro800" - clx = ClxDriver() - try: - if clx.open(addr, direct_connection=direct): - try: - initial_val = clx.read_tag(tag) - write_status = clx.write_tag(tag, val, initial_val[1]) - return write_status - except DataError as err: - clx_err = clx.get_status() - clx.close() - log.error("--\nDataError during writeTag({}, {}, {}, plc_type={}) -- {}\n{}\n".format(addr, tag, val, plc_type, err, clx_err)) - - except CommError as err: - clx_err = clx.get_status() - log.error("--\nCommError during write_tag({}, {}, {}, plc_type={})\n{}\n--".format(addr, tag, val, plc_type, err)) - clx.close() - return False - - -class Channel(object): - """Holds the configuration for a Meshify channel.""" - - def __init__(self, mesh_name, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False): - """Initialize the channel.""" - self.mesh_name = mesh_name - self.data_type = data_type - self.last_value = None - self.value = None - self.last_send_time = 0 - self.chg_threshold = chg_threshold - self.guarantee_sec = guarantee_sec - self.map_ = map_ - self.write_enabled = write_enabled - - def __str__(self): - """Create a string for the channel.""" - return "{}\nvalue: {}, last_send_time: {}".format(self.mesh_name, self.value, self.last_send_time) - - def check(self, new_value, force_send=False): - """Check to see if the new_value needs to be stored.""" - send_needed = False - send_reason = "" - if self.data_type == 'BOOL' or self.data_type == 'STRING' or type(new_value) == str: - if self.last_send_time == 0: - send_needed = True - send_reason = "no send time" - elif self.value is None: - send_needed = True - send_reason = "no value" - elif self.value != new_value: - if self.map_: - if not self.value == self.map_[new_value]: - send_needed = True - send_reason = "value change" - else: - send_needed = True - send_reason = "value change" - elif (time.time() - self.last_send_time) > self.guarantee_sec: - send_needed = True - send_reason = "guarantee sec" - elif force_send: - send_needed = True - send_reason = "forced" - else: - if self.last_send_time == 0: - send_needed = True - send_reason = "no send time" - elif self.value is None: - send_needed = True - send_reason = "no value" - elif abs(self.value - new_value) > self.chg_threshold: - send_needed = True - send_reason = "change threshold" - elif (time.time() - self.last_send_time) > self.guarantee_sec: - send_needed = True - send_reason = "guarantee sec" - elif force_send: - send_needed = True - send_reason = "forced" - if send_needed: - self.last_value = self.value - if self.map_: - try: - self.value = self.map_[new_value] - except KeyError: - log.error("Cannot find a map value for {} in {} for {}".format(new_value, self.map_, self.mesh_name)) - self.value = new_value - else: - self.value = new_value - self.last_send_time = time.time() - log.info("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) - return send_needed - - def read(self): - """Read the value.""" - pass - - -def identity(sent): - """Return exactly what was sent to it.""" - return sent - -def volume_units(vunit): - units = { - 0: "cm cubed/s", - 1: "cm cubed/min", - 2: "cm cubed/h", - 3: "cm cubed/d", - 4: "dm cubed/s", - 5: "dm cubed/min", - 6: "dm cubed/h", - 7: "dm cubed/d", - 8: "m cubed/s", - 9: "m cubed/min", - 10: "m cubed/h", - 11: "m cubed/d", - 12: "ml/s", - 13: "ml/min", - 14: "ml/h", - 15: "ml/d", - 16: "l/s", - 17: "l/min", - 18: "l/h (+)", - 19: "l/d", - 20: "hl/s", - 21: "hl/min", - 22: "hl/h", - 23: "hl/d", - 24: "Ml/s", - 25: "Ml/min", - 26: "Ml/h", - 27: "Ml/d", - 32: "af/s", - 33: "af/min", - 34: "af/h", - 35: "af/d", - 36: "ft cubed/s", - 37: "ft cubed/min", - 38: "ft cubed/h", - 39: "ft cubed/d", - 40: "fl oz/s (us)", - 41: "fl oz/min (us)", - 42: "fl oz/h (us)", - 43: "fl oz/d (us)", - 44: "gal/s (us)", - 45: "gal/min (us)", - 46: "gal/h (us)", - 47: "gal/d (us)", - 48: "Mgal/s (us)", - 49: "Mgal/min (us)", - 50: "Mgal/h (us)", - 51: "Mgal/d (us)", - 52: "bbl/s (us;liq.)", - 53: "bbl/min (us;liq.)", - 54: "bbl/h (us;liq.)", - 55: "bbl/d (us;liq.)", - 56: "bbl/s (us;beer)", - 57: "bbl/min (us;beer)", - 58: "bbl/h (us;beer)", - 59: "bbl/d (us;beer)", - 60: "bbl/s (us;oil)", - 61: "bbl/min (us;oil)", - 62: "bbl/h (us;oil)", - 63: "bbl/d (us;oil)", - 64: "bbl/s (us;tank)", - 65: "bbl/min (us;tank)", - 66: "bbl/h (us;tank)", - 67: "bbl/d (us;tank)", - 68: "gal/s (imp)", - 69: "gal/min (imp)", - 70: "gal/h (imp)", - 71: "gal/d (imp)", - 72: "Mgal/s (imp)", - 73: "Mgal/min (imp)", - 74: "Mgal/h (imp)", - 75: "Mgal/d (imp)", - 76: "bbl/s (imp;beer)", - 77: "bbl/min (imp;beer)", - 78: "bbl/h (imp;beer)", - 79: "bbl/d (imp;beer)", - 80: "bbl/s (imp;oil)", - 81: "bbl/min (imp;oil)", - 82: "bbl/h (imp;oil)", - 83: "bbl/d (imp;oil)", - 88: "kgal/s (us)", - 89: "kgal/min (us)", - 90: "kgal/h (us)", - 91: "kgal/d (us)", - 92: "MMft cubed/s", - 93: "MMft cubed/min", - 94: "MMft cubed/h", - 96: "Mft cubed/d" - } - return units[vunit] - -def totalizer_units(tunit): - - units = { - 0: "cm cubed", - 1: "dm cubed", - 2: "m cubed", - 3: "ml", - 4: "l", - 5: "hl", - 6: "Ml Mega", - 8: "af", - 9: "ft cubed", - 10: "fl oz (us)", - 11: "gal (us)", - 12: "Mgal (us)", - 13: "bbl (us;liq.)", - 14: "bbl (us;beer)", - 15: "bbl (us;oil)", - 16: "bbl (us;tank)", - 17: "gal (imp)", - 18: "Mgal (imp)", - 19: "bbl (imp;beer)", - 20: "bbl (imp;oil)", - 22: "kgal (us)", - 23: "Mft cubed", - 50: "g", - 51: "kg", - 52: "t", - 53: "oz", - 54: "lb", - 55: "STon", - 100: "Nl", - 101: "Nm cubed", - 102: "Sm cubed", - 103: "Sft cubed", - 104: "Sl", - 105: "Sgal (us)", - 106: "Sbbl (us;liq.)", - 107: "Sgal (imp)", - 108: "Sbbl (us;oil)", - 109: "MMSft cubed", - 110: "Nhl", - 251: "None" - } - return units[tunit] - -def int_to_bits(n,x): - return pad_to_x([int(digit) for digit in bin(n)[2:]],x) # [2:] to chop off the "0b" part - -def pad_to_x(n,x): - while len(n) < x: - n = [0] + n - return n - -def status_codes(n): - - status_array = int_to_bits(n,16) - status_low = { - 0: "Stopped", - 1: "Operating in Forward", - 2: "Operating in Reverse", - 3: "DC operating" - } - status_mid = { - 1: "Speed searching", - 2: "Accelerating", - 3: "At constant speed", - 4: "Decelerating", - 5: "Decelerating to stop", - 6: "H/W OCS", - 7: "S/W OCS", - 8: "Dwell operating" - } - status_high = { - 0: "Normal state", - 4: "Warning occurred", - 8: "Fault occurred" - } - values = { - 0: 8, - 1: 4, - 2: 2, - 3: 1 - } - - stats_low = status_array[12:] - stats_mid = status_array[8:12] - stats_high = status_array[:4] - low = 0 - mid = 0 - high = 0 - for x in range(4): - if stats_low[x] == 1: - low = low + values[x] - if stats_mid[x] == 1: - mid = mid + values[x] - if stats_high[x] == 1: - high = high + values[x] - - return status_low[low] + ";" + status_mid[mid] + ';' + status_high[high] - -def fault_code_a(n): - - fault_code_array = int_to_bits(n,16) - - """ fault = { - 0: "OCT", - 1: "OVT", - 2: "EXT-A", - 3: "EST", - 4: "COL", - 5: "GFT", - 6: "OHT", - 7: "ETH", - 8: "OLT", - 9: "Reserved", - 10: "EXT-B", - 11: "EEP", - 12: "FAN", - 13: "POT", - 14: "IOLT", - 15: "LVT" - } """ - fault = { - 0: "Overload Trip", - 1: "Underload Trip", - 2: "Inverter Overload Trip", - 3: "E-Thermal Trip", - 4: "Ground Fault Trip", - 5: "Output Image Trip", - 6: "Inmput Imaging Trip", - 7: "Reserved", - 8: "Reserved", - 9: "NTC Trip", - 10: "Overcurrent Trip", - 11: "Overvoltage Trip", - 12: "External Trip", - 13: "Arm Short", - 14: "Over Heat Trip", - 15: "Fuse Open Trip" - } - - faults = [] - counter = 15 - for x in range(16): - if fault_code_array[x] == 1: - faults = [fault[counter]] + faults - counter = counter - 1 - return '; '.join(faults) - -def fault_code_b(n): - - fault_code_array = int_to_bits(n,8) - - """ fault = { - 0: "COM", - 1: "Reserved", - 2: "NTC", - 3: "REEP", - 4: "OC2", - 5: "NBR", - 6: "SAFA", - 7: "SAFB" - } """ - fault = { - 0: "Reserved", - 1: "Reserved", - 2: "Reserved", - 3: "FAN Trip", - 4: "Reserved", - 5: "Reserved", - 6: "Pre PID Fail", - 7: "Bad contact at basic I/O board", - 8: "External Brake Trip", - 9: "No Motor Trip", - 10: "Bad Option Card", - 11: "Reserved", - 12: "Reserved", - 13: "Reserved", - 14: "Pre Over Heat Trip", - 15: "Reserved" - } - - faults = [] - counter = 7 - for x in range(8): - if fault_code_array[x] == 1: - faults = [fault[counter]] + faults - counter = counter - 1 - return '; '.join(faults) - -class ModbusChannel(Channel): - """Modbus channel object.""" - - def __init__(self, mesh_name, register_number, data_type, chg_threshold, guarantee_sec, channel_size=1, map_=False, write_enabled=False, transform_fn=identity, unit_number=1, scaling=0): - """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 - self.last_send_time = 0 - self.chg_threshold = chg_threshold - self.guarantee_sec = guarantee_sec - self.map_ = map_ - self.write_enabled = write_enabled - self.transform_fn = transform_fn - self.unit_number = unit_number - self.instrument = minimalmodbus.Instrument('/dev/ttyS0', self.unit_number) - self.scaling= scaling - - def read(self): - """Return the transformed read value.""" - if self.data_type == "FLOAT": - try: - read_value = self.instrument.read_float(self.register_number,4,self.channel_size) - except IOError as e: - log.info(e) - return None - - elif self.data_type == "INTEGER" or self.data_type == "STRING": - try: - read_value = self.instrument.read_register(self.register_number, self.scaling, 4) - except IOError as e: - log.info(e) - return None - read_value = self.transform_fn(read_value) - return read_value - - def write(self, value): - """Write a value to a register""" - if self.data_type == "FLOAT": - value = float(value) - elif self.data_type == "INTEGER": - value = int(value) - else: - value = str(value) - try: - self.instrument.write_register(self.register_number,value, self.scaling, 16 if self.channel_size > 1 else 6 ) - return True - except Exception as e: - log.info("Failed to write value: {}".format(e)) - return False - - -class PLCChannel(Channel): - """PLC Channel Object.""" - - def __init__(self, ip, mesh_name, plc_tag, data_type, chg_threshold, guarantee_sec, map_=False, write_enabled=False, plc_type='CLX'): - """Initialize the channel.""" - super(PLCChannel, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled) - self.plc_ip = ip - self.mesh_name = mesh_name - self.plc_tag = plc_tag - self.data_type = data_type - self.last_value = None - self.value = None - self.last_send_time = 0 - self.chg_threshold = chg_threshold - self.guarantee_sec = guarantee_sec - self.map_ = map_ - self.write_enabled = write_enabled - self.plc_type = plc_type - - def read(self): - """Read the value.""" - plc_value = None - if self.plc_tag and self.plc_ip: - read_value = read_tag(self.plc_ip, self.plc_tag, plc_type=self.plc_type) - if read_value: - plc_value = read_value[0] - - 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.""" - super(BoolArrayChannels, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled) - self.plc_ip = ip - self.mesh_name = mesh_name - self.plc_tag = plc_tag - self.data_type = data_type - self.last_value = None - self.value = None - self.last_send_time = 0 - self.chg_threshold = chg_threshold - self.guarantee_sec = guarantee_sec - self.map_ = map_ - self.write_enabled = write_enabled - - def compare_values(self, new_val_dict): - """Compare new values to old values to see if the values need storing.""" - send = False - for idx in new_val_dict: - try: - if new_val_dict[idx] != self.last_value[idx]: - send = True - except KeyError: - log.error("Key Error in self.compare_values for index {}".format(idx)) - send = True - return send - - def read(self, force_send=False): - """Read the value and check to see if needs to be stored.""" - send_needed = False - send_reason = "" - if self.plc_tag: - val = read_tag(self.plc_ip, self.plc_tag) - if val: - bool_arr = binarray(val[0]) - new_val = {} - for idx in self.map_: - try: - new_val[self.map_[idx]] = bool_arr[idx] - except KeyError: - log.error("Not able to get value for index {}".format(idx)) - - if self.last_send_time == 0: - send_needed = True - send_reason = "no send time" - elif self.value is None: - send_needed = True - send_reason = "no value" - elif self.compare_values(new_val): - send_needed = True - send_reason = "value change" - elif (time.time() - self.last_send_time) > self.guarantee_sec: - send_needed = True - send_reason = "guarantee sec" - elif force_send: - send_needed = True - send_reason = "forced" - - if send_needed: - self.value = new_val - self.last_value = self.value - self.last_send_time = time.time() - log.info("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason)) - return send_needed \ No newline at end of file diff --git a/piflow/v2/Tags.py b/piflow/v2/Tags.py deleted file mode 100644 index 46d00a0..0000000 --- a/piflow/v2/Tags.py +++ /dev/null @@ -1,51 +0,0 @@ -from Channel import PLCChannel,Channel, ModbusChannel, status_codes, fault_code_a, fault_code_b, volume_units, totalizer_units -import persistence - -data = persistence.load('persist.json') -flowmeter_unit_number = data['flowmeter'] -drive_enabled = data['drive_enabled'] -if drive_enabled: - drive_unit_number = data['drive'] - - -if drive_enabled: - tags = [ - ModbusChannel('volume_flow', 3873, 'FLOAT', 1,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_1', 2609, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_2', 2809, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_3', 3009, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('volume_flow_units', 2102, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=volume_units), - ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - - ModbusChannel('run_status', 772, 'STRING', 0, 3600, channel_size=1, unit_number=drive_unit_number, transform_fn=status_codes), - ModbusChannel('frequency', 784, 'INTEGER', 0.5, 600, channel_size=2, unit_number=drive_unit_number,scaling=2 ), - ModbusChannel('current', 783, 'INTEGER', 0.5, 600, channel_size=2, unit_number=drive_unit_number,scaling=1 ), - ModbusChannel('fault_a', 815, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_a), - ModbusChannel('fault_b', 816, 'STRING', 1, 3600, channel_size=1, unit_number=drive_unit_number,transform_fn=fault_code_b), - ModbusChannel('pid_ref', 791, 'INTEGER', 1, 600, channel_size=1, unit_number=drive_unit_number,scaling=1), - ModbusChannel('pid_feedback', 792, 'INTEGER', 1, 600, channel_size=1, unit_number=drive_unit_number,scaling=1), - ModbusChannel('motor_rated_current', 4896, 'INTEGER', 0, 3600, channel_size=1, unit_number=drive_unit_number,scaling=1), - ModbusChannel('sleep_delay', 4924, 'INTEGER', 1, 600, channel_size=1, unit_number=drive_unit_number, scaling=1) - ] -else: - tags = [ - ModbusChannel('volume_flow', 3873, 'FLOAT', 1,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_1', 2609, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_2', 2809, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('totalizer_3', 3009, 'FLOAT', 10,600,channel_size=2, unit_number=flowmeter_unit_number), - ModbusChannel('volume_flow_units', 2102, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=volume_units), - ModbusChannel('totalizer_1_units', 4603, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_2_units', 4604, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units), - ModbusChannel('totalizer_3_units', 4605, 'INTEGER', 1,3600,channel_size=1, unit_number=flowmeter_unit_number, transform_fn=totalizer_units) - ] - - - - - - - - - \ No newline at end of file diff --git a/tenflowmeterskid/python-driver/Channel.py b/tenflowmeterskid/Channel.py similarity index 100% rename from tenflowmeterskid/python-driver/Channel.py rename to tenflowmeterskid/Channel.py diff --git a/tenflowmeterskid/python-driver/Tags.py b/tenflowmeterskid/Tags.py similarity index 100% rename from tenflowmeterskid/python-driver/Tags.py rename to tenflowmeterskid/Tags.py diff --git a/tenflowmeterskid/python-driver/config.txt b/tenflowmeterskid/config.txt similarity index 100% rename from tenflowmeterskid/python-driver/config.txt rename to tenflowmeterskid/config.txt diff --git a/tenflowmeterskid/python-driver/device_base.py b/tenflowmeterskid/device_base.py similarity index 100% rename from tenflowmeterskid/python-driver/device_base.py rename to tenflowmeterskid/device_base.py diff --git a/tenflowmeterskid/python-driver/file_logger.py b/tenflowmeterskid/file_logger.py similarity index 100% rename from tenflowmeterskid/python-driver/file_logger.py rename to tenflowmeterskid/file_logger.py diff --git a/tenflowmeterskid/html-templates/Alerts.html b/tenflowmeterskid/html-templates/Alerts.html deleted file mode 100644 index 2971cab..0000000 --- a/tenflowmeterskid/html-templates/Alerts.html +++ /dev/null @@ -1 +0,0 @@ -Alerts diff --git a/tenflowmeterskid/html-templates/Device.html b/tenflowmeterskid/html-templates/Device.html deleted file mode 100644 index 91d7188..0000000 --- a/tenflowmeterskid/html-templates/Device.html +++ /dev/null @@ -1,42 +0,0 @@ -
-
-

Public IP Address

-

<%= channels["tenflowmeterskid.public_ip_address"].value %>

-

-
- - diff --git a/tenflowmeterskid/html-templates/NodeDetailHeader.html b/tenflowmeterskid/html-templates/NodeDetailHeader.html deleted file mode 100644 index 28262a3..0000000 --- a/tenflowmeterskid/html-templates/NodeDetailHeader.html +++ /dev/null @@ -1,6 +0,0 @@ -
-
-
-
-

<%= node.vanityname %>

-
diff --git a/tenflowmeterskid/html-templates/Nodelist.html b/tenflowmeterskid/html-templates/Nodelist.html deleted file mode 100644 index 756a869..0000000 --- a/tenflowmeterskid/html-templates/Nodelist.html +++ /dev/null @@ -1,31 +0,0 @@ - - -
-
-
-
- -
- -
- -
-

<%= node.vanityname %>

-
-
diff --git a/tenflowmeterskid/html-templates/Overview.html b/tenflowmeterskid/html-templates/Overview.html deleted file mode 100644 index eac5942..0000000 --- a/tenflowmeterskid/html-templates/Overview.html +++ /dev/null @@ -1,121 +0,0 @@ - -
-
-

HEADER 1

-
-
-

CHANNEL 1

-
-
-
-
- - - -
- - <%= channels["tenflowmeterskid.channel_1"].timestamp %> - -
-
-
- - - - - - - - diff --git a/tenflowmeterskid/html-templates/Sidebar.html b/tenflowmeterskid/html-templates/Sidebar.html deleted file mode 100644 index e80ac7c..0000000 --- a/tenflowmeterskid/html-templates/Sidebar.html +++ /dev/null @@ -1,15 +0,0 @@ -" - class="data-table btn-block btn btn-theme animated" - title="Device Log"> Device Log - -" - data-techname="<%=channels["tenflowmeterskid.sync"].techName %>" - data-name="<%= channels["tenflowmeterskid.sync"].name%>" - data-nodechannelcurrentId="<%= channels["tenflowmeterskid.sync"].nodechannelcurrentId %>" - id="<%= channels["tenflowmeterskid.sync"].channelId %>" - class="btn btn-large btn-block btn-theme animated setstatic mqtt"> - Sync All Data diff --git a/tenflowmeterskid/html-templates/Trends.html b/tenflowmeterskid/html-templates/Trends.html deleted file mode 100644 index 8193486..0000000 --- a/tenflowmeterskid/html-templates/Trends.html +++ /dev/null @@ -1,37 +0,0 @@ -
-
- - to - - - Run - -
-
-
-
-
- diff --git a/piflow/VFD525/persistence.py b/tenflowmeterskid/persistence.py similarity index 100% rename from piflow/VFD525/persistence.py rename to tenflowmeterskid/persistence.py diff --git a/tenflowmeterskid/python-driver/persistence.py b/tenflowmeterskid/python-driver/persistence.py deleted file mode 100644 index 8c8703f..0000000 --- a/tenflowmeterskid/python-driver/persistence.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Data persistance functions.""" -# if more advanced persistence is needed, use a sqlite database -import json - - -def load(filename="persist.json"): - """Load persisted settings from the specified file.""" - try: - with open(filename, 'r') as persist_file: - return json.load(persist_file) - except Exception: - return False - - -def store(persist_obj, filename="persist.json"): - """Store the persisting settings into the specified file.""" - try: - with open(filename, 'w') as persist_file: - return json.dump(persist_obj, persist_file, indent=4) - except Exception: - return False diff --git a/tenflowmeterskid/python-driver/tenflowmeterskid.py b/tenflowmeterskid/tenflowmeterskid.py similarity index 100% rename from tenflowmeterskid/python-driver/tenflowmeterskid.py rename to tenflowmeterskid/tenflowmeterskid.py diff --git a/tenflowmeterskid/python-driver/utilities.py b/tenflowmeterskid/utilities.py similarity index 100% rename from tenflowmeterskid/python-driver/utilities.py rename to tenflowmeterskid/utilities.py