Adds public_ip_address, fixes pressure graph

This commit is contained in:
Patrick McDonagh
2018-07-03 16:51:51 -05:00
parent 261ceba0b4
commit 3688d62539
8 changed files with 213 additions and 53 deletions

View File

@@ -0,0 +1,47 @@
<div class="row row-flex box-me">
<div class="col-md-6 text-center">
<h2 class="uppercase">Public IP Address</h2>
<p><%= channels["pondlevel.public_ip_address"].value %><p>
<div class- "timestamp-box">
<a href="#" data-channelId="<%= channels['pondlevel.public_ip_address'].channelId %>" class="data-table" title="Download Channel History">
<i class="fa fa-download"></i>
</a>
</div>
</div>
</div>
<style>
.uppercase {
text-transform: uppercase;
font-size: 14px;
color: #666;
font-weight: 400;
letter-spacing: 1px;
z-index: 100;
}
.box-me {
position: relative;
padding: 0.5em;
padding-bottom: 1.5em;
border: 1px solid #eee;
/*margin: 1em 0;*/
}
.row-flex {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
flex-wrap: wrap;
}
.row-flex > [class*='col-'] {
display: flex;
flex-direction: column;
}
p {
font-size: 1.25em;
}
</style>

View File

@@ -95,7 +95,7 @@
</div> </div>
<div class='col-xs-8'> <div class='col-xs-8'>
<div style="height:300px" id="chart-pressure_psi" data-chart="chart" data-nodename1="pondlevel.pressure_psi" data-datalabel1="Pressure" data-daysofhistory="2" data-chartlabel="Pond Volume" data-ylabel="" data-xlabel="Date" data-units=" PSI"></div> <div style="height:300px" id="chart-pressure_psi" data-chart="chart" data-nodename1="pondlevel.pressure_psi" data-datalabel1="Pressure" data-daysofhistory="2" data-chartlabel="Pressure" data-ylabel="" data-xlabel="Date" data-units=" PSI"></div>
</div> </div>
</div> </div>
<% } %> <% } %>

View File

