diff --git a/HTML/NodeList.html b/HTML/NodeList.html
new file mode 100644
index 0000000..17630bf
--- /dev/null
+++ b/HTML/NodeList.html
@@ -0,0 +1,41 @@
+
+
+
diff --git a/README.md b/README.md
index 313ac08..f5e4e1a 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,22 @@
-# flow-monitor
\ No newline at end of file
+# flow-monitor
+
+## To set up sqlite database
+```
+sqlite3 flow-monitor.db
+
+CREATE TABLE flow_data (
+ id integer PRIMARY KEY,
+ gal_totalizer_value float,
+ bbl_totalizer_value float,
+ last_measured_timestamp integer
+);
+
+INSERT INTO flow_data (id, gal_totalizer_value, bbl_totalizer_value, last_measured_timestamp) VALUES (1, 0.0, 0.0, 0);
+```
+
+## To reset the sqlite database
+```
+sqlite3 flow-monitor.db
+
+UPDATE flow_data SET gal_totalizer_value=0.0, bbl_totalizer_value=0.0, last_measured_timestamp=0 WHERE id=1;
+```
diff --git a/config.txt b/config.txt
new file mode 100644
index 0000000..eec9092
--- /dev/null
+++ b/config.txt
@@ -0,0 +1,10 @@
+{
+
+"driverFileName":"flow-monitor.py",
+"deviceName":"flowmonitor",
+"driverId":"0140",
+"releaseVersion":"1",
+"files": {
+ "file1":"flow-monitor.py"}
+
+}
diff --git a/flow-monitor.db b/flow-monitor.db
new file mode 100644
index 0000000..6e32248
Binary files /dev/null and b/flow-monitor.db differ
diff --git a/flow-monitor.py b/flow-monitor.py
new file mode 100644
index 0000000..90f428c
--- /dev/null
+++ b/flow-monitor.py
@@ -0,0 +1,170 @@
+"""Driver for connecting Flow Monitor to Meshify."""
+import threading
+from device_base import deviceBase
+import time
+from datetime import datetime
+import sqlite3
+
+
+class Channel:
+ """Meshify channel structure."""
+
+ def __init__(self, meshify_name, senddelta_value, senddelta_time):
+ """Initialize the channel with variables."""
+ self.meshify_name = meshify_name
+ self.senddelta_time = senddelta_time
+ self.senddelta_value = senddelta_value
+
+ self.last_sent_value = None
+ self.last_sent_timestamp = 0
+
+ def check_if_send_needed(self, value, timestamp):
+ """Check to see if the value needs to be pushed."""
+ if self.last_sent_value is None or self.last_sent_timestamp == 0:
+ return True
+
+ if abs(value - self.last_sent_value) > self.senddelta_value:
+ return True
+
+ if (timestamp - self.last_sent_timestamp) > self.senddelta_time:
+ return True
+
+ return False
+
+ def update(self, last_sent_value, last_sent_timestamp):
+ """Update values after a push."""
+ self.last_sent_value = last_sent_value
+ self.last_sent_timestamp = last_sent_timestamp
+
+
+def scale(raw_val, raw_min, raw_max, eu_min, eu_max):
+ """Scale a raw value."""
+ m = (eu_max - eu_min) / (raw_max - raw_min)
+ b = eu_max - (m * raw_max)
+ return m * raw_val + b
+
+
+def is_today(tstamp):
+ """Check if a given timestamp belongs to the current date."""
+ midnight_today = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
+ midnight_ts = (midnight_today - datetime(1970, 1, 1)).total_seconds()
+ return tstamp >= midnight_ts
+
+
+class start(threading.Thread, deviceBase):
+ """Start class required for driver."""
+
+ def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None,
+ companyId=None, offset=None, mqtt=None, Nodes=None):
+ """Initalize the driver."""
+ threading.Thread.__init__(self)
+ deviceBase.__init__(self, name=name, number=number, mac=mac, Q=Q,
+ mcu=mcu, companyId=companyId, offset=offset,
+ mqtt=mqtt, Nodes=Nodes)
+
+ self.daemon = True
+ self.version = "1"
+ self.finished = threading.Event()
+ 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.channels["status"]["last_value"] = ""
+
+
+ def run(self):
+ """Run the driver."""
+
+ # Configuration Parameters
+ total_time_store_delta = 60 # seconds
+ flow_time_store_delta = 60 # seconds
+
+ raw_min = 3.89
+ raw_max = 19.54
+
+ gpm_min = 0.0
+ gpm_max = 600.0
+
+ gal_per_bbl = 42.0
+
+ galtotal_ch = Channel('gal_total', 100.0, total_time_store_delta)
+ bbltotal_ch = Channel('bbl_total', galtotal_ch.senddelta_value/gal_per_bbl, total_time_store_delta)
+
+ gpmflow_ch = Channel('gpm_flow', 10.0, flow_time_store_delta)
+ bpdflow_ch = Channel('bpd_flow', gpmflow_ch.senddelta_value/gal_per_bbl, total_time_store_delta)
+
+ runstatus_ch = Channel('run_status', 0.5, 600)
+
+ last_measured_timestamp = time.time()
+ conn = sqlite3.connect('/root/python_firmware/drivers/flow-monitor.db')
+ c = conn.cursor()
+ c.execute('SELECT * FROM flow_data WHERE id = 1')
+ stored_data = c.fetchone()
+ gal_totalizer_value = stored_data[1]
+ bbl_totalizer_value = stored_data[2]
+ last_measured_timestamp = stored_data[3]
+ if not is_today(last_measured_timestamp):
+ gal_totalizer_value = 0
+ bbl_totalizer_value = 0
+ last_measured_timestamp = time.time()
+
+ wait_loops = 0
+ while wait_loops < 15:
+ print("Waiting to start driver in {} seconds".format(15 - wait_loops))
+ wait_loops += 1
+ time.sleep(1)
+
+ while True:
+ try:
+ mcu_status = self.mcu.getDict()
+ print(mcu_status)
+ cloop_val = float(mcu_status['cloop'])
+
+ din1_val = 1 if mcu_status['din1'] == 'On' else 0
+ gpm_val = scale(cloop_val, raw_min, raw_max, gpm_min, gpm_max)
+ if gpm_val < 0:
+ gpm_val = 0
+
+ bpd_val = (gpm_val / gal_per_bbl) * 60.0 * 24.0
+
+ now = time.time()
+ time_diff = now - last_measured_timestamp
+ gal_flow_delta = (time_diff / 60.0) * gpm_val
+ bbl_flow_delta = (time_diff / 60.0) * (1.0 / 60.0) * (1.0 / 24.0) * bpd_val
+
+ gal_totalizer_value += gal_flow_delta
+ bbl_totalizer_value += bbl_flow_delta
+ last_measured_timestamp = now
+
+ c.execute('UPDATE flow_data SET gal_totalizer_value=?, bbl_totalizer_value=?, last_measured_timestamp=?',
+ (gal_totalizer_value, bbl_totalizer_value, last_measured_timestamp))
+ conn.commit()
+
+ print('gpm: {}, bpd: {}, gal: {}, bbl:{}'.format(gpm_val, bpd_val, gal_totalizer_value, bbl_totalizer_value))
+
+ if galtotal_ch.check_if_send_needed(gal_totalizer_value, now):
+ self.sendtodb(galtotal_ch.meshify_name, gal_totalizer_value, 0)
+ galtotal_ch.update(gal_totalizer_value, now)
+
+ if bbltotal_ch.check_if_send_needed(bbl_totalizer_value, now):
+ self.sendtodb(bbltotal_ch.meshify_name, bbl_totalizer_value, 0)
+ bbltotal_ch.update(bbl_totalizer_value, now)
+
+ if gpmflow_ch.check_if_send_needed(gpm_val, now):
+ self.sendtodb(gpmflow_ch.meshify_name, gpm_val, 0)
+ gpmflow_ch.update(gpm_val, now)
+
+ if bpdflow_ch.check_if_send_needed(bpd_val, now):
+ self.sendtodb(bpdflow_ch.meshify_name, bpd_val, 0)
+ bpdflow_ch.update(bpd_val, now)
+
+ if runstatus_ch.check_if_send_needed(din1_val, now):
+ self.sendtodb(runstatus_ch.meshify_name, din1_val, 0)
+ runstatus_ch.update(din1_val, now)
+
+ except Exception as e:
+ print("problem in the driver: {}".format(e))
+ time.sleep(5)
diff --git a/test_totalizer.py b/test_totalizer.py
new file mode 100644
index 0000000..917500f
--- /dev/null
+++ b/test_totalizer.py
@@ -0,0 +1,150 @@
+"""Driver for testing Flow Monitor to Meshify."""
+import time
+import sqlite3
+from datetime import datetime
+
+
+class Channel:
+ """Meshify channel structure."""
+
+ def __init__(self, meshify_name, senddelta_value, senddelta_time):
+ """Initialize the channel with variables."""
+ self.meshify_name = meshify_name
+ self.senddelta_time = senddelta_time
+ self.senddelta_value = senddelta_value
+
+ self.last_sent_value = None
+ self.last_sent_timestamp = 0
+
+ def check_if_send_needed(self, value, timestamp):
+ """Check to see if the value needs to be pushed."""
+ if self.last_sent_value is None or self.last_sent_timestamp == 0:
+ return True
+
+ if abs(value - self.last_sent_value) > self.senddelta_value:
+ return True
+
+ if (timestamp - self.last_sent_timestamp) > self.senddelta_time:
+ return True
+
+ return False
+
+ def update(self, last_sent_value, last_sent_timestamp):
+ """Update values after a push."""
+ self.last_sent_value = last_sent_value
+ self.last_sent_timestamp = last_sent_timestamp
+
+
+def scale(raw_val, raw_min, raw_max, eu_min, eu_max):
+ """Scale a raw value."""
+ m = (eu_max - eu_min) / (raw_max - raw_min)
+ b = eu_max - (m * raw_max)
+ return m * raw_val + b
+
+
+def is_today(tstamp):
+ """Check if a given timestamp belongs to the current date."""
+ midnight_today = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
+ midnight_ts = (midnight_today - datetime(1970, 1, 1)).total_seconds()
+ return tstamp >= midnight_ts
+
+
+def loop():
+ """Run the driver."""
+ # Configuration Parameters
+ total_time_store_delta = 600 # seconds
+ flow_time_store_delta = 600 # seconds
+
+ raw_min = 3.89
+ raw_max = 19.54
+
+ gpm_min = 0.0
+ gpm_max = 600.0
+
+ gal_per_bbl = 42.0
+
+ galtotal_ch = Channel('gal_total', 100.0, total_time_store_delta)
+ bbltotal_ch = Channel('bbl_total', galtotal_ch.senddelta_value/gal_per_bbl, total_time_store_delta)
+
+ gpmflow_ch = Channel('gpm_flow', 10.0, flow_time_store_delta)
+ bpdflow_ch = Channel('bpd_flow', gpmflow_ch.senddelta_value/gal_per_bbl, total_time_store_delta)
+
+ runstatus_ch = Channel('run_status', 0.5, 600)
+
+ last_measured_timestamp = time.time()
+ conn = sqlite3.connect('flow-monitor.db')
+ c = conn.cursor()
+
+ conn.commit()
+ c.execute('SELECT * FROM flow_data WHERE id = 1')
+ stored_data = c.fetchone()
+ gal_totalizer_value = stored_data[1]
+ bbl_totalizer_value = stored_data[2]
+ last_measured_timestamp = stored_data[3]
+ if not is_today(last_measured_timestamp):
+ gal_totalizer_value = 0
+ bbl_totalizer_value = 0
+ last_measured_timestamp = time.time()
+
+ wait_loops = 0
+ while wait_loops < 15:
+ print("Waiting to start driver in {} seconds".format(15 - wait_loops))
+ wait_loops += 1
+ time.sleep(1)
+
+ while True:
+ try:
+ mcu_status = {}
+ mcu_status['cloop'] = '12.0'
+ mcu_status['din1'] = 'Off'
+ print(mcu_status)
+ cloop_val = float(mcu_status['cloop'])
+
+ din1_val = 1 if mcu_status['din1'] == 'On' else 0
+ gpm_val = scale(cloop_val, raw_min, raw_max, gpm_min, gpm_max)
+ if gpm_val < 0:
+ gpm_val = 0
+
+ bpd_val = (gpm_val / gal_per_bbl) * 60.0 * 24.0
+
+ now = time.time()
+ time_diff = now - last_measured_timestamp
+ gal_flow_delta = (time_diff / 60.0) * gpm_val
+ bbl_flow_delta = (time_diff / 60.0) * (1.0 / 60.0) * (1.0 / 24.0) * bpd_val
+
+ gal_totalizer_value += gal_flow_delta
+ bbl_totalizer_value += bbl_flow_delta
+ last_measured_timestamp = now
+
+ c.execute('UPDATE flow_data SET gal_totalizer_value=?, bbl_totalizer_value=?, last_measured_timestamp=?',
+ (gal_totalizer_value, bbl_totalizer_value, last_measured_timestamp))
+ conn.commit()
+
+ print('gpm: {}, bpd: {}, gal: {}, bbl:{}'.format(gpm_val, bpd_val, gal_totalizer_value, bbl_totalizer_value))
+
+ # if galtotal_ch.check_if_send_needed(gal_totalizer_value, now):
+ # self.sendtodb(galtotal_ch.meshify_name, gal_totalizer_value, 0)
+ # galtotal_ch.update(gal_totalizer_value, now)
+ #
+ # if bbltotal_ch.check_if_send_needed(bbl_totalizer_value, now):
+ # self.sendtodb(bbltotal_ch.meshify_name, bbl_totalizer_value, 0)
+ # bbltotal_ch.update(bbl_totalizer_value, now)
+ #
+ # if gpmflow_ch.check_if_send_needed(gpm_val, now):
+ # self.sendtodb(gpmflow_ch.meshify_name, gpm_val, 0)
+ # gpmflow_ch.update(gpm_val, now)
+ #
+ # if bpdflow_ch.check_if_send_needed(bpd_val, now):
+ # self.sendtodb(bpdflow_ch.meshify_name, bpd_val, 0)
+ # bpdflow_ch.update(bpd_val, now)
+ #
+ # if runstatus_ch.check_if_send_needed(din1_val, now):
+ # self.sendtodb(runstatus_ch.meshify_name, din1_val, 0)
+ # runstatus_ch.update(din1_val, now)
+
+ except Exception as e:
+ print("problem in the driver: {}".format(e))
+ time.sleep(5)
+
+
+loop()