Compare commits
9 Commits
working-dr
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8778389e5 | ||
|
|
668cbf3b9f | ||
|
|
b6e3587344 | ||
|
|
79767d383b | ||
|
|
273f29b851 | ||
|
|
6ca7d16132 | ||
|
|
42afcda071 | ||
|
|
4faa6aa296 | ||
|
|
ec72749c2a |
@@ -1,37 +0,0 @@
|
||||
<div class='col-xs-1'>
|
||||
<div class="<%= nodecolors.statuscolor %> nodecolor"></div>
|
||||
</div>
|
||||
<div class='col-xs-6'>
|
||||
<h3><%= node.vanityname %></h3>
|
||||
</div>
|
||||
|
||||
<div class='col-xs-4'>
|
||||
<div class="text-center">
|
||||
<h2>Last Note</h2>
|
||||
<p class="note-text"><%= channels['advvfdipp.notes'].value %></p>
|
||||
<p> at <%= channels["advvfdipp.notes"].timestamp %></p>
|
||||
<button href="#" data-channelId="<%= channels['advvfdipp.notes'].channelId %>" class="data-table btn btn-theme note-btn" title="Note History"><i style='margin-left: 0.5em; cursor: pointer' class="fa fa-th-list icon-theme"></i> All Notes</button>
|
||||
<br />
|
||||
<button type="button" class="btn btn-theme note-btn" data-toggle="modal" data-target="#note-modal"><i style='margin-left: 0.5em; cursor: pointer' class="fa fa-pencil icon-theme"></i> New Note</button>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
#note-modal{
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
position: relative;
|
||||
}
|
||||
.modal-dialog {
|
||||
top:5%;
|
||||
}
|
||||
.note-btn {
|
||||
margin-top: 10px;
|
||||
width: 75%;
|
||||
}
|
||||
.note-text {
|
||||
font-size: 1.5em;
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
34
abbflow.py
34
abbflow.py
@@ -1,34 +0,0 @@
|
||||
|
||||
import threading
|
||||
import time
|
||||
from device_base import deviceBase
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class start(threading.Thread, deviceBase):
|
||||
def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None,
|
||||
companyId=None, offset=None, mqtt=None, Nodes=None):
|
||||
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 = "2"
|
||||
self.finished = threading.Event()
|
||||
threading.Thread.start(self)
|
||||
self.sleep_minutes = 25
|
||||
|
||||
# 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):
|
||||
self.channels["status"]["last_value"] = ""
|
||||
|
||||
def run(self):
|
||||
self.sendtodb('sleeplog', "I'm awake!", 0)
|
||||
while (True):
|
||||
t = datetime.now()
|
||||
if (t.minute == 5 or t.minute == 35):
|
||||
self.sendtodb('sleeplog', "Going to sleep...", 0)
|
||||
self.mcu.sleep(self.sleep_minutes * 60)
|
||||
14
channels_abbflow.csv
Normal file
14
channels_abbflow.csv
Normal file
@@ -0,0 +1,14 @@
|
||||
id,name,deviceTypeId,fromMe,io,subTitle,helpExplanation,channelType,dataType,defaultValue,regex,regexErrMsg,units,min,max,change,guaranteedReportPeriod,minReportTime
|
||||
8333,battery_voltage,317,FALSE,readonly,Battery Voltage,V,device,float,,,,,,,,,
|
||||
8334,volume_flow,317,FALSE,readonly,Volume Flow,MCF/Day,device,float,,,,,,,,,
|
||||
8335,today_volume,317,FALSE,readonly,Today Volume,MCF,device,float,,,,,,,,,
|
||||
8336,yesterday_volume,317,FALSE,readonly,Yesterday Volume,MCF,device,float,,,,,,,,,
|
||||
8337,accumulated_volume,317,FALSE,readonly,Accumulated Volume,MCF,device,float,,,,,,,,,
|
||||
8338,last_calculation_period_volume,317,FALSE,readonly,Last Calculation Period Volume,SCF,device,float,,,,,,,,,
|
||||
8339,differential_pressure,317,FALSE,readonly,Differential Pressure,InH2O,device,float,,,,,,,,,
|
||||
8340,static_pressure,317,FALSE,readonly,Static Pressure,PSIA,device,float,,,,,,,,,
|
||||
8341,temperature,317,FALSE,readonly,Temperature,deg F,device,float,,,,,,,,,
|
||||
8349,charger_voltage,317,FALSE,readonly,Charger Voltage,V,device,float,,,,,,,,,
|
||||
8358,notes,317,FALSE,readwrite,Notes,User-entered notes,user input,string,No notes yet...,,,,,,,,
|
||||
9018,sleeplog,317,FALSE,readonly,Sleep Log,Log of sleep and awakeness,device,string,Nothing here yet...,,,,,,,,
|
||||
,public_ip_address,317,FALSE,readonly,Public IP Address,Network Address,device,string,n/a,,,,,,,,
|
||||
|
42
html-templates/Device.html
Normal file
42
html-templates/Device.html
Normal file
@@ -0,0 +1,42 @@
|
||||
<div class="row row-flex box-me">
|
||||
<div class="col-md-6 text-center">
|
||||
<h2 class="uppercase">Public IP Address</h2>
|
||||
<p><%= channels["abbflow.public_ip_address"].value %><p>
|
||||
</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>
|
||||
6
html-templates/NodeDetailHeader.html
Normal file
6
html-templates/NodeDetailHeader.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<div class='col-xs-1'>
|
||||
<div class="<%= nodecolors.statuscolor %> nodecolor"></div>
|
||||
</div>
|
||||
<div class='col-xs-6'>
|
||||
<h3><%= node.vanityname %></h3>
|
||||
</div>
|
||||
@@ -29,13 +29,13 @@
|
||||
<h4><%= node.vanityname %></h4>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-3">
|
||||
<h2>Volume Flow</h2>
|
||||
<p><span data-valueupdate="volume_flow"><%= channels["abbflow.volume_flow"].value %></span> MCF/Day</p>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-3">
|
||||
<h2>Today Volume</h2>
|
||||
<p><span data-valueupdate="today_volume"><%= channels["abbflow.today_volume"].value %></span> MCF</p>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-3">
|
||||
<h2>Yesterday Volume</h2>
|
||||
<p><span data-valueupdate="yesterday_volume"><%= channels["abbflow.yesterday_volume"].value %></span> MCF</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -26,6 +26,24 @@
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<div class="row row-flex box-me">
|
||||
<div class='col-xs-8'>
|
||||
<div class="text-center">
|
||||
<h2>Last Note</h2>
|
||||
<p class="note-text"><%= channels['abbflow.notes'].value %></p>
|
||||
<p> at <%= channels["abbflow.notes"].timestamp %></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-4">
|
||||
<div class="text-center">
|
||||
<button href="#" data-channelId="<%= channels['abbflow.notes'].channelId %>" class="data-table btn btn-theme note-btn" title="Note History"><i style='margin-left: 0.5em; cursor: pointer' class="fa fa-th-list icon-theme"></i> All Notes</button>
|
||||
<br />
|
||||
<button type="button" class="btn btn-theme note-btn" data-toggle="modal" data-target="#note-modal"><i style='margin-left: 0.5em; cursor: pointer' class="fa fa-pencil icon-theme"></i> New Note</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='row row-flex box-me'>
|
||||
<div class='col-xs-4 text-center'>
|
||||
<h2>Volume Flow</h2>
|
||||
@@ -373,4 +391,23 @@
|
||||
letter-spacing: 1px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#note-modal{
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
position: relative;
|
||||
}
|
||||
.modal-dialog {
|
||||
top:5%;
|
||||
}
|
||||
.note-btn {
|
||||
margin-top: 10px;
|
||||
width: 75%;
|
||||
}
|
||||
.note-text {
|
||||
font-size: 1.5em;
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
1
html-templates/Sidebar.html
Normal file
1
html-templates/Sidebar.html
Normal file
@@ -0,0 +1 @@
|
||||
<a href="#" data-channelId="<%= channels['abbflow.sleeplog'].channelId %>" class="data-table" title="Sleep Log"><i style='margin-left: 0.5em; cursor: pointer' class="fa fa-th-list icon-theme"></i> Sleep Log</a>
|
||||
53
python-driver/abbflow.py
Normal file
53
python-driver/abbflow.py
Normal file
@@ -0,0 +1,53 @@
|
||||
"""Driver for connecting ABB Flowmeter to Meshify."""
|
||||
import threading
|
||||
import time
|
||||
from device_base import deviceBase
|
||||
from utilities import get_public_ip_address
|
||||
|
||||
WAIT_FOR_CONNECTION_SECONDS = 60
|
||||
IP_CHECK_PERIOD = 60
|
||||
|
||||
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 = "8"
|
||||
self.finished = threading.Event()
|
||||
self.public_ip_address = ""
|
||||
self.public_ip_address_last_checked = 0
|
||||
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."""
|
||||
for i in range(0, WAIT_FOR_CONNECTION_SECONDS):
|
||||
print("abbflow driver will start in {} seconds".format(WAIT_FOR_CONNECTION_SECONDS - i))
|
||||
time.sleep(1)
|
||||
|
||||
while True:
|
||||
if (time.time() - self.public_ip_address_last_checked) > IP_CHECK_PERIOD:
|
||||
self._check_ip_address()
|
||||
|
||||
def _check_ip_address(self):
|
||||
"""Check the public IP address and send to Meshify if changed."""
|
||||
print("Checking IP Address...")
|
||||
self.public_ip_address_last_checked = time.time()
|
||||
test_public_ip = get_public_ip_address()
|
||||
print("Got {} for IP Address".format(test_public_ip))
|
||||
if not test_public_ip == self.public_ip_address:
|
||||
self.sendtodbDev(1, 'public_ip_address', test_public_ip, 0, 'abbflow')
|
||||
self.public_ip_address = test_public_ip
|
||||
@@ -3,7 +3,7 @@
|
||||
"driverFileName":"abbflow.py",
|
||||
"deviceName":"abbflow",
|
||||
"driverId":"0110",
|
||||
"releaseVersion":"2",
|
||||
"releaseVersion":"8",
|
||||
"files": {
|
||||
"file1":"abbflow.py",
|
||||
"file2":"modbusMap.p" }
|
||||
11
python-driver/driverConfig.json
Normal file
11
python-driver/driverConfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "abbflow",
|
||||
"driverFilename": "abbflow.py",
|
||||
"driverId": "0110",
|
||||
"additionalDriverFiles": [
|
||||
"utilities.py",
|
||||
"modbusMap.p"
|
||||
],
|
||||
"version": 8,
|
||||
"s3BucketName": "abbflow"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
49
python-driver/utilities.py
Normal file
49
python-driver/utilities.py
Normal file
@@ -0,0 +1,49 @@
|
||||
"""Utility functions for the driver."""
|
||||
import socket
|
||||
import struct
|
||||
|
||||
|
||||
def get_public_ip_address():
|
||||
"""Find the public IP Address of the host device."""
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.connect(("8.8.8.8", 80))
|
||||
ip_address = sock.getsockname()[0]
|
||||
sock.close()
|
||||
return ip_address
|
||||
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user