@@ -0,0 +1,21 @@
id,name,deviceTypeId,fromMe,io,subTitle,helpExplanation,channelType,dataType,defaultValue,regex,regexErrMsg,units,min,max,change,guaranteedReportPeriod,minReportTime
12764,pond_level,412,FALSE,readonly,Pond Level,Level in Ft.,device,float,,,,,,,,,
12769,high_level_limit,412,FALSE,readwrite,High Level Limit,Limit in ft.,user input,float,25,,,,,,,,
12770,low_level_limit,412,FALSE,readwrite,Low Level Limit, Limit in ft.,user input,float,1,,,,,,,,
13352,setrawmax,412,FALSE,readwrite,Raw Max Setpoint,in mA,device,float,,,,,,,,,
13353,setrawmin,412,FALSE,readwrite,Raw Min Setpoint,in mA,device,float,,,,,,,,,
13354,seteumax,412,FALSE,readwrite,EU Max Setpoint,in Ft.,device,float,,,,,,,,,
13355,seteumin,412,FALSE,readwrite,EU Min Setpoint,in Ft.,device,float,,,,,,,,,
13356,log,412,FALSE,readwrite,Log,Log,device,string,,,,,,,,,
13357,sync,412,FALSE,readwrite,Sync,Sycn,device,string,,,,,,,,,
13358,calibration_data,412,FALSE,readonly,Calibration Data,All calibration data,device,string,,,,,,,,,
13359,addcalibrationpoint,412,FALSE,readwrite,Add Calibration Point,Add a single calibration point,device,string,,,,,,,,,
13360,deletecalibrationpoint,412,FALSE,readwrite,Delete Calibration Point,Delete a Calibration Point,device,integer,,,,,,,,,
13361,pond_volume,412,FALSE,readonly,Pond Volume,in BBL,device,float,0,,,,,,,,
13642,pressure_psi,412,FALSE,readonly,Pressure,in PSI,device,float,,,,,,,,,
13643,setpsirawmin,412,FALSE,readwrite,Pressure Raw Min Setpoint,in PSI,device,float,,,,,,,,,
13644,setpsirawmax,412,FALSE,readwrite,Pressure Raw Max Setpoint,in PSI,device,float,,,,,,,,,
13645,setpsieumax,412,FALSE,readwrite,Pressure EU Max Setpoint,in PSI,device,float,,,,,,,,,
13646,setpsieumin,412,FALSE,readwrite,Pressure EU Min Setpoint,in PSI,device,float,,,,,,,,,
13647,high_pressure_limit,412,FALSE,readwrite,High Pressure Input,Send an alert when pressure > high_pressure_input,user input,float,30,,,,,,,,
,public_ip_address,412,FALSE,readonly,Public IP Address,Network Address,device,string,,,,,,,,,
1 id name deviceTypeId fromMe io subTitle helpExplanation channelType dataType defaultValue regex regexErrMsg units min max change guaranteedReportPeriod minReportTime
2 12764 pond_level 412 FALSE readonly Pond Level Level in Ft. device float
3 12769 high_level_limit 412 FALSE readwrite High Level Limit Limit in ft. user input float 25
4 12770 low_level_limit 412 FALSE readwrite Low Level Limit Limit in ft. user input float 1
5 13352 setrawmax 412 FALSE readwrite Raw Max Setpoint in mA device float
6 13353 setrawmin 412 FALSE readwrite Raw Min Setpoint in mA device float
7 13354 seteumax 412 FALSE readwrite EU Max Setpoint in Ft. device float
8 13355 seteumin 412 FALSE readwrite EU Min Setpoint in Ft. device float
9 13356 log 412 FALSE readwrite Log Log device string
10 13357 sync 412 FALSE readwrite Sync Sycn device string
11 13358 calibration_data 412 FALSE readonly Calibration Data All calibration data device string
12 13359 addcalibrationpoint 412 FALSE readwrite Add Calibration Point Add a single calibration point device string
13 13360 deletecalibrationpoint 412 FALSE readwrite Delete Calibration Point Delete a Calibration Point device integer
14 13361 pond_volume 412 FALSE readonly Pond Volume in BBL device float 0
15 13642 pressure_psi 412 FALSE readonly Pressure in PSI device float
16 13643 setpsirawmin 412 FALSE readwrite Pressure Raw Min Setpoint in PSI device float
17 13644 setpsirawmax 412 FALSE readwrite Pressure Raw Max Setpoint in PSI device float
18 13645 setpsieumax 412 FALSE readwrite Pressure EU Max Setpoint in PSI device float
19 13646 setpsieumin 412 FALSE readwrite Pressure EU Min Setpoint in PSI device float
20 13647 high_pressure_limit 412 FALSE readwrite High Pressure Input Send an alert when pressure > high_pressure_input user input float 30
21 public_ip_address 412 FALSE readonly Public IP Address Network Address device string

View File

@@ -1,10 +1,13 @@
{ {
"files": { "driverFileName": "pondlevel.py",
"file2": "calibration_db.py",
"file1": "pondlevel.py"
},
"deviceName": "pondlevel", "deviceName": "pondlevel",
"driverId": "0130", "driverId": "130",
"releaseVersion": "3", "releaseVersion": "4",
"driverFileName": "pondlevel.py" "files": {
} "file1": "pondlevel.py",
"file2": "calibration_db.py",
"file3": "persistence.py",
"file4": "utilities.py",
"file5": "file_logger.py"
}
}

View File

@@ -4,8 +4,10 @@
"driverId": "0130", "driverId": "0130",
"additionalDriverFiles": [ "additionalDriverFiles": [
"calibration_db.py", "calibration_db.py",
"persistence.py" "persistence.py",
"utilities.py",
"file_logger.py"
], ],
"version": 1, "version": 4,
"s3BucketName": "pondlevel" "s3BucketName": "pondlevel"
} }

View File

