Working POCloud driver and templates
This commit is contained in:
File diff suppressed because one or more lines are too long
BIN
POCloud/mobilelogo.png
Normal file
BIN
POCloud/mobilelogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
1
POCloud/transferlite/.pytest_cache/v/cache/nodeids
vendored
Normal file
1
POCloud/transferlite/.pytest_cache/v/cache/nodeids
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
3
POCloud/transferlite/.vscode/settings.json
vendored
Normal file
3
POCloud/transferlite/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"python.pythonPath": "/usr/local/bin/python"
|
||||
}
|
||||
25
POCloud/transferlite/channels_transferlite.csv
Normal file
25
POCloud/transferlite/channels_transferlite.csv
Normal 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,,,,,,,,
|
||||
|
244
POCloud/transferlite/html-templates/Control.html
Normal file
244
POCloud/transferlite/html-templates/Control.html
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
18
POCloud/transferlite/python-driver/file_logger.py
Normal file
18
POCloud/transferlite/python-driver/file_logger.py
Normal 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)
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user