Working POCloud driver and templates

This commit is contained in:
Patrick McDonagh
2018-07-31 10:03:38 -05:00
parent b7dbfeeef6
commit 293ba44107
15 changed files with 6949 additions and 6660 deletions

File diff suppressed because one or more lines are too long

BIN
POCloud/mobilelogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,3 @@
{
"python.pythonPath": "/usr/local/bin/python"
}

View File

@@ -0,0 +1,25 @@
id,name,deviceTypeId,fromMe,io,subTitle,helpExplanation,channelType,dataType,defaultValue,regex,regexErrMsg,units,min,max,change,guaranteedReportPeriod,minReportTime
13900,public_ip_address,464,FALSE,readonly,Public IP Address,Public IP of Device,device,string,Unknown,,,,,,,,
13901,watchdog,464,FALSE,readonly,Watchdog,Connection with PLC is OK,device,string,Unknown,,,,,,,,
,ft01_flowmeter_bpd,464,FALSE,readonly,Flowmeter BPD,BPD,device,float,0,,,,,,,,
,auto_manual,464,FALSE,readonly,Auto Mode,Auto/Manual,device,string,n/a,,,,,,,,
,ft01_flowmeter_gpm,464,FALSE,readonly,Flowmeter GPM,GPM,device,float,0,,,,,,,,
,lt11_pondlevel,464,FALSE,readonly,Pond 1 Level,Ft.,device,float,0,,,,,,,,
,lt21_pondlevel,464,FALSE,readonly,Pond 2 Level,Ft.,device,float,0,,,,,,,,
,pt11_dischargepressure,464,FALSE,readonly,System 1 Discharge Pressure,PSI,device,float,0,,,,,,,,
,pt21_dischargepressure,464,FALSE,readonly,System 2 Discharge Pressure,PSI,device,float,0,,,,,,,,
,flow_rate_setpoint,464,FALSE,readwrite,Flow Rate Setpoint,BPD,device,float,0,,,,,,,,
,system1_frequency_setpoint,464,FALSE,readwrite,System 1 Frequency Setpoint,Hz,device,float,0,,,,,,,,
,system2_frequency_setpoint,464,FALSE,readwrite,System 2 Frequency Setpoint,Hz,device,float,0,,,,,,,,
,ft01_flowmeter_bpd_yesterday,464,FALSE,readonly,Flow Total Yesterday,BBL,device,float,0,,,,,,,,
,ft01_flowmeter_bpd_today,464,FALSE,readonly,Flow Total Today,BBL,device,float,0,,,,,,,,
,system1_hasleveltransmitter,464,FALSE,readonly,System 1 Has Level Transmitter,Yes/No,device,string,n/a,,,,,,,,
,system2_hasleveltransmitter,464,FALSE,readonly,System 2 Has Level Transmitter,Yes/No,device,string,n/a,,,,,,,,
,mc11_motorfrequency,464,FALSE,readonly,System 1 Motor Frequency,Hz,device,float,0,,,,,,,,
,mc21_motorfrequency,464,FALSE,readonly,System 2 Motor Frequency,Hz,device,float,0,,,,,,,,
,log,464,FALSE,readonly,Device Log,Device Log,device,string,Commissioned.,,,,,,,,
,sync,464,FALSE,readwrite,Sync,Force Send,device,string,,,,,,,,,
,writeplctag,464,FALSE,readwrite,Write PLC Tag,writes a tag to the PLC,device,string,,,,,,,,,
,state_supervisor,464,FALSE,readonly,Supervisor State,Phase State,device,string,n/a,,,,,,,,
,state_system1,464,FALSE,readonly,System 1 State,Phase State,device,string,n/a,,,,,,,,
,state_system2,464,FALSE,readonly,System 2 State,Phase State,device,string,n/a,,,,,,,,
1 id name deviceTypeId fromMe io subTitle helpExplanation channelType dataType defaultValue regex regexErrMsg units min max change guaranteedReportPeriod minReportTime
2 13900 public_ip_address 464 FALSE readonly Public IP Address Public IP of Device device string Unknown
3 13901 watchdog 464 FALSE readonly Watchdog Connection with PLC is OK device string Unknown
4 ft01_flowmeter_bpd 464 FALSE readonly Flowmeter BPD BPD device float 0
5 auto_manual 464 FALSE readonly Auto Mode Auto/Manual device string n/a
6 ft01_flowmeter_gpm 464 FALSE readonly Flowmeter GPM GPM device float 0
7 lt11_pondlevel 464 FALSE readonly Pond 1 Level Ft. device float 0
8 lt21_pondlevel 464 FALSE readonly Pond 2 Level Ft. device float 0
9 pt11_dischargepressure 464 FALSE readonly System 1 Discharge Pressure PSI device float 0
10 pt21_dischargepressure 464 FALSE readonly System 2 Discharge Pressure PSI device float 0
11 flow_rate_setpoint 464 FALSE readwrite Flow Rate Setpoint BPD device float 0
12 system1_frequency_setpoint 464 FALSE readwrite System 1 Frequency Setpoint Hz device float 0
13 system2_frequency_setpoint 464 FALSE readwrite System 2 Frequency Setpoint Hz device float 0
14 ft01_flowmeter_bpd_yesterday 464 FALSE readonly Flow Total Yesterday BBL device float 0
15 ft01_flowmeter_bpd_today 464 FALSE readonly Flow Total Today BBL device float 0
16 system1_hasleveltransmitter 464 FALSE readonly System 1 Has Level Transmitter Yes/No device string n/a
17 system2_hasleveltransmitter 464 FALSE readonly System 2 Has Level Transmitter Yes/No device string n/a
18 mc11_motorfrequency 464 FALSE readonly System 1 Motor Frequency Hz device float 0
19 mc21_motorfrequency 464 FALSE readonly System 2 Motor Frequency Hz device float 0
20 log 464 FALSE readonly Device Log Device Log device string Commissioned.
21 sync 464 FALSE readwrite Sync Force Send device string
22 writeplctag 464 FALSE readwrite Write PLC Tag writes a tag to the PLC device string
23 state_supervisor 464 FALSE readonly Supervisor State Phase State device string n/a
24 state_system1 464 FALSE readonly System 1 State Phase State device string n/a
25 state_system2 464 FALSE readonly System 2 State Phase State device string n/a