@@ -0,0 +1,18 @@
"""Logging setup for pondlevel"""
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 = './pondlevel.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('pondlevel')
filelogger.setLevel(logging.INFO)
filelogger.addHandler(my_handler)
console_out = logging.StreamHandler(sys.stdout)
console_out.setFormatter(log_formatter)
filelogger.addHandler(console_out)

View File

@@ -5,6 +5,8 @@ from device_base import deviceBase
import time import time
import json import json
import persistence import persistence
from utilities import get_public_ip_address
from file_logger import filelogger as log
_ = None _ = None
@@ -45,11 +47,14 @@ class start(threading.Thread, deviceBase):
deviceBase.__init__(self, name=name, number=number, mac=mac, Q=Q, mcu=mcu, companyId=companyId, offset=offset, mqtt=mqtt, Nodes=Nodes) 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.daemon = True
self.version = "3" self.version = "4"
self.finished = threading.Event() self.finished = threading.Event()
self.forceSend = False self.forceSend = False
threading.Thread.start(self) threading.Thread.start(self)
self.public_ip_address = ""
self.public_ip_address_last_checked = 0
self.PL_RAWMAX = 20.0 self.PL_RAWMAX = 20.0
self.PL_RAWMIN = 4.0 self.PL_RAWMIN = 4.0
self.PL_EUMAX = 23.068 self.PL_EUMAX = 23.068
@@ -85,9 +90,9 @@ class start(threading.Thread, deviceBase):
self.PL_EUMAX = scaling_persist['eu_max'] self.PL_EUMAX = scaling_persist['eu_max']
self.PL_EUMIN = scaling_persist['eu_min'] self.PL_EUMIN = scaling_persist['eu_min']
except KeyError: except KeyError:
print("No persistence data for pond level scaling parameters.") log.warning("No persistence data for pond level scaling parameters.")
except TypeError: except TypeError:
print("No persistence data for pond level scaling parameters.") log.warning("No persistence data for pond level scaling parameters.")
try: try:
self.PSI_RAWMAX = scaling_persist['psi_raw_max'] self.PSI_RAWMAX = scaling_persist['psi_raw_max']
@@ -95,27 +100,28 @@ class start(threading.Thread, deviceBase):
self.PSI_EUMAX = scaling_persist['psi_eu_max'] self.PSI_EUMAX = scaling_persist['psi_eu_max']
self.PSI_EUMIN = scaling_persist['psi_eu_min'] self.PSI_EUMIN = scaling_persist['psi_eu_min']
except KeyError: except KeyError:
print("No persistence data for pressure scaling parameters.") log.warning("No persistence data for pressure scaling parameters.")
except TypeError: except TypeError:
print("No persistence data for pressure scaling parameters.") log.warning("No persistence data for pressure scaling parameters.")
try: try:
if len(strapping_persist.keys()) > 0: if len(strapping_persist.keys()) > 0:
for k in strapping_persist.keys(): for k in strapping_persist.keys():
self.strapping_table[float(k)] = strapping_persist[k] self.strapping_table[float(k)] = strapping_persist[k]
print("Using stored strapping table:\n{}".format(self.strapping_table)) log.info("Using stored strapping table:\n{}".format(self.strapping_table))
else: else:
print("No stored strapping table found.") log.warning("No stored strapping table found.")
except Exception as e: except Exception as e:
print("No stored strapping table. Got Error: {}".format(e)) log.warning("No stored strapping table. Got Error: {}".format(e))
wait_sec = 30 wait_sec = 30
for i in range(0, wait_sec): for i in range(0, wait_sec):
print("pondlevel driver will start in {} seconds".format(wait_sec - i)) log.info("pondlevel driver will start in {} seconds".format(wait_sec - i))
time.sleep(1) time.sleep(1)
print("BOOM! Starting pondlevel driver...") log.info("BOOM! Starting pondlevel driver...")
# db.setup_calibration_table(drop_first=False) # db.setup_calibration_table(drop_first=False)
self.send_calibration_points() self.send_calibration_points()
self._check_ip_address()
self.sendtodb("setrawmax", self.PL_RAWMAX, 0) self.sendtodb("setrawmax", self.PL_RAWMAX, 0)
self.sendtodb("setrawmin", self.PL_RAWMIN, 0) self.sendtodb("setrawmin", self.PL_RAWMIN, 0)
@@ -128,40 +134,39 @@ class start(threading.Thread, deviceBase):
self.sendtodb("setpsieumin", self.PSI_EUMIN, 0) self.sendtodb("setpsieumin", self.PSI_EUMIN, 0)
send_loops = 0 send_loops = 0
ip_check_after = 60
while True: while True:
now = time.time()
pl_send_now = False pl_send_now = False
psi_send_now = False psi_send_now = False
if self.forceSend: if self.forceSend:
print "FORCE SEND: TRUE" log.warning("FORCE SEND: TRUE")
pl_send_now = True pl_send_now = True
psi_send_now = True psi_send_now = True
try:
mcu_status = self.mcu.getDict() # Gets a dictionary of the IO states
cloop_val = float(mcu_status['cloop'])
analog1_val = float(mcu_status['analog1'])
temp_pl = scale_to_eu(cloop_val, self.PL_RAWMAX, self.PL_RAWMIN, self.PL_EUMAX, self.PL_EUMIN)
temp_psi = scale_to_eu(analog1_val, self.PSI_RAWMAX, self.PSI_RAWMIN, self.PSI_EUMAX, self.PSI_EUMIN)
except AttributeError as err:
log.error("Could not connect to MCU object, this device might not have an MCU: {}".format(err))
except KeyError as err:
log.error("Connected to MCU, but {} does not exist.".format(err))
mcu_status = self.mcu.getDict() # Gets a dictionary of the IO states
cloop_val = float(mcu_status['cloop'])
analog1_val = float(mcu_status['analog1'])
temp_pl = scale_to_eu(cloop_val, self.PL_RAWMAX, self.PL_RAWMIN, self.PL_EUMAX, self.PL_EUMIN) if (now - pond_level['timestamp']) > send_time:
temp_psi = scale_to_eu(analog1_val, self.PSI_RAWMAX, self.PSI_RAWMIN, self.PSI_EUMAX, self.PSI_EUMIN) log.info("Sending pond level {} due to time limit".format(temp_pl))
# Check if pond level needs to be sent
# 4/30/2018 -- COMMENTING OUT
# Pond level was sending irregular data
# -- Patrick McDonagh
# if abs(temp_pl - pond_level['value']) > send_delta:
# print("Sending pond level {} due to value change".format(temp_pl))
# pl_send_now = True
# 4/30/2018 -- END COMMENTING OUT
if (time.time() - pond_level['timestamp']) > send_time:
print("Sending pond level {} due to time limit".format(temp_pl))
pl_send_now = True pl_send_now = True
# Check if pressure needs to be sent # Check if pressure needs to be sent
if abs(temp_psi - psi_reading['value']) > send_delta: if abs(temp_psi - psi_reading['value']) > send_delta:
print("Sending pressure psi {} due to value change".format(temp_psi)) log.info("Sending pressure psi {} due to value change".format(temp_psi))
psi_send_now = True psi_send_now = True
if (time.time() - psi_reading['timestamp']) > send_time: if (now - psi_reading['timestamp']) > send_time:
print("Sending pressure psi {} due to time limit".format(temp_psi)) log.info("Sending pressure psi {} due to time limit".format(temp_psi))
psi_send_now = True psi_send_now = True
if pl_send_now: if pl_send_now:
@@ -174,23 +179,36 @@ class start(threading.Thread, deviceBase):
self.sendtodb('pond_volume', pond_volume, 0) self.sendtodb('pond_volume', pond_volume, 0)
pond_level['value'] = temp_pl pond_level['value'] = temp_pl
pond_level['timestamp'] = time.time() pond_level['timestamp'] = now
if psi_send_now: if psi_send_now:
self.sendtodb('pressure_psi', temp_psi, 0) self.sendtodb('pressure_psi', temp_psi, 0)
psi_reading['value'] = temp_psi psi_reading['value'] = temp_psi
psi_reading['timestamp'] = time.time() psi_reading['timestamp'] = now
print("pondlevel driver still alive...") if (now - self.public_ip_address_last_checked) > ip_check_after or self.forceSend:
self._check_ip_address()
log.info("pondlevel driver still alive...")
if self.forceSend: if self.forceSend:
if send_loops > 2: if send_loops > 2:
print("Turning off forceSend") log.info("Turning off forceSend")
self.forceSend = False self.forceSend = False
send_loops = 0 send_loops = 0
else: else:
send_loops += 1 send_loops += 1
time.sleep(10) 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()
if not test_public_ip == self.public_ip_address:
self.sendtodb('public_ip_address', test_public_ip, 0)
self.public_ip_address = test_public_ip
def send_calibration_points(self): def send_calibration_points(self):
"""Send calibration data from database to Meshify.""" """Send calibration data from database to Meshify."""
strapping_table_list = [] strapping_table_list = []
@@ -212,14 +230,14 @@ class start(threading.Thread, deviceBase):
"""Add a JSON calibration point to the database.""" """Add a JSON calibration point to the database."""
try: try:
new_point = json.loads(value.replace("'", '"')) new_point = json.loads(value.replace("'", '"'))
print("Trying to add Height: {}, volume: {}".format(new_point['height'], new_point['volume'])) log.info("Trying to add Height: {}, volume: {}".format(new_point['height'], new_point['volume']))
self.strapping_table[float(new_point['height'])] = float(new_point['volume']) self.strapping_table[float(new_point['height'])] = float(new_point['volume'])
self.store_strapping_table() self.store_strapping_table()
# db.insert_calibration_data(new_point['height'], new_point['volume']) # db.insert_calibration_data(new_point['height'], new_point['volume'])
self.send_calibration_points() self.send_calibration_points()
return True return True
except Exception as e: except Exception as e:
print("EXCEPTION: {}".format(e)) log.error("EXCEPTION: {}".format(e))
def pondlevel_deletecalibrationpoint(self, name, value): def pondlevel_deletecalibrationpoint(self, name, value):
"""Delete a calibration point from the database.""" """Delete a calibration point from the database."""
@@ -230,7 +248,7 @@ class start(threading.Thread, deviceBase):
self.send_calibration_points() self.send_calibration_points()
return True return True
except Exception as e: except Exception as e:
print("Error deleting calibration point: {}".format(e)) log.error("Error deleting calibration point: {}".format(e))
return(e) return(e)
def store_scaling_data(self): def store_scaling_data(self):
@@ -261,8 +279,8 @@ class start(threading.Thread, deviceBase):
for height_i in height_list: for height_i in height_list:
strapping_table_list.append([float(height_i), float(self.strapping_table[height_i])]) strapping_table_list.append([float(height_i), float(self.strapping_table[height_i])])
print("Strapping Table Data\n===") # print("Strapping Table Data\n===")
print(strapping_table_list) # print(strapping_table_list)
cal_min_height = strapping_table_list[0][0] cal_min_height = strapping_table_list[0][0]
cal_max_height = strapping_table_list[-1][0] cal_max_height = strapping_table_list[-1][0]
@@ -286,7 +304,7 @@ class start(threading.Thread, deviceBase):
return line_m * height + line_b return line_m * height + line_b
except Exception as e: except Exception as e:
print("Error in get_volume_for_height: {}".format(e)) log.error("Error in get_volume_for_height: {}".format(e))
return 0.0 return 0.0
def pondlevel_setrawmin(self, name, value): def pondlevel_setrawmin(self, name, value):

View File

@@ -0,0 +1,51 @@
"""Utility functions for the driver."""
import socket
import struct
def get_public_ip_address():
"""Find the public IP Address of the host device."""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ip = s.getsockname()[0]
s.close()
return ip
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")
else:
return float("NaN")
else:
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 = struct.unpack('>f', mypack)
print("[{}, {}] >> {}".format(int1, int2, f[0]))
return f[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