View File

@@ -0,0 +1,244 @@
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<div class="row row-flex">
<div class="col-xs-12 text-center">
<h1>Control</h1>
</div>
<div class='col-xs-4 text-center box-me'>
<!-- Use data-confirm-message to set the exact message that pops up in the alert window. -->
<a href="#"
data-confirm-message="Are you sure you want to remotely start the well?"
data-refreshpause="1"
data-command=""
data-staticsend="{'tag': 'cmd_Start', 'val': 1}"
data-channelId="<%= channels["transferlite.writeplctag"].channelId %>"
data-techname="<%=channels["transferlite.writeplctag"].techName %>"
data-name="<%= channels["transferlite.writeplctag"].name%>"
data-nodechannelcurrentId="<%= channels["transferlite.writeplctag"].nodechannelcurrentId %>"
id="<%= channels["transferlite.writeplctag"].channelId %>"
class="btn btn-large btn-success confirmstatic pad15">
Start</a>
</div>
<div class='col-xs-4 text-center box-me'>
<a href="#"
data-confirm-message="Are you sure you want to remotely stop the well?"
data-refreshpause="1"
data-command=""
data-staticsend="{'tag': 'cmd_Stop', 'val': 1}"
data-channelId="<%= channels["transferlite.writeplctag"].channelId %>"
data-techname="<%=channels["transferlite.writeplctag"].techName %>"
data-name="<%= channels["transferlite.writeplctag"].name%>"
data-nodechannelcurrentId="<%= channels["transferlite.writeplctag"].nodechannelcurrentId %>"
id="<%= channels["transferlite.writeplctag"].channelId %>"
class="btn btn-large btn-danger confirmstatic pad15">
Stop</a>
</div>
<div class='col-xs-4 text-center box-me'>
<a href="#"
data-confirm-message="Are you sure you want to remotely reset alarms?"
data-refreshpause="1"
data-command=""
data-staticsend="{'tag': 'cmd_ResetAlarms', 'val': 1}"
data-channelId="<%= channels["transferlite.writeplctag"].channelId %>"
data-techname="<%=channels["transferlite.writeplctag"].techName %>"
data-name="<%= channels["transferlite.writeplctag"].name%>"
data-nodechannelcurrentId="<%= channels["transferlite.writeplctag"].nodechannelcurrentId %>"
id="<%= channels["transferlite.writeplctag"].channelId %>"
class="btn btn-large btn-warning confirmstatic pad15">
Reset Alarms</a>
</div>
</div>
<div class="row row-flex">
<div class="col-xs-12 text-center">
<h1>Auto Mode
<% if(channels['transferlite.auto_manual'].value === "Auto") { %>
<span class="label label-success">Active</span>
<% } %>
</h1>
</div>
<div class='col-xs-4 text-center box-me'>
<a href="#"
data-confirm-message="Are you sure you want to remotely activate auto mode?"
data-refreshpause="1"
data-command=""
data-staticsend="{'tag': 'cfg_Mode', 'val': 0}"
data-channelId="<%= channels["transferlite.writeplctag"].channelId %>"
data-techname="<%=channels["transferlite.writeplctag"].techName %>"
data-name="<%= channels["transferlite.writeplctag"].name%>"
data-nodechannelcurrentId="<%= channels["transferlite.writeplctag"].nodechannelcurrentId %>"
id="<%= channels["transferlite.writeplctag"].channelId %>"
class="btn btn-large btn-theme animated confirmstatic pad15">
Set Auto Mode</a>
</div>
<div class="col-md-4 box-me entry-top-level" id="flow_rate_setpoint">
<div class="pad15">
<h2>Flow Rate Setpoint</h2>
<form class="form-inline">
<div class="form-group">
<input class="form-control val_box"
type="number"
step="any"
value="<%=channels['transferlite.flow_rate_setpoint'].value %>">
</div>
<a href="#"
data-confirm-message="Are you sure you want to do this?"
data-refreshpause="1"
data-command=""
data-staticsend="{'tag': 'set_FlowRateSetpoint', 'val': <%=channels['transferlite.flow_rate_setpoint'].value %>}"
data-channelId="<%= channels["transferlite.writeplctag"].channelId %>"
data-techname="<%=channels["transferlite.writeplctag"].techName %>"
data-name="<%= channels["transferlite.writeplctag"].name%>"
data-nodechannelcurrentId="<%= channels["transferlite.writeplctag"].nodechannelcurrentId %>"
id="<%= channels["transferlite.writeplctag"].channelId %>"
class="btn btn-large btn-theme animated setstatic material-icons">send</a>
</form>
</div>
</div>
</div>
<div class="row row-flex">
<div class="col-xs-12 text-center">
<h1>Manual Mode
<% if(channels['transferlite.auto_manual'].value === "Manual") { %>
<span class="label label-success">Active</span>
<% } %>
</h1>
</div>
<div class='col-xs-4 text-center box-me'>
<a href="#"
data-confirm-message="Are you sure you want to remotely activate manual mode?"
data-refreshpause="1"
data-command=""
data-staticsend="{'tag': 'cfg_Mode', 'val': 1}"
data-channelId="<%= channels["transferlite.writeplctag"].channelId %>"
data-techname="<%=channels["transferlite.writeplctag"].techName %>"
data-name="<%= channels["transferlite.writeplctag"].name%>"
data-nodechannelcurrentId="<%= channels["transferlite.writeplctag"].nodechannelcurrentId %>"
id="<%= channels["transferlite.writeplctag"].channelId %>"
class="btn btn-large btn-theme animated confirmstatic pad15">
Set Manual Mode</a>
</div>
<div class="col-md-4 box-me entry-top-level" id="system1_frequency_setpoint">
<div class="pad15">
<h2>System 1 Frequency</h2>
<form class="form-inline">
<div class="form-group">
<input class="form-control val_box"
type="number"
step="any"
value="<%=channels['transferlite.system1_frequency_setpoint'].value %>">
</div>
<a href="#"
data-confirm-message="Are you sure you want to do this?"
data-refreshpause="1"
data-command=""
data-staticsend="{'tag': 'set_ManualFrequencySP_System1', 'val': <%=channels['transferlite.system1_frequency_setpoint'].value %>}"
data-channelId="<%= channels["transferlite.writeplctag"].channelId %>"
data-techname="<%=channels["transferlite.writeplctag"].techName %>"
data-name="<%= channels["transferlite.writeplctag"].name%>"
data-nodechannelcurrentId="<%= channels["transferlite.writeplctag"].nodechannelcurrentId %>"
id="<%= channels["transferlite.writeplctag"].channelId %>"
class="btn btn-large btn-theme animated setstatic material-icons">send</a>
</form>
</div>
</div>
<div class="col-md-4 box-me entry-top-level" id="system2_frequency_setpoint">
<div class="pad15">
<h2>System 2 Frequency</h2>
<form class="form-inline">
<div class="form-group">
<input class="form-control val_box"
type="number"
step="any"
value="<%=channels['transferlite.system2_frequency_setpoint'].value %>">
</div>
<a href="#"
data-confirm-message="Are you sure you want to do this?"
data-refreshpause="1"
data-command=""
data-staticsend="{'tag': 'set_ManualFrequencySP_System2', 'val': <%=channels['transferlite.system2_frequency_setpoint'].value %>}"
data-channelId="<%= channels["transferlite.writeplctag"].channelId %>"
data-techname="<%=channels["transferlite.writeplctag"].techName %>"
data-name="<%= channels["transferlite.writeplctag"].name%>"
data-nodechannelcurrentId="<%= channels["transferlite.writeplctag"].nodechannelcurrentId %>"
id="<%= channels["transferlite.writeplctag"].channelId %>"
class="btn btn-large btn-theme animated setstatic material-icons">send</a>
</form>
</div>
</div>
</div>
<script>
$('.val_box').each(function(topLevel){
$(this).change(function(){
var id = "#" + $(this).closest(".entry-top-level").attr('id');
if (id !== "#undefined"){
// console.log("before parse", $(id).find('.setstatic').attr('data-staticsend').replace(/'/g, '"'));
var jsobj = JSON.parse($(id).find('.setstatic').attr('data-staticsend').replace(/'/g, '"'));
// console.log("after parse", jsobj)
// var tagStart = $(id).find('.setstatic').attr('data-staticsend').indexOf("tag") + 3;
// var tagStop = $(id).find('.setstatic').attr('data-staticsend').indexOf("] ]");
// var tag = $(id).find('.setstatic').attr('data-staticsend').substring(tagStart, tagStop).split(',')[0].replace(/'/g,"");
var val = $(id).find('.val_box').val();
var newData = "{'tag': '" + jsobj.tag +"', 'val': " + val.toString() + "}"
var tag = $(id).find('.setstatic').attr('data-staticsend', newData);
console.log($(id).find('.setstatic').attr('data-staticsend'));
}
});
});
</script>
<style>
.box-me {
position: relative;
padding: 0.5em;
padding-bottom: 1.5em;
border: 1px solid #eee;
/*margin: 1em 0;*/
}
.box-me .gauge-box {
margin-top: -0.25em;
}
.pad15 {
margin: 15px 15px;
}
.box-me h2 {
text-transform: uppercase;
font-size: 14px;
color: #666;
font-weight: 400;
letter-spacing: 1px;
z-index: 100;
}
.dynamic-chart-form {
background-color: whiteSmoke;
padding: 1em 0.5em;
margin-top: 1em;
}
.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;
}
</style>

View File

@@ -1,6 +1,32 @@
<div class='col-xs-1'>
<div class="<%= nodecolors.statuscolor %> nodecolor"></div>
</div>
<div class='col-xs-6'>
<h3><%= node.vanityname %></h3>
<div id="node-detail-header">
<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-5'>
<h2>Status</h2>
<table id="states">
<tr><td>Overall:</td><td><%= channels['transferlite.state_supervisor'].value %></td></tr>
<tr><td>System 1:</td><td><%= channels['transferlite.state_system1'].value %></td></tr>
<tr><td>System 2:</td><td><%= channels['transferlite.state_system2'].value %></td></tr>
</table>
</div>
</div>
<style>
#node-detail-header h2 {
text-transform: uppercase;
font-size: 14px;
color: #aaa;
margin: 0.75em 0;
}
#states td {
font-size: 20px;
color: black;
font-weight: 600;
padding-right: 15px;
}
</style>

View File

@@ -14,6 +14,13 @@
color: black;
font-weight: 600;
}
#totals td {
font-size: 20px;
color: black;
font-weight: 600;
padding-right: 15px;
}
</style>
<div class="row header">
@@ -28,4 +35,13 @@
<div class="col-xs-4">
<h4><%= node.vanityname %></h4>
</div>
<div class="col-xs-4">
<h2>Totals</h2>
<table id="totals">
<tr><td>Today:</td><td><%= Math.round(channels['transferlite.ft01_flowmeter_bpd_today'].value) %> BBL</td></tr>
<tr><td>Yesterday:</td><td><%= Math.round(channels['transferlite.ft01_flowmeter_bpd_yesterday'].value) %> BBL</td></tr>
</table>
</div>
</div>

View File

@@ -1,121 +1,277 @@
<div class="box-me">
<div class="row row-flex">
<div class="make-gauge col-xs-4"
data-deviceName="transferlite"
data-channelName="ft01_flowmeter_bpd"
data-displayName="Flow Rate (BPD)"
data-units="BPD"
data-min="0"
data-max="100000"
data-decimalPlaces="0"
data-channelId="<%= channels['transferlite.ft01_flowmeter_bpd'].channelId %>"
data-timestamp="<%= channels['transferlite.ft01_flowmeter_bpd'].timestamp %>">
</div>
<div class="make-gauge col-xs-4"
data-deviceName="transferlite"
data-channelName="ft01_flowmeter_gpm"
data-displayName="Flow Rate (GPM)"
data-units="GPM"
data-min="0"
data-max="5000"
data-decimalPlaces="1"
data-channelId="<%= channels['transferlite.ft01_flowmeter_gpm'].channelId %>"
data-timestamp="<%= channels['transferlite.ft01_flowmeter_gpm'].timestamp %>">
</div>
<div class="col-xs-4 text-center">
<h2>Flow Totals</h2>
<table id="totals">
<tr><td>Today:</td><td><%= Math.round(channels['transferlite.ft01_flowmeter_bpd_today'].value * 10.0) / 10.0 %> BBL</td></tr>
<tr><td>Yesterday:</td><td><%= Math.round(channels['transferlite.ft01_flowmeter_bpd_yesterday'].value * 10.0) / 10.0 %> BBL</td></tr>
</table>
</div>
<div class="row row-flex box-me">
<div class="col-xs-12 text-center">
<h1>HEADER 1</h1>
</div>
<div class="col-xs-4 text-center">
<h2>CHANNEL 1</h2>
<div class="gauge-box">
<div data-labelheight="10"
style="height: 170px; background: transparent; margin: 0 auto;"
id="gauge-channel_1"
data-chart="solidgauge"
data-nodename="transferlite.channel_1"
data-units="UNITS"
data-min="0"
data-max="100"
data-decimalplaces="2"
data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B"
data-valuefontsize="18px">
</div>
<div class="box-me">
<div class="row">
<div class="col-xs-12 text-center">
<h1>System 1</h1>
</div>
</div>
<div class="row">
<% if(channels['transferlite.system1_hasleveltransmitter'].value === 'true') { %>
<div class="make-gauge col-xs-4"
data-deviceName="transferlite"
data-channelName="lt11_pondlevel"
data-displayName="Pond Level"
data-units="Ft"
data-min="0"
data-max="30"
data-decimalPlaces="2"
data-channelId="<%= channels['transferlite.lt11_pondlevel'].channelId %>"
data-timestamp="<%= channels['transferlite.lt11_pondlevel'].timestamp %>">
</div>
<div class- "timestamp-box">
<a href="#" data-channelId="<%= channels['transferlite.channel_1'].channelId %>" class="data-table" title="Download Channel History">
<i class="fa fa-download"></i>
</a>
<% } %>
<div class="make-gauge col-xs-4"
data-deviceName="transferlite"
data-channelName="mc11_motorfrequency"
data-displayName="Motor Frequency"
data-units="Hz"
data-min="0"
data-max="100"
data-decimalPlaces="2"
data-channelId="<%= channels['transferlite.mc11_motorfrequency'].channelId %>"
data-timestamp="<%= channels['transferlite.mc11_motorfrequency'].timestamp %>">
</div>
<div class="make-gauge col-xs-4"
data-deviceName="transferlite"
data-channelName="pt11_dischargepressure"
data-displayName="Discharge Pressure"
data-units="PSI"
data-min="0"
data-max="200"
data-decimalPlaces="1"
data-channelId="<%= channels['transferlite.pt11_dischargepressure'].channelId %>"
data-timestamp="<%= channels['transferlite.pt11_dischargepressure'].timestamp %>">
</div>
</div>
</div>
<div class="box-me">
<div class="row">
<div class="col-xs-12 text-center">
<h1>System 2</h1>
</div>
</div>
<div class="row">
<% if(channels['transferlite.system2_hasleveltransmitter'].value === 'true') { %>
<div class="make-gauge col-xs-4"
data-deviceName="transferlite"
data-channelName="lt21_pondlevel"
data-displayName="Pond Level"
data-units="Ft"
data-min="0"
data-max="30"
data-decimalPlaces="2"
data-channelId="<%= channels['transferlite.lt21_pondlevel'].channelId %>"
data-timestamp="<%= channels['transferlite.lt21_pondlevel'].timestamp %>">
</div>
<span data-timeupdate="channel_1">
<%= channels["transferlite.channel_1"].timestamp %>
</span>
<% } %>
<div class="make-gauge col-xs-4"
data-deviceName="transferlite"
data-channelName="mc21_motorfrequency"
data-displayName="Motor Frequency"
data-units="Hz"
data-min="0"
data-max="100"
data-decimalPlaces="2"
data-channelId="<%= channels['transferlite.mc21_motorfrequency'].channelId %>"
data-timestamp="<%= channels['transferlite.mc21_motorfrequency'].timestamp %>">
</div>
<div class="make-gauge col-xs-4"
data-deviceName="transferlite"
data-channelName="pt21_dischargepressure"
data-displayName="Discharge Pressure"
data-units="PSI"
data-min="0"
data-max="200"
data-decimalPlaces="1"
data-channelId="<%= channels['transferlite.pt21_dischargepressure'].channelId %>"
data-timestamp="<%= channels['transferlite.pt21_dischargepressure'].timestamp %>">
</div>
</div>
</div>
<style>
.box-me {
position: relative;
padding: 0.5em;
padding-bottom: 1.5em;
border: 1px solid #eee;
/*margin: 1em 0;*/
}
.box-me {
position: relative;
padding: 0.5em;
padding-bottom: 1.5em;
border: 1px solid #eee;
/*margin: 1em 0;*/
}
.box-me .gauge-box {
margin-top: -0.25em;
}
.box-me .gauge-box {
margin-top: -0.25em;
}
h2 {
text-transform: uppercase;
font-size: 14px;
color: #666;
font-weight: 400;
letter-spacing: 1px;
z-index: 100;
}
.pad15 {
margin: 15px 15px;
}
.dynamic-chart-form {
background-color: whiteSmoke;
padding: 1em 0.5em;
margin-top: 1em;
}
.box-me h2 {
text-transform: uppercase;
font-size: 14px;
color: #666;
font-weight: 400;
letter-spacing: 1px;
z-index: 100;
}
.row-flex {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
flex-wrap: wrap;
}
.dynamic-chart-form {
background-color: whiteSmoke;
padding: 1em 0.5em;
margin-top: 1em;
}
.row-flex>[class*='col-'] {
display: flex;
flex-direction: column;
}
.row-flex {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
flex-wrap: wrap;
}
#systemStatusTimelineContainer h2 {
text-transform: uppercase;
font-size: 14px;
color: #666;
font-weight: 400;
letter-spacing: 1px;
z-index: 100;
}
.row-flex > [class*='col-'] {
display: flex;
flex-direction: column;
}
.slice.node-detail hr {
border-color: #ccc;
}
#systemStatusTimelineContainer h2 {
text-transform: uppercase;
font-size: 14px;
color: #666;
font-weight: 400;
letter-spacing: 1px;
z-index: 100;
}
.slice.node-detail #alarms li {
margin-bottom: 1em;
padding: 0.5em;
}
.slice.node-detail hr {
border-color: #ccc;
}
.slice.node-detail #alarms li {
margin-bottom: 1em;
padding: 0.5em;
}
.slice.node-detail #alarms li:nth-child(even){
background-color: whiteSmoke;
}
.slice.node-detail #alarms li span {
margin-left: 1em;
color: #aaa;
}
.slice.node-detail #alarms li:nth-child(even) {
background-color: whiteSmoke;
}
.slice.node-detail #alarms li span {
margin-left: 1em;
color: #aaa;
}
#totals td {
font-size: 20px;
color: black;
font-weight: 600;
padding-right: 15px;
}
</style>
<script>
$('.val_box').each(function(topLevel){
$(this).change(function(){
var id = "#" + $(this).closest(".entry-top-level").attr('id');
if (id !== "#undefined"){
var val = $(id).find('.val_box').val();
var tag = $(id).find('.setstatic').attr('data-staticsend', val);
console.log($(id).find('.setstatic').attr('data-staticsend'));
}
$('.val_box').each(function (topLevel) {
$(this).change(function () {
var id = "#" + $(this).closest(".entry-top-level").attr('id');
if (id !== "#undefined") {
var val = $(id).find('.val_box').val();
var tag = $(id).find('.setstatic').attr('data-staticsend', val);
console.log($(id).find('.setstatic').attr('data-staticsend'));
}
});
});
});
</script>
$('.make-gauge').each(function (gaugeDiv) {
const deviceName = $(this).attr("data-deviceName");
const channelName = $(this).attr("data-channelName");
const displayName = $(this).attr("data-displayName");
const units = $(this).attr("data-units");
const min = $(this).attr("data-min");
const max = $(this).attr("data-max");
const decimalPlaces = $(this).attr("data-decimalPlaces");
const channelId = $(this).attr("data-channelId");
const timestamp = $(this).attr("data-timestamp");
const gaugeHTML = makeGauge(deviceName, channelName, displayName, units, min, max, decimalPlaces, channelId, timestamp);
$(this).html(gaugeHTML);
});
function makeGauge(deviceName, channelName, displayName, units, min, max, decimalPlaces, channelId, timestamp) {
return (
'<div class="text-center"> \
<h2>' + displayName + '</h2> \
<div class="gauge-box"> \
<div data-labelheight="10" \
style="height: 170px; background: transparent; margin: 0 auto;" \
id="gauge-' + channelName + '" \
data-chart="solidgauge" \
data-nodename="' + deviceName + '.' + channelName + '" \
data-units="'+ units + '" \
data-min="' + min + '" \
data-max="' + max + '" \
data-decimalplaces="' + decimalPlaces + '" \
data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" \
data-valuefontsize="18px"> \
</div> \
<div class- "timestamp-box"> \
<a href="#" data-channelId="' + channelId + '" class="data-table" title="Download Channel History"> \
<i class="fa fa-download"></i> \
</a> \
</div> \
<span data-timeupdate="' + channelName + '">' + timestamp + '</span> \
</div> \
</div>'
);
}
$('.val_box').each(function (topLevel) {
$(this).change(function () {
var id = "#" + $(this).closest(".entry-top-level").attr('id');
if (id !== "#undefined") {
var val = $(id).find('.val_box').val();
var tag = $(id).find('.setstatic').attr('data-staticsend', val);
console.log($(id).find('.setstatic').attr('data-staticsend'));
}
});
});
</script>

View File

@@ -18,7 +18,7 @@
data-ylabel=""
data-xlabel="Date"
data-units=""
data-channelnames="transferlite.channel_1,">
data-channelnames="transferlite.ft01_flowmeter_bpd,transferlite.ft01_flowmeter_gpm,transferlite.lt11_pondlevel,transferlite.lt21_pondlevel,transferlite.pt11_dischargepressure,transferlite.pt21_dischargepressure,transferlite.ft01_flowmeter_bpd_yesterday,transferlite.ft01_flowmeter_bpd_today,transferlite.flow_rate_setpoint,transferlite.system1_frequency_setpoint,transferlite.system2_frequency_setpoint,transferlite.mc11_motorfrequency,transferlite.mc21_motorfrequency">
</div>
<style>
.dynamic-chart-form {

View File

@@ -2,10 +2,12 @@
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
TAG_DATAERROR_SLEEPTIME = 5
def binarray(intval):
"""Split an integer into its bits."""
bin_string = '{0:08b}'.format(intval)
@@ -17,80 +19,72 @@ def binarray(intval):
def read_tag(addr, tag, plc_type="CLX"):
"""Read a tag from the PLC."""
direct = plc_type == "Micro800"
addr = str(addr)
tag = str(tag)
c = ClxDriver()
clx = ClxDriver()
try:
if c.open(addr, direct_connection=direct):
if clx.open(addr, direct_connection=direct):
try:
v = c.read_tag(tag)
return v
except DataError as e:
c.close()
val = clx.read_tag(tag)
return val
except DataError as err:
clx.close()
time.sleep(TAG_DATAERROR_SLEEPTIME)
print("Data Error during readTag({}, {}, plc_type='{}'): {}".format(addr, tag, plc_type, e))
else:
raise DataError("no data")
log.error("Data Error during readTag({}, {}): {}".format(addr, tag, err))
except CommError:
# err = c.get_status()
c.close()
print("Could not connect during readTag({}, {})".format(addr, tag))
# print err
except AttributeError as e:
c.close()
print("AttributeError during readTag({}, {}): \n{}".format(addr, tag, e))
c.close()
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"
c = ClxDriver()
if c.open(addr, direct_connection=direct):
clx = ClxDriver()
if clx.open(addr, direct_connection=direct):
arr_vals = []
try:
for i in range(start, end):
tag_w_index = tag + "[{}]".format(i)
v = c.read_tag(tag_w_index)
# print('{} - {}'.format(tag_w_index, v))
arr_vals.append(round(v[0], 4))
# print(v)
val = clx.read_tag(tag_w_index)
arr_vals.append(round(val[0], 4))
if arr_vals:
return arr_vals
print("No length for {}".format(addr))
return False
else:
log.error("No length for {}".format(addr))
return False
except Exception:
print("Error during readArray({}, {}, {}, {})".format(addr, tag, start, end))
err = c.get_status()
c.close()
print(err)
return False
c.close()
return False
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"
c = ClxDriver()
clx = ClxDriver()
try:
if c.open(addr, direct_connection=direct):
if clx.open(addr, direct_connection=direct):
try:
cv = c.read_tag(tag)
print(cv)
wt = c.write_tag(tag, val, cv[1])
return wt
except Exception:
print("Error during writeTag({}, {}, {})".format(addr, tag, val))
err = c.get_status()
c.close()
print(err)
c.close()
except CommError:
# err = c.get_status()
c.close()
print("Could not connect during writeTag({}, {}, {})".format(addr, tag, val))
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."""
@@ -122,7 +116,7 @@ class Channel(object):
elif self.value is None:
send_needed = True
send_reason = "no value"
elif not (self.value == new_value):
elif self.value != new_value:
if self.map_:
if not self.value == self.map_[new_value]:
send_needed = True
@@ -158,12 +152,12 @@ class Channel(object):
try:
self.value = self.map_[new_value]
except KeyError:
print("Cannot find a map value for {} in {} for {}".format(new_value, self.map_, self.mesh_name))
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()
print("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason))
log.info("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason))
return send_needed
def read(self):
@@ -179,7 +173,7 @@ def identity(sent):
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, transformFn=identity):
def __init__(self, mesh_name, register_number, data_type, chg_threshold, guarantee_sec, channel_size=1, map_=False, write_enabled=False, transform_fn=identity):
"""Initialize the channel."""
super(ModbusChannel, self).__init__(mesh_name, data_type, chg_threshold, guarantee_sec, map_, write_enabled)
self.mesh_name = mesh_name
@@ -193,11 +187,11 @@ class ModbusChannel(Channel):
self.guarantee_sec = guarantee_sec
self.map_ = map_
self.write_enabled = write_enabled
self.transformFn = transformFn
self.transform_fn = transform_fn
def read(self, mbsvalue):
"""Return the transformed read value."""
return self.transformFn(mbsvalue)
return self.transform_fn(mbsvalue)
class PLCChannel(Channel):
@@ -235,6 +229,7 @@ class BoolArrayChannels(Channel):
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
@@ -255,7 +250,7 @@ class BoolArrayChannels(Channel):
if new_val_dict[idx] != self.last_value[idx]:
send = True
except KeyError:
print("Key Error in self.compare_values for index {}".format(idx))
log.error("Key Error in self.compare_values for index {}".format(idx))
send = True
return send
@@ -264,15 +259,15 @@ class BoolArrayChannels(Channel):
send_needed = False
send_reason = ""
if self.plc_tag:
v = read_tag(self.plc_ip, self.plc_tag)
if v:
bool_arr = binarray(v[0])
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:
print("Not able to get value for index {}".format(idx))
log.error("Not able to get value for index {}".format(idx))
if self.last_send_time == 0:
send_needed = True
@@ -294,5 +289,5 @@ class BoolArrayChannels(Channel):
self.value = new_val
self.last_value = self.value
self.last_send_time = time.time()
print("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason))
log.info("Sending {} for {} - {}".format(self.value, self.mesh_name, send_reason))
return send_needed

View File

@@ -1,12 +1,12 @@
{
"driverFileName": "transferlite.py",
"deviceName": "transferlite",
"driverId": "0230",
"releaseVersion": "1",
"files": {
"file1": "transferlite.py",
"file2": "utilities.py",
"file3": "persistence.py",
"file4": "Channel.py"
}
"file3": "channel.py",
"file2": "utilities.py",
"file1": "transferlite.py",
"file4": "file_logger.py"
},
"deviceName": "transferlite",
"driverId": "0230",
"releaseVersion": "2",
"driverFileName": "transferlite.py"
}

View File

@@ -1,12 +1,12 @@
{
"name": "transferlite",
"driverFilename": "transferlite.py",
"driverId": "0000",
"name": "transferlite",
"driverFilename": "transferlite.py",
"driverId": "0230",
"additionalDriverFiles": [
"utilities.py",
"persistence.py",
"Channel.py"
],
"version": 1,
"utilities.py",
"channel.py",
"file_logger.py"
],
"version": 2,
"s3BucketName": "transferlite"
}

View File

@@ -0,0 +1,18 @@
"""Logging setup for {{cookiecutter.driver_name}}"""
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 = './{{cookiecutter.driver_name}}.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('{{cookiecutter.driver_name}}')
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

@@ -7,55 +7,67 @@ import time
import logging
from random import randint
from device_base import deviceBase
from Channel import PLCChannel, read_tag, write_tag
import persistence
from channel import PLCChannel, read_tag, write_tag
from utilities import get_public_ip_address
from file_logger import filelogger as log
_ = None
log.info("transferlite startup")
# LOGGING SETUP
from logging.handlers import RotatingFileHandler
TRUE_FALSE = {
0: "false",
1: "true"
}
log_formatter = logging.Formatter('%(asctime)s %(levelname)s %(funcName)s(%(lineno)d) %(message)s')
logFile = './transferlite.log'
my_handler = RotatingFileHandler(logFile, mode='a', maxBytes=500*1024,
backupCount=2, encoding=None, delay=0)
my_handler.setFormatter(log_formatter)
my_handler.setLevel(logging.INFO)
logger = logging.getLogger('transferlite')
logger.setLevel(logging.INFO)
logger.addHandler(my_handler)
AUTO_MANUAL = {
0: "Auto",
1: "Manual"
}
console_out = logging.StreamHandler(sys.stdout)
console_out.setFormatter(log_formatter)
logger.addHandler(console_out)
logger.info("transferlite startup")
PHASE_STATES = {
1: "Running",
2: "Holding",
4: "Restarting",
8: "Stopping",
16: "Aborting",
32: "Resetting",
64: "Idle",
128: "Held",
256: "Complete",
512: "Stopped",
1024: "Aborted"
}
# GLOBAL VARIABLES
WAIT_FOR_CONNECTION_SECONDS = 15
WAIT_FOR_CONNECTION_SECONDS = 60
IP_CHECK_PERIOD = 60
WATCHDOG_ENABLE = True
WATCHDOG_SEND_PERIOD = 3600 # Seconds, the longest amount of time before sending watchdog status
PLC_IP_ADDRESS = "10.20.4.37"
WATCHDOG_CHECK_PERIOD = 60
WATCHDOG_SEND_PERIOD = 3600 # Seconds, the longest amount of time before sending the watchdog status
PLC_IP_ADDRESS = "192.168.1.10"
CHANNELS = [
PLCChannel(PLC_IP_ADDRESS, "ft01_flowmeter_bpd", "FT01_Flowmeter_BPD", "REAL", 100.0, 600),
PLCChannel(PLC_IP_ADDRESS, "auto_manual", "sts_autoMode", "BOOL", 1, 600),
PLCChannel(PLC_IP_ADDRESS, "auto_manual", "sts_autoMode", "STRING", 1, 600, map_=AUTO_MANUAL),
PLCChannel(PLC_IP_ADDRESS, "ft01_flowmeter_gpm", "FT01_Flowmeter.val", "REAL", 10.0, 600),
PLCChannel(PLC_IP_ADDRESS, "lt11_pondlevel", "LT11_PondLevel.val", "REAL", 1.0, 600),
PLCChannel(PLC_IP_ADDRESS, "lt21_pondlevel", "LT21_PondLevel.val", "REAL", 1.0, 600),
PLCChannel(PLC_IP_ADDRESS, "system1_hasleveltransmitter", "cfg_System1.hasLevelTransmitter", "STRING", 1.0, 600, map_=TRUE_FALSE),
PLCChannel(PLC_IP_ADDRESS, "system2_hasleveltransmitter", "cfg_System2.hasLevelTransmitter", "STRING", 1.0, 600, map_=TRUE_FALSE),
PLCChannel(PLC_IP_ADDRESS, "pt11_dischargepressure", "PT11_DischargePressure.val", "REAL", 10, 600),
PLCChannel(PLC_IP_ADDRESS, "pt21_dischargepressure", "PT21_DischargePressure.val", "REAL", 10, 600),
PLCChannel(PLC_IP_ADDRESS, "flow_rate_setpoint", "set_FlowRateSetpoint", "REAL", 1.0, 600),
PLCChannel(PLC_IP_ADDRESS, "system1_frequency_setpoint", "set_ManualFrequencySP_System1", "REAL", 1.0, 600),
PLCChannel(PLC_IP_ADDRESS, "system2_frequency_setpoint", "set_ManualFrequencySP_System2", "REAL", 1.0, 600),
PLCChannel(PLC_IP_ADDRESS, "ft01_flowmeter_bpd_yesterday", "FT01_Flowmeter_History[1]", "REAL", 1.0, 600),
PLCChannel(PLC_IP_ADDRESS, "ft01_flowmeter_bpd_today", "FT01_Flowmeter_History[0]", "REAL",100.0, 600)
PLCChannel(PLC_IP_ADDRESS, "ft01_flowmeter_bpd_today", "FT01_Flowmeter_History[0]", "REAL",100.0, 600),
PLCChannel(PLC_IP_ADDRESS, "mc11_motorfrequency", "MC11_Pump.status.speedFeedback", "REAL", 5.0, 600),
PLCChannel(PLC_IP_ADDRESS, "mc21_motorfrequency", "MC21_Pump.status.speedFeedback", "REAL", 5.0, 600),
PLCChannel(PLC_IP_ADDRESS, "state_supervisor", "Supervisor.State", "STRING", 1.0, 600, map_=PHASE_STATES),
PLCChannel(PLC_IP_ADDRESS, "state_system1", "System1.State", "STRING", 1.0, 600, map_=PHASE_STATES),
PLCChannel(PLC_IP_ADDRESS, "state_system2", "System2.State", "STRING", 1.0, 600, map_=PHASE_STATES)
]
# PERSISTENCE FILE
PERSIST = persistence.load()
class start(threading.Thread, deviceBase):
"""Start class required by Meshify."""
@@ -69,7 +81,7 @@ class start(threading.Thread, deviceBase):
mqtt=mqtt, Nodes=Nodes)
self.daemon = True
self.version = "1"
self.version = "2"
self.finished = threading.Event()
self.force_send = False
self.public_ip_address = ""
@@ -90,7 +102,7 @@ class start(threading.Thread, deviceBase):
for i in range(0, WAIT_FOR_CONNECTION_SECONDS):
print("transferlite driver will start in {} seconds".format(WAIT_FOR_CONNECTION_SECONDS - i))
time.sleep(1)
logger.info("BOOM! Starting transferlite driver...")
log.info("BOOM! Starting transferlite driver...")
self._check_ip_address()
self._check_watchdog()
@@ -98,13 +110,11 @@ class start(threading.Thread, deviceBase):
self.nodes["transferlite_0199"] = self
send_loops = 0
watchdog_check_after = 60
ip_check_after = 60
while True:
now = time.time()
if self.force_send:
logger.warning("FORCE SEND: TRUE")
log.warning("FORCE SEND: TRUE")
for chan in CHANNELS:
read_val = chan.read()
@@ -116,17 +126,17 @@ class start(threading.Thread, deviceBase):
# print("transferlite driver still alive...")
if self.force_send:
if send_loops > 2:
logger.warning("Turning off force_send")
log.warning("Turning off force_send")
self.force_send = False
send_loops = 0
else:
send_loops += 1
if WATCHDOG_ENABLE:
if (now - self.watchdog_last_checked) > watchdog_check_after:
if (now - self.watchdog_last_checked) > WATCHDOG_CHECK_PERIOD:
self._check_watchdog()
if (now - self.public_ip_address_last_checked) > ip_check_after:
if (now - self.public_ip_address_last_checked) > IP_CHECK_PERIOD:
self._check_ip_address()
@@ -172,7 +182,7 @@ class start(threading.Thread, deviceBase):
tag_n = str(new_val['tag']) # "cmd_Start"
val_n = new_val['val']
w = write_tag(str(PLC_IP_ADDRESS), tag_n, val_n)
logger.info("Result of transferlite_writeplctag(self, {}, {}) = {}".format(name, value, w))
log.info("Result of transferlite_writeplctag(self, {}, {}) = {}".format(name, value, w))
if w is None:
w = "Error writing to PLC..."
return w