Copied files from vfd-ipp, updated to generate channels and functions

This commit is contained in:
Patrick McDonagh
2016-04-27 14:55:24 -05:00
parent c25b5f0e2b
commit 790611ac94
25 changed files with 18753 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
MainHP - http://s3.amazonaws.com/device-drivers/multitech/OCG/mainMeshify/
M1 - http://s3.amazonaws.com/device-drivers/M1V2/M1/
ipp - https://s3.amazonaws.com/meshify-devicedrivers/ipp/

View File

@@ -0,0 +1,498 @@
<form class='set_channel'>
<br />
<div class="pad15">
<button class='btn btn-theme btn-block set_channel_btn' value='Save'>APPLY CHANGES</button>
</div>
<br />
<div class="text-center"><h1>CONTROL</h1></div>
<div class="row row-flex">
<div class='col-xs-12 text-center box-me'>
<div class="col-xs-6 col-xs-offset-3">
<h2>Motor Speed Reference (Hz)</h2>
<input class="form-control" data-channelId='<%= channels["vfdipp.vfdspeedref"].channelId %>'
data-techName='<%=channels["vfdipp.vfdspeedref"].techName %>'
data-name='<%= channels["vfdipp.vfdspeedref"].name %>'
data-val="<%=channels["vfdipp.vfdspeedref"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.vfdspeedref"].channelId %>"
value="<%=channels["vfdipp.vfdspeedref"].value %>">
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<h2>Start Command</h2>
<input type="toggle" data-checkedValue="1" data-uncheckedValue="0" data-valueupdate="startcommand" data-channelId='<%= channels["vfdipp.startcommand"].channelId %>' data-techName='<%=channels["vfdipp.startcommand"].techName %>' data-name='vfdipp.startcommand' id="<%= channels["vfdipp.startcommand"].channelId %>" name="<%= channels["vfdipp.startcommand"].channelId %>">
</div>
<div class='col-xs-4 text-center box-me'>
<h2>Stop Command</h2>
<input type="toggle" data-checkedValue="1" data-uncheckedValue="0" data-valueupdate="stopcommand" data-channelId='<%= channels["vfdipp.stopcommand"].channelId %>' data-techName='<%=channels["vfdipp.stopcommand"].techName %>' data-name='vfdipp.stopcommand' id="<%= channels["vfdipp.stopcommand"].channelId %>" name="<%= channels["vfdipp.stopcommand"].channelId %>">
</div>
<div class='col-xs-4 text-center box-me'>
<h2>Clear VFD Fault</h2>
<input type="toggle" data-checkedValue="1" data-uncheckedValue="0" data-valueupdate="vfdclearfault" data-channelId='<%= channels["vfdipp.vfdclearfault"].channelId %>' data-techName='<%=channels["vfdipp.vfdclearfault"].techName %>' data-name='vfdipp.vfdclearfault' id="<%= channels["vfdipp.vfdclearfault"].channelId %>" name="<%= channels["vfdipp.vfdclearfault"].channelId %>">
</div>
</div>
<div class="text-center"><h1>VFD CONFIGURATION</h1></div>
<div class="row row-flex">
<div class="col-md-6 box-me">
<h2>MOTOR NAMEPLATE DATA</h2>
<table class="table">
<tbody>
<tr>
<td>Motor FLA (A)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.vfdnameplatefla"].channelId %>'
data-techName='<%=channels["vfdipp.vfdnameplatefla"].techName %>'
data-name='<%= channels["vfdipp.vfdnameplatefla"].name %>'
data-val="<%=channels["vfdipp.vfdnameplatefla"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.vfdnameplatefla"].channelId %>"
value="<%=channels["vfdipp.vfdnameplatefla"].value %>">
</td>
</tr>
<tr>
<td>Motor HP (HP)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.vfdnameplatehp"].channelId %>'
data-techName='<%=channels["vfdipp.vfdnameplatehp"].techName %>'
data-name='<%= channels["vfdipp.vfdnameplatehp"].name %>'
data-val="<%=channels["vfdipp.vfdnameplatehp"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.vfdnameplatehp"].channelId %>"
value="<%=channels["vfdipp.vfdnameplatehp"].value %>">
</td>
</tr>
<tr>
<td>Motor RPM (RPM)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.vfdnameplaterpm"].channelId %>'
data-techName='<%=channels["vfdipp.vfdnameplaterpm"].techName %>'
data-name='<%= channels["vfdipp.vfdnameplaterpm"].name %>'
data-val="<%=channels["vfdipp.vfdnameplaterpm"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.vfdnameplaterpm"].channelId %>"
value="<%=channels["vfdipp.vfdnameplaterpm"].value %>">
</td>
</tr>
<tr>
<td>Motor Frequency (Hz)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.vfdnameplatehz"].channelId %>'
data-techName='<%=channels["vfdipp.vfdnameplatehz"].techName %>'
data-name='<%= channels["vfdipp.vfdnameplatehz"].name %>'
data-val="<%=channels["vfdipp.vfdnameplatehz"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.vfdnameplatehz"].channelId %>"
value="<%=channels["vfdipp.vfdnameplatehz"].value %>">
</td>
</tr>
<tr>
<td>Motor Overload Current (A)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.vfdnameplateolcurrent"].channelId %>'
data-techName='<%=channels["vfdipp.vfdnameplateolcurrent"].techName %>'
data-name='<%= channels["vfdipp.vfdnameplateolcurrent"].name %>'
data-val="<%=channels["vfdipp.vfdnameplateolcurrent"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.vfdnameplateolcurrent"].channelId %>"
value="<%=channels["vfdipp.vfdnameplateolcurrent"].value %>">
</td>
</tr>
<tr>
<td>Motor Volts (V)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.vfdnameplatevolts"].channelId %>'
data-techName='<%=channels["vfdipp.vfdnameplatevolts"].techName %>'
data-name='<%= channels["vfdipp.vfdnameplatevolts"].name %>'
data-val="<%=channels["vfdipp.vfdnameplatevolts"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.vfdnameplatevolts"].channelId %>"
value="<%=channels["vfdipp.vfdnameplatevolts"].value %>">
</td>
</tr>
<tr>
<td>Motor Poles</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.vfdmotorpoles"].channelId %>'
data-techName='<%=channels["vfdipp.vfdmotorpoles"].techName %>'
data-name='<%= channels["vfdipp.vfdmotorpoles"].name %>'
data-val="<%=channels["vfdipp.vfdmotorpoles"].value %>"
type="number"
id="<%= channels["vfdipp.vfdmotorpoles"].channelId %>"
value="<%=channels["vfdipp.vfdmotorpoles"].value %>">
</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-6 box-me">
<h2>VFD SETTINGS</h2>
<table class="table">
<tbody>
<tr>
<td>Min. Frequency (Hz)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.vfdminfreq"].channelId %>'
data-techName='<%=channels["vfdipp.vfdminfreq"].techName %>'
data-name='<%= channels["vfdipp.vfdminfreq"].name %>'
data-val="<%=channels["vfdipp.vfdminfreq"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.vfdminfreq"].channelId %>"
value="<%=channels["vfdipp.vfdminfreq"].value %>">
</td>
</tr>
<tr>
<td>Max. Frequency (Hz)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.vfdmaxfreq"].channelId %>'
data-valueupdate="vfdmaxfreq"
data-techName='<%=channels["vfdipp.vfdmaxfreq"].techName %>'
data-name='<%= channels["vfdipp.vfdmaxfreq"].name %>'
data-val="<%=channels["vfdipp.vfdmaxfreq"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.vfdmaxfreq"].channelId %>"
value="<%=channels["vfdipp.vfdmaxfreq"].value %>">
</td>
</tr>
<tr>
<td>Accel. Time (sec)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.vfdacceltime"].channelId %>'
data-techName='<%=channels["vfdipp.vfdacceltime"].techName %>'
data-name='<%= channels["vfdipp.vfdacceltime"].name %>'
data-val="<%=channels["vfdipp.vfdacceltime"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.vfdacceltime"].channelId %>"
value="<%=channels["vfdipp.vfdacceltime"].value %>">
</td>
</tr>
<tr>
<td>Decel. Time (sec)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.vfddeceltime"].channelId %>'
data-techName='<%=channels["vfdipp.vfddeceltime"].techName %>'
data-name='<%= channels["vfdipp.vfddeceltime"].name %>'
data-val="<%=channels["vfdipp.vfddeceltime"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.vfddeceltime"].channelId %>"
value="<%=channels["vfdipp.vfddeceltime"].value %>">
</td>
</tr>
<tr>
<td>Stop Mode</td>
<td>
<% if (channels["vfdipp.vfdstopmode"].value == 0) { %>
<span class="label label-success">Coast</span>
<% } else if (channels["vfdipp.vfdstopmode"].value == 1) { %>
<span class="label label-danger">Ramp</span>
<% } else if (channels["vfdipp.vfdstopmode"].value == 2) { %>
<span class="label label-danger">Ramp to Hold</span>
<% } else if (channels["vfdipp.vfdstopmode"].value == 3) { %>
<span class="label label-danger">DC Brake</span>
<% } else if (channels["vfdipp.vfdstopmode"].value == 4) { %>
<span class="label label-danger">DCBrkAutoOff</span>
<% } else if (channels["vfdipp.vfdstopmode"].value == 5) { %>
<span class="label label-danger">Current Limit</span>
<% } else if (channels["vfdipp.vfdstopmode"].value == 6) { %>
<span class="label label-danger">Fast Brake</span>
<% } %>
</td>
</tr>
<tr>
<td>Torque Perf. Mode</td>
<td>
<% if (channels["vfdipp.vfdtorqueperfmode"].value == 0){ %>
<span class="label label-danger">V/Hz</span>
<% } else if (channels["vfdipp.vfdtorqueperfmode"].value == 1){ %>
<span class="label label-success">SVC</span>
<% } else if (channels["vfdipp.vfdtorqueperfmode"].value == 2){ %>
<span class="label label-danger">Economize</span>
<% } else if (channels["vfdipp.vfdtorqueperfmode"].value == 3){ %>
<span class="label label-danger">Vector</span>
<% } %>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="text-center"><h1>DOWNHOLE CONFIGURATION</h1></div>
<div class="row row-flex">
<div class='col-xs-12 text-center box-me'>
<h2>Downhole Sensor Enabled</h2>
<input type="toggle" data-checkedValue="1" data-uncheckedValue="0" data-valueupdate="downholetoolenabled" data-channelId='<%= channels["vfdipp.downholetoolenabled"].channelId %>' data-techName='<%=channels["vfdipp.downholetoolenabled"].techName %>' data-name='vfdipp.downholetoolenabled' id="<%= channels["vfdipp.downholetoolenabled"].channelId %>" name="<%= channels["vfdipp.downholetoolenabled"].channelId %>">
</div>
<div class='col-xs-6 text-center box-me'>
<h2>Pressure Trip</h2>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>Pressure Shutdown Enabled</td>
<td>
<input type="toggle" data-checkedValue="1" data-uncheckedValue="0" data-valueupdate="dhpressureshutdownenabled" data-channelId='<%= channels["vfdipp.dhpressureshutdownenabled"].channelId %>' data-techName='<%=channels["vfdipp.dhpressureshutdownenabled"].techName %>' data-name='vfdipp.dhpressureshutdownenabled' id="<%= channels["vfdipp.dhpressureshutdownenabled"].channelId %>" name="<%= channels["vfdipp.dhpressureshutdownenabled"].channelId %>">
</td>
</tr>
<tr>
<td>Pressure Shutdown Limit (PSI)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.dhpressureshutdownlimit"].channelId %>'
data-techName='<%=channels["vfdipp.dhpressureshutdownlimit"].techName %>'
data-name='<%= channels["vfdipp.dhpressureshutdownlimit"].name %>'
data-val="<%=channels["vfdipp.dhpressureshutdownlimit"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.dhpressureshutdownlimit"].channelId %>"
value="<%=channels["vfdipp.dhpressureshutdownlimit"].value %>">
</td>
</tr>
<tr>
<td>Pressure Restart Enabled</td>
<td>
<input type="toggle" data-checkedValue="1" data-uncheckedValue="0" data-valueupdate="dhpressurestartupenabled" data-channelId='<%= channels["vfdipp.dhpressurestartupenabled"].channelId %>' data-techName='<%=channels["vfdipp.dhpressurestartupenabled"].techName %>' data-name='vfdipp.dhpressurestartupenabled' id="<%= channels["vfdipp.dhpressurestartupenabled"].channelId %>" name="<%= channels["vfdipp.dhpressurestartupenabled"].channelId %>">
</td>
</tr>
<tr>
<td>Pressure Startup Limit (PSI)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.dhpressurestartup"].channelId %>'
data-techName='<%=channels["vfdipp.dhpressurestartup"].techName %>'
data-name='<%= channels["vfdipp.dhpressurestartup"].name %>'
data-val="<%=channels["vfdipp.dhpressurestartup"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.dhpressurestartup"].channelId %>"
value="<%=channels["vfdipp.dhpressurestartup"].value %>">
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class='col-xs-6 text-center box-me'>
<h2>Temperature Trip</h2>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>Temp. Shutdown Enabled</td>
<td>
<input type="toggle" data-checkedValue="1" data-uncheckedValue="0" data-valueupdate="dhtempshutdownenabled" data-channelId='<%= channels["vfdipp.dhtempshutdownenabled"].channelId %>' data-techName='<%=channels["vfdipp.dhtempshutdownenabled"].techName %>' data-name='vfdipp.dhtempshutdownenabled' id="<%= channels["vfdipp.dhtempshutdownenabled"].channelId %>" name="<%= channels["vfdipp.dhtempshutdownenabled"].channelId %>">
</td>
</tr>
<tr>
<td>Temp. Shutdown Limit (&deg;F)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.dhtempshutdown"].channelId %>'
data-techName='<%=channels["vfdipp.dhtempshutdown"].techName %>'
data-name='<%= channels["vfdipp.dhtempshutdown"].name %>'
data-val="<%=channels["vfdipp.dhtempshutdown"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.dhtempshutdown"].channelId %>"
value="<%=channels["vfdipp.dhtempshutdown"].value %>">
</td>
</tr>
<tr>
<td>Temp. Restart Enabled</td>
<td>
<input type="toggle" data-checkedValue="1" data-uncheckedValue="0" data-valueupdate="dhtempstartupenabled" data-channelId='<%= channels["vfdipp.dhtempstartupenabled"].channelId %>' data-techName='<%=channels["vfdipp.dhtempstartupenabled"].techName %>' data-name='vfdipp.dhtempstartupenabled' id="<%= channels["vfdipp.dhtempstartupenabled"].channelId %>" name="<%= channels["vfdipp.dhtempstartupenabled"].channelId %>">
</td>
</tr>
<tr>
<td>Temp. Startup Limit (&deg;F)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.dhtempstartuplimit"].channelId %>'
data-techName='<%=channels["vfdipp.dhtempstartuplimit"].techName %>'
data-name='<%= channels["vfdipp.dhtempstartuplimit"].name %>'
data-val="<%=channels["vfdipp.dhtempstartuplimit"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.dhtempstartuplimit"].channelId %>"
value="<%=channels["vfdipp.dhtempstartuplimit"].value %>">
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="text-center"><h1>PRESSURE TRANSDUCER CONFIGURATION</h1></div>
<div class="row row-flex">
<div class='col-xs-12 text-center box-me'>
<h2>Tubing Pressure Transducer Enabled</h2>
<input type="toggle" data-checkedValue="1" data-uncheckedValue="0" data-valueupdate="tubingpressuretransducerenabled" data-channelId='<%= channels["vfdipp.tubingpressuretransducerenabled"].channelId %>' data-techName='<%=channels["vfdipp.tubingpressuretransducerenabled"].techName %>' data-name='vfdipp.tubingpressuretransducerenabled' id="<%= channels["vfdipp.tubingpressuretransducerenabled"].channelId %>" name="<%= channels["vfdipp.tubingpressuretransducerenabled"].channelId %>">
</div>
<div class='col-xs-6 text-center box-me'>
<h2>Scaling Values</h2>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>Min Value (PSI)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.tubingpressureeumin"].channelId %>'
data-techName='<%=channels["vfdipp.tubingpressureeumin"].techName %>'
data-name='<%= channels["vfdipp.tubingpressureeumin"].name %>'
data-val="<%=channels["vfdipp.tubingpressureeumin"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.tubingpressureeumin"].channelId %>"
value="<%=channels["vfdipp.tubingpressureeumin"].value %>">
</td>
</tr>
<tr>
<td>Max Value (PSI)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.tubingpressureeumax"].channelId %>'
data-techName='<%=channels["vfdipp.tubingpressureeumax"].techName %>'
data-name='<%= channels["vfdipp.tubingpressureeumax"].name %>'
data-val="<%=channels["vfdipp.tubingpressureeumax"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.tubingpressureeumax"].channelId %>"
value="<%=channels["vfdipp.tubingpressureeumax"].value %>">
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class='col-xs-6 text-center box-me'>
<h2>Trip Settings</h2>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>Low Limit (PSI)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.tubingpressurelosp"].channelId %>'
data-techName='<%=channels["vfdipp.tubingpressurelosp"].techName %>'
data-name='<%= channels["vfdipp.tubingpressurelosp"].name %>'
data-val="<%=channels["vfdipp.tubingpressurelosp"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.tubingpressurelosp"].channelId %>"
value="<%=channels["vfdipp.tubingpressurelosp"].value %>">
</td>
</tr>
<tr>
<td>High Limit (PSI)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.tubingpressurehisp"].channelId %>'
data-techName='<%=channels["vfdipp.tubingpressurehisp"].techName %>'
data-name='<%= channels["vfdipp.tubingpressurehisp"].name %>'
data-val="<%=channels["vfdipp.tubingpressurehisp"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.tubingpressurehisp"].channelId %>"
value="<%=channels["vfdipp.tubingpressurehisp"].value %>">
</td>
</tr>
<tr>
<td>Startup Delay (sec)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.tubingpressurealarmstartupdelay"].channelId %>'
data-techName='<%=channels["vfdipp.tubingpressurealarmstartupdelay"].techName %>'
data-name='<%= channels["vfdipp.tubingpressurealarmstartupdelay"].name %>'
data-val="<%=channels["vfdipp.tubingpressurealarmstartupdelay"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.tubingpressurealarmstartupdelay"].channelId %>"
value="<%=channels["vfdipp.tubingpressurealarmstartupdelay"].value %>">
</td>
</tr>
<tr>
<td>Trip Delay (sec)</td>
<td>
<input class="form-control" data-channelId='<%= channels["vfdipp.tubingpressurealarmdelay"].channelId %>'
data-techName='<%=channels["vfdipp.tubingpressurealarmdelay"].techName %>'
data-name='<%= channels["vfdipp.tubingpressurealarmdelay"].name %>'
data-val="<%=channels["vfdipp.tubingpressurealarmdelay"].value %>"
type="number" step="any"
id="<%= channels["vfdipp.tubingpressurealarmdelay"].channelId %>"
value="<%=channels["vfdipp.tubingpressurealarmdelay"].value %>">
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<br />
<div class="pad15">
<button class='btn btn-theme btn-block set_channel_btn' value='Save'>APPLY CHANGES</button>
</div>
</form>
<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;
}
#systemStatusTimelineContainer h2 {
text-transform: uppercase;
font-size: 14px;
color: #666;
font-weight: 400;
letter-spacing: 1px;
z-index: 100;
}
</style>

View File

@@ -0,0 +1,269 @@
<% if (channels["vfdipp.downholetoolenabled"].value == 0){ %>
<div class="row">
<div class="well mar15 text-center">
<h1>THE DOWNHOLE SENSOR IS DISABLED</h1>
<h1>IT CAN BE ENABLED FROM THE CONFIGURATION SCREEN</h1>
</div>
</div>
<% } %>
<div class="text-center"><h1>LIVE VALUES</h1></div>
<div class='row row-flex'>
<div class='col-xs-4 text-center box-me'>
<h2>Intake Pressure</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-dhintakepressure" data-chart="solidgauge" data-nodename="vfdipp.dhintakepressure" data-units="PSI" data-min="0" data-max="<%= channels["vfdipp.dhpsirating"].value %>" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="dhintakepressure"><%= channels["vfdipp.dhintakepressure"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<h2>Fluid Level</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-dhfluidlevel" data-chart="solidgauge" data-nodename="vfdipp.dhfluidlevel" data-units="ft." data-min="0" data-max="1000" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="dhfluidlevel"><%= channels["vfdipp.dhfluidlevel"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<h2>Intake Temperature</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-dhintaketemperature" data-chart="solidgauge" data-nodename="vfdipp.dhintaketemperature" data-units="&deg;F" data-min="0" data-max="200" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="dhintaketemperature"><%= channels["vfdipp.dhintaketemperature"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<h2>Instrument Status</h2>
<div class="gauge-box">
<h1 data-valueupdate="dhdownholestatusint">
<% if(channels["vfdipp.dhdownholestatusint"].value == 0) { %>
<span class="label label-success">OK</span>
<% } else if (channels["vfdipp.dhdownholestatusint"].value == 1){ %>
<span class="label label-warning">Connecting...</span>
<% } else if (channels["vfdipp.dhdownholestatusint"].value == 2){ %>
<span class="label label-danger">Open Circuit</span>
<% } else if (channels["vfdipp.dhdownholestatusint"].value == 3){ %>
<span class="label label-danger">Shorted</span>
<% } else if (channels["vfdipp.dhdownholestatusint"].value == 4){ %>
<span class="label label-danger">Cannot Decode</span>
<% } %>
</h1>
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<h2>MAX VALUES</h2>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>Max Pressure (Startup)</td>
<td><%= channels["vfdipp.dhmaxintakepressurestartup"].value %></td>
</tr>
<tr>
<td>Max Pressure (Lifetime)</td>
<td><%= channels["vfdipp.dhmaxintakepressureforever"].value %></td>
</tr>
<tr>
<td>Max Temp. (Startup)</td>
<td><%= channels["vfdipp.dhmaxintaketemperaturestartup"].value %></td>
</tr>
<tr>
<td>Max Temp. (Lifetime)</td>
<td><%= channels["vfdipp.dhmaxintaketemperatureforever"].value %></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="text-center"><h1>TRENDS</h1></div>
<div class="row box-me">
<div class='col-xs-12' style="padding-top: 1em; margin-bottom: 1em;">
<div class="input-daterange input-group" id="datepicker">
<input data-chartid="dynamicChart" id="fromDate" data-daysofhistory="7" type="text" class="form-control" name="start">
<span class="input-group-addon">to</span>
<input class="form-control" data-chartid="dynamicChart" id="toDate" type="text" name="end">
<span class='input-group-btn'>
<a href="#!" data-chartid="dynamicChart" data-otherchartids="statusTimeline" class="btn chart-update btn-theme">Run</a>
</span>
</div>
</div>
<hr>
<div class='clearfix col-xs-12' style='height: 300px' id="dynamicChart" data-chart="dynamicchart" data-daysofhistory="7" data-chartlabel="Data" data-ylabel="" data-xlabel="Date" data-units="" data-channelnames="vfdipp.dhintakepressure,vfdipp.dhintaketemperature,vfdipp.dhmaxintakepressureforever,vfdipp.dhmaxintakepressurestartup,vfdipp.dhmaxintaketemperaturestartup,vfdipp.dhmaxintaketemperatureforever"></div>
</div>
<div class="text-center"><h1>CONFIGURATION</h1></div>
<div class="row row-flex">
<div class='col-xs-4 text-center box-me'>
<h2>Pressure Trip</h2>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>Pressure Shutdown Enabled</td>
<td>
<% if (channels["vfdipp.dhpressureshutdownenabled"].value == 1){ %>
<span class="label label-success">True</span>
<% } else { %>
<span class="label label-warning">False</span>
<% } %>
</td>
</tr>
<tr>
<td>Pressure Shutdown Limit</td>
<td><%= channels["vfdipp.dhpressureshutdownlimit"].value %> PSI</td>
</tr>
<tr>
<td>Pressure Restart Enabled</td>
<td>
<% if (channels["vfdipp.dhpressurestartupenabled"].value == 1){ %>
<span class="label label-success">True</span>
<% } else { %>
<span class="label label-warning">False</span>
<% } %>
</td>
</tr>
<tr>
<td>Pressure Startup Limit</td>
<td><%= channels["vfdipp.dhpressurestartup"].value %> PSI</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<h2>Temperature Trip</h2>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>Temp. Shutdown Enabled</td>
<td>
<% if (channels["vfdipp.dhtempshutdownenabled"].value == 1){ %>
<span class="label label-success">True</span>
<% } else { %>
<span class="label label-warning">False</span>
<% } %>
</td>
</tr>
<tr>
<td>Temp. Shutdown Limit</td>
<td><%= channels["vfdipp.dhtempshutdown"].value %> &deg;F</td>
</tr>
<tr>
<td>Temp. Restart Enabled</td>
<td>
<% if (channels["vfdipp.dhtempstartupenabled"].value == 1){ %>
<span class="label label-success">True</span>
<% } else { %>
<span class="label label-warning">False</span>
<% } %>
</td>
</tr>
<tr>
<td>Temp. Startup Limit</td>
<td><%= channels["vfdipp.dhtempstartuplimit"].value %> &deg;F</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<h2>Sensor Info.</h2>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>Number of Channels</td>
<td><%= channels["vfdipp.dhnumchannels"].value %></td>
</tr>
<tr>
<td>PSI Rating</td>
<td><%= channels["vfdipp.dhpsirating"].value %> PSI</td>
</tr>
<tr>
<td>Tool Type</td>
<td><%= channels["vfdipp.dhtooltype"].value %></td>
</tr>
<tr>
<td>Tool Voltage</td>
<td><%= channels["vfdipp.dhtoolvoltage"].value %> V</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<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;
}
.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;
}
.mar15 {
margin: 15px 15px;
}
#systemStatusTimelineContainer h2 {
text-transform: uppercase;
font-size: 14px;
color: #666;
font-weight: 400;
letter-spacing: 1px;
z-index: 100;
}
</style>

View File

@@ -0,0 +1,149 @@
<div class='row row-flex box-me'>
<div class='col-xs-4 text-center'>
<h2>Motor Speed</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-vfdspeedfdbk" data-chart="solidgauge" data-nodename="vfdipp.vfdspeedfdbk" data-units="Hz" data-min="0" data-max="100" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="vfdspeedfdbk"><%= channels["vfdipp.vfdspeedfdbk"].timestamp %></span>
</div>
</div>
<div class='col-xs-8'>
<div style="height:300px" id="chart-vfdspeedfdbk" data-chart="chart" data-nodename1="vfdipp.vfdspeedfdbk" data-datalabel1="Speed" data-daysofhistory="2" data-chartlabel="Motor Speed" data-ylabel="" data-xlabel="Date" data-units=" Hz"></div>
</div>
</div>
<% if (channels["vfdipp.downholetoolenabled"].value == 1) {%>
<div class='row row-flex box-me'>
<div class='col-xs-4 text-center'>
<h2>Downhole Pressure</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-dhintakepressure" data-chart="solidgauge" data-nodename="vfdipp.dhintakepressure" data-units="PSI" data-min="0" data-max="400" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="dhintakepressure"><%= channels["vfdipp.dhintakepressure"].timestamp %></span>
</div>
</div>
<div class='col-xs-8'>
<div style="height:300px" id="chart-dhintakepressure" data-chart="chart" data-nodename1="vfdipp.dhintakepressure" data-datalabel1="Downhole Pressure" data-daysofhistory="2" data-chartlabel="DH Intake Pressure" data-ylabel="" data-xlabel="Date" data-units=" PSI"></div>
</div>
</div>
<div class='row row-flex box-me'>
<div class='col-xs-4 text-center'>
<h2>Downhole Temperature</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-dhintaketemperature" data-chart="solidgauge" data-nodename="vfdipp.dhintaketemperature" data-units=" &deg; F" data-min="0" data-max="400" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="dhintaketemperature"><%= channels["vfdipp.dhintaketemperature"].timestamp %></span>
</div>
</div>
<div class='col-xs-8'>
<div style="height:300px" id="chart-dhintaketemperature" data-chart="chart" data-nodename1="vfdipp.dhintaketemperature" data-datalabel1="Downhole Temperature" data-daysofhistory="2" data-chartlabel="DH Intake Temperature" data-ylabel="" data-xlabel="Date" data-units=" &deg; F"></div>
</div>
</div>
<% } %>
<% if (channels["vfdipp.tubingpressuretransducerenabled"].value == 1) {%>
<div class='row row-flex box-me'>
<div class='col-xs-4 text-center'>
<h2>Downhole Pressure</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-tubingpressure" data-chart="solidgauge" data-nodename="vfdipp.tubingpressure" data-units="PSI" data-min="0" data-max="400" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="tubingpressure"><%= channels["vfdipp.tubingpressure"].timestamp %></span>
</div>
</div>
<div class='col-xs-8'>
<div style="height:300px" id="chart-tubingpressure" data-chart="chart" data-nodename1="vfdipp.tubingpressure" data-datalabel1="Tubing Pressure" data-daysofhistory="2" data-chartlabel="Tubing Pressure" data-ylabel="" data-xlabel="Date" data-units=" PSI"></div>
</div>
</div>
<% } %>
<div class='row row-flex box-me'>
<div class='col-xs-4 text-center'>
<h2>Output Current</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-vfdoutputcurrent" data-chart="solidgauge" data-nodename="vfdipp.vfdoutputcurrent" data-units="A" data-min="0" data-max="<%= channels["vfdipp.vfdnameplatefla"].value %>" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="vfdoutputcurrent"><%= channels["vfdipp.vfdoutputcurrent"].timestamp %></span>
</div>
</div>
<div class='col-xs-8'>
<div style="height:300px" id="chart-vfdoutputcurrent" data-chart="chart" data-nodename1="vfdipp.vfdoutputcurrent" data-datalabel1="Output Current" data-daysofhistory="2" data-chartlabel="Output Current" data-ylabel="" data-xlabel="Date" data-units=" A"></div>
</div>
</div>
<div class='row row-flex box-me'>
<div class='col-xs-4 text-center'>
<h2>Output Voltage</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-vfdoutputvoltage" data-chart="solidgauge" data-nodename="vfdipp.vfdoutputvoltage" data-units="V" data-min="0" data-max="600" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="vfdoutputvoltage"><%= channels["vfdipp.vfdoutputvoltage"].timestamp %></span>
</div>
</div>
<div class='col-xs-8'>
<div style="height:300px" id="chart-vfdoutputvoltage" data-chart="chart" data-nodename1="vfdipp.vfdoutputvoltage" data-datalabel1="Output Voltage" data-daysofhistory="2" data-chartlabel="Output Voltage" data-ylabel="" data-xlabel="Date" data-units=" V"></div>
</div>
</div>
<div class='row row-flex box-me'>
<div class='col-xs-4 text-center'>
<h2>DC Bus Voltage</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-vfddcbusvoltage" data-chart="solidgauge" data-nodename="vfdipp.vfddcbusvoltage" data-units="V" data-min="0" data-max="700" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="vfddcbusvoltage"><%= channels["vfdipp.vfddcbusvoltage"].timestamp %></span>
</div>
</div>
<div class='col-xs-8'>
<div style="height:300px" id="chart-vfddcbusvoltage" data-chart="chart" data-nodename1="vfdipp.vfddcbusvoltage" data-datalabel1="DC Bus Voltage" data-daysofhistory="2" data-chartlabel="DC Bus Voltage" data-ylabel="" data-xlabel="Date" data-units=" V"></div>
</div>
</div>
<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;
}
#systemStatusTimelineContainer h2 {
text-transform: uppercase;
font-size: 14px;
color: #666;
font-weight: 400;
letter-spacing: 1px;
z-index: 100;
}
</style>

View File

@@ -0,0 +1,327 @@
<div class="text-center"><h1>LIVE VALUES</h1></div>
<div class='row'>
<div class='col-xs-4 text-center box-me'>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>
<h2>Active Alarms</h2>
</td>
<td></td>
</tr>
<tr>
<td>VFD</td>
<td>
<% if (channels["vfdipp.alarmvfd"].value == 0){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>Mode</td>
<td>
<% if (channels["vfdipp.alarmmode"].value == 0){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>DH Pressure</td>
<td>
<% if (channels["vfdipp.alarmpressure"].value == 0){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>DH Temperature</td>
<td>
<% if (channels["vfdipp.alarmtemperature"].value == 0){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>Remote</td>
<td>
<% if (channels["vfdipp.alarmremote"].value == 0){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>Tubing Pressure</td>
<td>
<% if (channels["vfdipp.alarmtubingpressure"].value == 0){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>
<h2>Start Permissive</h2>
</td>
<td>
<h2>
<% if (channels["vfdipp.startpermissive"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</h2>
</td>
</tr>
<tr>
<td>VFD</td>
<td>
<% if (channels["vfdipp.spvfd"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>Mode</td>
<td>
<% if (channels["vfdipp.spmode"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>DH Pressure</td>
<td>
<% if (channels["vfdipp.sppressure"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>DH Temperature</td>
<td>
<% if (channels["vfdipp.sptemperature"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>Remote</td>
<td>
<% if (channels["vfdipp.spremote"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>
<h2>Run Permissive</h2>
</td>
<td>
<h2>
<% if (channels["vfdipp.runpermissive"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</h2>
</td>
</tr>
<tr>
<td>VFD</td>
<td>
<% if (channels["vfdipp.rpvfd"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>Mode</td>
<td>
<% if (channels["vfdipp.rpmode"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>DH Pressure</td>
<td>
<% if (channels["vfdipp.rppressure"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>DH Temperature</td>
<td>
<% if (channels["vfdipp.rptemperature"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>Remote</td>
<td>
<% if (channels["vfdipp.rpremote"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
<tr>
<td>Tubing Pressure</td>
<td>
<% if (channels["vfdipp.rptubingpressure"].value == 1){ %>
<span class="label label-success">OK</span>
<% } else { %>
<span class="label label-danger">NOT OK</span>
<% } %>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class='row'>
<div class='col-xs-6 col-xs-offset-3 text-center box-me'>
<h2>Last Shutdown Cause</h2>
<h1>
<% if (channels["vfdipp.lastshutdowncause"].value == 0){ %>
<span class="label label-primary">Unknown</span>
<% } else if (channels["vfdipp.lastshutdowncause"].value == 1) { %>
<span class="label label-primary">Mode</span>
<% } else if (channels["vfdipp.lastshutdowncause"].value == 2) { %>
<span class="label label-primary">DH Pressure</span>
<% } else if (channels["vfdipp.lastshutdowncause"].value == 3) { %>
<span class="label label-primary">DH Temperature</span>
<% } else if (channels["vfdipp.lastshutdowncause"].value == 4) { %>
<span class="label label-primary">Tubing Pressure</span>
<% } else if (channels["vfdipp.lastshutdowncause"].value == 5) { %>
<span class="label label-primary">VFD</span>
<% } else if (channels["vfdipp.lastshutdowncause"].value == 6) { %>
<span class="label label-primary">Remote Trip</span>
<% } else if (channels["vfdipp.lastshutdowncause"].value == 7) { %>
<span class="label label-primary">User Shutdown</span>
<% } %>
</h1>
</div>
</div>
<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;
}
.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;
}
.fill-vertically {
height:261px;
}
#systemStatusTimelineContainer 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;
}
.row-flex > [class*='col-'] {
display: flex;
flex-direction: column;
}
</style>

View File

@@ -0,0 +1,27 @@
<div class='col-xs-12' style="padding-top: 1em; margin-bottom: 1em;">
<div class="input-daterange input-group" id="datepicker">
<input data-chartid="dynamicChart" id="fromDate" data-daysofhistory="7" type="text" class="form-control" name="start">
<span class="input-group-addon">to</span>
<input class="form-control" data-chartid="dynamicChart" id="toDate" type="text" name="end">
<span class='input-group-btn'>
<a href="#!" data-chartid="dynamicChart" data-otherchartids="statusTimeline" class="btn chart-update btn-theme">Run</a>
</span>
</div>
</div>
<hr>
<div class='clearfix col-xs-12' style='height: 450px' id="dynamicChart" data-chart="dynamicchart" data-daysofhistory="7" data-chartlabel="Data" data-ylabel="" data-xlabel="Date" data-units="" data-channelnames="vfdipp.vfdoutputcurrent,vfdipp.vfdspeedref,vfdipp.vfdspeedfdbk,vfdipp.dhintakepressure,vfdipp.dhintaketemperature,vfdipp.tubingpressure,vfdipp.vfddcbusvoltage,vfdipp.vfdoutputvoltage"></div>
<style>
.dynamic-chart-form {
background-color: whiteSmoke;
padding: 1em 0.5em;
margin-top: 1em;
}
#systemStatusTimelineContainer h2 {
text-transform: uppercase;
font-size: 14px;
color: #666;
font-weight: 400;
letter-spacing: 1px;
z-index: 100;
}
</style>

View File

@@ -0,0 +1,386 @@
<div class="text-center"><h1>LIVE VALUES</h1></div>
<div class='row row-flex'>
<div class='col-xs-4 text-center box-me'>
<h2>Speed Feedback</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-vfdspeedfdbk" data-chart="solidgauge" data-nodename="vfdipp.vfdspeedfdbk" data-units="Hz" data-min="0" data-max="100" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="vfdspeedfdbk"><%= channels["vfdipp.vfdspeedfdbk"].timestamp %></span>
</div>
</div>
<!-- <div class='col-xs-4 text-center box-me'>
<h2>Speed Reference</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge2" data-chart="solidgauge" data-nodename="vfdipp.vfdspeedref" data-units="Hz" data-min="0" data-max="100" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-decimals="2" data-valuefontsize="18px"></div>
<span data-timeupdate="vfdspeedref"><%= channels["vfdipp.vfdspeedref"].timestamp %></span>
</div>
</div> -->
<div class='col-xs-4 text-center box-me'>
<h2>Output Current</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-vfdoutputcurrent" data-chart="solidgauge" data-nodename="vfdipp.vfdoutputcurrent" data-units="A" data-min="0" data-max="<%= channels["vfdipp.vfdnameplatefla"].value %>" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="vfdoutputcurrent"><%= channels["vfdipp.vfdoutputcurrent"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<h2>Output Voltage</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-vfdoutputvoltage" data-chart="solidgauge" data-nodename="vfdipp.vfdoutputvoltage" data-units="V" data-min="0" data-max="600" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="vfdoutputvoltage"><%= channels["vfdipp.vfdoutputvoltage"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<h2>DC Bus Voltage</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge-vfddcbusvoltage" data-chart="solidgauge" data-nodename="vfdipp.vfddcbusvoltage" data-units="V" data-min="0" data-max="700" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-valuefontsize="18px"></div>
<span data-timeupdate="vfddcbusvoltage"><%= channels["vfdipp.vfddcbusvoltage"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<h2>VFD Status</h2>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>VFD Active</td>
<td>
<% if (channels["vfdipp.vfdactive"].value == 1){ %>
<span class="label label-success">True</span>
<% } else { %>
<span class="label label-danger">False</span>
<% } %>
</td>
</tr>
<tr>
<td>VFD Ready</td>
<td>
<% if (channels["vfdipp.vfdready"].value == 1){ %>
<span class="label label-success">True</span>
<% } else { %>
<span class="label label-danger">False</span>
<% } %>
</td>
</tr>
<tr>
<td>VFD At Speed</td>
<td>
<% if (channels["vfdipp.vfdatspeedref"].value == 1){ %>
<span class="label label-success">True</span>
<% } else { %>
<span class="label label-danger">False</span>
<% } %>
</td>
</tr>
<tr>
<td>VFD Disabled</td>
<td>
<% if (channels["vfdipp.vfddisabled"].value == 1){ %>
<span class="label label-danger">True</span>
<% } else { %>
<span class="label label-success">False</span>
<% } %>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class='col-xs-4 text-center box-me'>
<h2>VFD Faults</h2>
<div class="gauge-box">
<table class="table">
<tbody>
<tr>
<td>VFD Faulted</td>
<td>
<% if (channels["vfdipp.vfdfault"].value == 1){ %>
<span class="label label-danger">True</span>
<% } else { %>
<span class="label label-success">False</span>
<% } %>
</td>
</tr>
<tr>
<td>VFD Fault Code</td>
<td>
<% if (channels["vfdipp.vfdfaultcode"].value == 0) { %>
<span class="vfdFault">None</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 2) { %>
<span class="vfdFault">Auxiliary Input</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 3 ) { %>
<span class="vfdFault">Power Loss</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 4 ) { %>
<span class="vfdFault">UnderVoltage</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 5 ) { %>
<span class="vfdFault">OverVoltage</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 6 ) { %>
<span class="vfdFault">Motor Stalled</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 7 ) { %>
<span class="vfdFault">Motor Overload</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 8 ) { %>
<span class="vfdFault">Heatsink OverTemp</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 9 ) { %>
<span class="vfdFault">Control Module OverTemp</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 12 ) { %>
<span class="vfdFault">Hardware OverCurrent</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 13 ) { %>
<span class="vfdFault">Ground Fault</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 15 ) { %>
<span class="vfdFault">Load Loss</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 21 ) { %>
<span class="vfdFault">Output Phase Loss</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 29 ) { %>
<span class="vfdFault">Analog Input Loss</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 33 ) { %>
<span class="vfdFault">Auto Restart Tries Exceeded</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 38 ) { %>
<span class="vfdFault">Phase U Ground Fault</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 39 ) { %>
<span class="vfdFault">Phase V Ground Fault</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 40 ) { %>
<span class="vfdFault">Phase W Ground Fault</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 41 ) { %>
<span class="vfdFault">Phase UV Short</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 42 ) { %>
<span class="vfdFault">Phase UW Short</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 43 ) { %>
<span class="vfdFault">Phase VW Short</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 48 ) { %>
<span class="vfdFault">Parameters Defaulted</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 59 ) { %>
<span class="vfdFault">Safety Open</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 63 ) { %>
<span class="vfdFault">Software OverCurrent</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 64 ) { %>
<span class="vfdFault">Drive Overload</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 70 ) { %>
<span class="vfdFault">Power Unit Failure</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 71 ) { %>
<span class="vfdFault">DSI Network Loss</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 72 ) { %>
<span class="vfdFault">Option Card Network Loss</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 73 ) { %>
<span class="vfdFault">Ethernet Network Loss</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 80 ) { %>
<span class="vfdFault">Autotune Failure</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 81 ) { %>
<span class="vfdFault">DSI Communications Loss</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 82 ) { %>
<span class="vfdFault">Option Card Communications Loss</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 83 ) { %>
<span class="vfdFault">Ethernet Communications Loss</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 91 ) { %>
<span class="vfdFault">Encoder Loss</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 94 ) { %>
<span class="vfdFault">Function Loss</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 100 ) { %>
<span class="vfdFault">Parameter Checksum Error</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 101 ) { %>
<span class="vfdFault">External Storage Failure</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 105 ) { %>
<span class="vfdFault">Control Module Connection Error</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 106 ) { %>
<span class="vfdFault">Incompatible Control Module</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 107 ) { %>
<span class="vfdFault">Replaced Control Module not Recognized</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 109 ) { %>
<span class="vfdFault">Mismatched Control Module</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 110 ) { %>
<span class="vfdFault">Keypad Membrane Failure</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 111 ) { %>
<span class="vfdFault">Safety Hardware Malfunction</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 114 ) { %>
<span class="vfdFault">Microprocessor Failure</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 122 ) { %>
<span class="vfdFault">IO Board Failure</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 125 ) { %>
<span class="vfdFault">Flash Update Required</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 126 ) { %>
<span class="vfdFault">Non-recoverable Firmware Error</span>
<% } else if (channels["vfdipp.vfdfaultcode"].value == 127 ) { %>
<span class="vfdFault">DSI Flash Update Required</span>
<% } %>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="text-center"><h1>TRENDS</h1></div>
<div class="row">
<div class='col-xs-12' style="padding-top: 1em; margin-bottom: 1em;">
<div class="input-daterange input-group" id="datepicker">
<input data-chartid="dynamicChart" id="fromDate" data-daysofhistory="7" type="text" class="form-control" name="start">
<span class="input-group-addon">to</span>
<input class="form-control" data-chartid="dynamicChart" id="toDate" type="text" name="end">
<span class='input-group-btn'>
<a href="#!" data-chartid="dynamicChart" data-otherchartids="statusTimeline" class="btn chart-update btn-theme">Run</a>
</span>
</div>
</div>
<hr>
<div class='clearfix col-xs-12' style='height: 300px' id="dynamicChart" data-chart="dynamicchart" data-daysofhistory="7" data-chartlabel="Data" data-ylabel="" data-xlabel="Date" data-units="" data-channelnames="vfdipp.vfdspeedref,vfdipp.vfdspeedfdbk,vfdipp.vfdoutputcurrent,vfdipp.vfdoutputcurrent,vfdipp.vfddcbusvoltage"></div>
</div>
<div class="text-center"><h1>CONFIGURATION</h1></div>
<div class="row row-flex">
<div class="col-md-6 box-me text-center">
<h2>MOTOR NAMEPLATE DATA</h2>
<table class="table">
<tbody>
<tr>
<td>Motor FLA</td>
<td><%= channels["vfdipp.vfdnameplatefla"].value %> A</td>
</tr>
<tr>
<td>Motor HP</td>
<td><%= Math.round(channels["vfdipp.vfdnameplatehp"].value * 10) / 10 %> HP</td>
</tr>
<tr>
<td>Motor RPM</td>
<td><%= channels["vfdipp.vfdnameplaterpm"].value %> RPM</td>
</tr>
<tr>
<td>Motor Frequency</td>
<td><%= channels["vfdipp.vfdnameplatehz"].value %> Hz</td>
</tr>
<tr>
<td>Motor Overload Current</td>
<td><%= channels["vfdipp.vfdnameplateolcurrent"].value %> A</td>
</tr>
<tr>
<td>Motor Volts</td>
<td><%= channels["vfdipp.vfdnameplatevolts"].value %> V</td>
</tr>
<tr>
<td>Motor Poles</td>
<td><%= channels["vfdipp.vfdmotorpoles"].value %></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-6 box-me text-center">
<h2>VFD SETTINGS</h2>
<table class="table">
<tbody>
<tr>
<td>Min. Frequency</td>
<td><%= channels["vfdipp.vfdminfreq"].value %> Hz</td>
</tr>
<tr>
<td>Max. Frequency</td>
<td><%= channels["vfdipp.vfdmaxfreq"].value %> Hz</td>
</tr>
<tr>
<td>Accel. Time</td>
<td><%= channels["vfdipp.vfdacceltime"].value %> s.</td>
</tr>
<tr>
<td>Decel. Time</td>
<td><%= channels["vfdipp.vfddeceltime"].value %> s.</td>
</tr>
<tr>
<td>Stop Mode</td>
<td>
<% if (channels["vfdipp.vfdstopmode"].value == 0){ %>
<span class="label label-success">Coast</span>
<% } else if (channels["vfdipp.vfdstopmode"].value == 1){ %>
<span class="label label-danger">Ramp</span>
<% } else if (channels["vfdipp.vfdstopmode"].value == 2){ %>
<span class="label label-danger">Ramp to Hold</span>
<% } else if (channels["vfdipp.vfdstopmode"].value == 3){ %>
<span class="label label-danger">DC Brake</span>
<% } else if (channels["vfdipp.vfdstopmode"].value == 4){ %>
<span class="label label-danger">DCBrkAutoOff</span>
<% } else if (channels["vfdipp.vfdstopmode"].value == 5){ %>
<span class="label label-danger">Current Limit</span>
<% } else if (channels["vfdipp.vfdstopmode"].value == 6){ %>
<span class="label label-danger">Fast Brake</span>
<% } %>
</td>
</tr>
<tr>
<td>Torque Perf. Mode</td>
<td>
<% if (channels["vfdipp.vfdtorqueperfmode"].value == 0){ %>
<span class="label label-danger">V/Hz</span>
<% } else if (channels["vfdipp.vfdtorqueperfmode"].value == 1){ %>
<span class="label label-success">SVC</span>
<% } else if (channels["vfdipp.vfdtorqueperfmode"].value == 2){ %>
<span class="label label-danger">Economize</span>
<% } else if (channels["vfdipp.vfdtorqueperfmode"].value == 3){ %>
<span class="label label-danger">Vector</span>
<% } %>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<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;
}
.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;
}
#systemStatusTimelineContainer h2 {
text-transform: uppercase;
font-size: 14px;
color: #666;
font-weight: 400;
letter-spacing: 1px;
z-index: 100;
}
</style>

File diff suppressed because one or more lines are too long

21
POCloud_Driver/config.txt Normal file
View File

@@ -0,0 +1,21 @@
{
"driverFileName":"ipp.py",
"deviceName":"ipp",
"driverId":"0090",
"releaseVersion":"1",
"files": {
"file1":"ipp.py",
"file2":"micro800.py",
"file3":"ipp_channels.p",
"file4":"ipp_channels_setup.py",
"file5":"pycomm_micro/__init__.py",
"file6":"pycomm_micro/common.py",
"file7":"pycomm_micro/ab_comm/__init__.py",
"file8":"pycomm_micro/ab_comm/clx.py",
"file9":"pycomm_micro/ab_comm/slc.py",
"file10":"pycomm_micro/cip/__init__.py",
"file11":"pycomm_micro/cip/cip_base.py",
"file12":"pycomm_micro/cip/cip_const.py" }
}

View File

@@ -0,0 +1,20 @@
import pickle
with open('testPickle.p', 'rb') as ch_f:
channels = pickle.load(ch_f)
out = []
for x in channels.keys():
chName = x
dType = channels[x]['data_type']
if dType == 'REAL':
dType = "float"
elif dType[-3:] == "INT":
dType = "integer"
elif dType == "BOOL":
dType = "boolean"
else:
print dType
out.append("{0} - {1}".format(chName, dType))
for a in sorted(out):
print a

628
POCloud_Driver/ipp.py Normal file
View File

@@ -0,0 +1,628 @@
#!/usr/bin/python
import types
import traceback
import binascii
import threading
import time
import thread
import os
import struct
import sys
import serial
import minimalmodbus
import pickle
import re
from device_base import deviceBase
import micro800 as u800
import requests
try:
import json
except:
import simplejson as json
min_upload_time = 30
addr = '192.168.1.20'
class start(threading.Thread, deviceBase):
channels = {}
def updateGPS(self):
gps = self.mcu.gps
print("GPS found me at {0}".format(gps))
self.sendtodb("gps", gps, 0)
def setupChannels(self):
with open('drivers/ipp_channels.p', 'rb') as ch_f:
self.channels = pickle.load(ch_f)
print("Channel List\n================")
for x in self.channels.keys():
print x
print("================")
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 = "1"
self.device_address = addr
self.finished = threading.Event()
threading.Thread.start(self)
self.sendtodbJSON("device_address", self.device_address, 0)
self.setupChannels()
# self.run()
# self.updateGPS()
# 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):
print("****************\n*************\nEXECUTING RUN\n********************\n****************")
self.runLoopStatus = ""
last_OK_state = 0
while True:
if len(self.channels) > 0:
try:
for i in self.channels:
runLoopStatus = i
print("reading {0}".format(i))
valData = u800.readMicroTag(self.device_address, self.channels[i]['tag'])
print(valData)
if valData:
nowVal = valData[0]
ch = self.channels[i]
if ch['data_type'] == "BOOL":
if ch['last_value'] == "":
self.sendtodbJSON(i, nowVal, 0)
ch['last_time_uploaded'] = time.time()
ch['last_value'] = nowVal
elif (not (ch['last_value'] == nowVal)) or ((time.time() - ch['last_time_uploaded']) > ch['max_time_between_uploads']):
self.sendtodbJSON(i, nowVal, 0)
ch['last_time_uploaded'] = time.time()
ch['last_value'] = nowVal
if (ch['data_type'] == "REAL") or (ch['data_type'][-3:] == "INT"):
if ch['last_value'] == "":
self.sendtodbJSON(i, nowVal, 0)
ch['last_time_uploaded'] = time.time()
ch['last_value'] = nowVal
elif (abs(ch['last_value'] - nowVal) > ch['change_amount']) or ((time.time() - ch['last_time_uploaded']) > ch['max_time_between_uploads']):
self.sendtodbJSON(i, nowVal, 0)
ch['last_time_uploaded'] = time.time()
ch['last_value'] = nowVal
runLoopStatus = "Complete"
OK_state = 1
if not OK_state == last_OK_state:
self.sendtodbJSON("driver_ok", OK_state, 0)
last_OK_state = OK_state
time.sleep(10)
except Exception, e:
OK_state = 0
if not OK_state == last_OK_state:
self.sendtodbJSON("driver_ok", OK_state, 0)
last_OK_state = OK_state
sleep_timer = 30
print "Error during {0} of run loop: {1}\nWill try again in {2} seconds...".format(runLoopStatus, e, sleep_timer)
time.sleep(sleep_timer)
else:
print("Apparently no self.channels... length shows {0}".format(len(self.channels)))
print self.channels
self.setupChannels()
time.sleep(30)
def write_vfdconfig(self):
print("Writing config to drive")
return u800.writeMicroTag(addr, 'VFD_Write', 1)
def vfdipp_sync(self, name, value):
self.sendtodb("connected", "true", 0)
return True
def vfdipp_address(self, name, value):
self.device_address = value
return True
def vfdipp_gpsUpdate(self, name, value):
updateGPS()
return True
# ======== AUTOMATICALLY GENERATED TAG WRITE FUNCTIONS BELOW HERE ===========
def vfdipp_cfgCFLASetting(self, name, value):
print('trying to set cfg_C_FLASetting to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_C_FLASetting', float(value))
def vfdipp_cfgCTripEnableControl(self, name, value):
print('trying to set cfg_C_TripEnableControl to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_C_TripEnableControl', int(value))
def vfdipp_cfgCWarningEnableControl(self, name, value):
print('trying to set cfg_C_WarningEnableControl to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_C_WarningEnableControl', int(value))
def vfdipp_cfgClearTripCountAfter(self, name, value):
print('trying to set cfg_ClearTripCountAfter to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_ClearTripCountAfter', int(value))
def vfdipp_cfgGFGroundFaultInhibitTime(self, name, value):
print('trying to set cfg_GF_GroundFaultInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_GF_GroundFaultInhibitTime', int(value))
def vfdipp_cfgGFGroundFaultTripDelay(self, name, value):
print('trying to set cfg_GF_GroundFaultTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_GF_GroundFaultTripDelay', float(value))
def vfdipp_cfgGFGroundFaultTripLevel(self, name, value):
print('trying to set cfg_GF_GroundFaultTripLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_GF_GroundFaultTripLevel', float(value))
def vfdipp_cfgGFGroundFaultWarningDelay(self, name, value):
print('trying to set cfg_GF_GroundFaultWarningDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_GF_GroundFaultWarningDelay', float(value))
def vfdipp_cfgGFGroundFaultWarningLevel(self, name, value):
print('trying to set cfg_GF_GroundFaultWarningLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_GF_GroundFaultWarningLevel', float(value))
def vfdipp_cfgICTPrimary(self, name, value):
print('trying to set cfg_I_CTPrimary to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_CTPrimary', int(value))
def vfdipp_cfgICTSecondary(self, name, value):
print('trying to set cfg_I_CTSecondary to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_CTSecondary', int(value))
def vfdipp_cfgICurrentImbalanceInhibitTime(self, name, value):
print('trying to set cfg_I_CurrentImbalanceInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_CurrentImbalanceInhibitTime', int(value))
def vfdipp_cfgICurrentImbalanceTripDelay(self, name, value):
print('trying to set cfg_I_CurrentImbalanceTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_CurrentImbalanceTripDelay', int(value))
def vfdipp_cfgICurrentImbalanceTripLevel(self, name, value):
print('trying to set cfg_I_CurrentImbalanceTripLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_CurrentImbalanceTripLevel', int(value))
def vfdipp_cfgICurrentImbalanceWarningLevel(self, name, value):
print('trying to set cfg_I_CurrentImbalanceWarningLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_CurrentImbalanceWarningLevel', int(value))
def vfdipp_cfgIJamInhibitTime(self, name, value):
print('trying to set cfg_I_JamInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_JamInhibitTime', int(value))
def vfdipp_cfgIJamTripDelay(self, name, value):
print('trying to set cfg_I_JamTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_JamTripDelay', int(value))
def vfdipp_cfgIJamWarningLevel(self, name, value):
print('trying to set cfg_I_JamWarningLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_JamWarningLevel', int(value))
def vfdipp_cfgILineLossInhibitTime(self, name, value):
print('trying to set cfg_I_LineLossInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_LineLossInhibitTime', int(value))
def vfdipp_cfgILineLossTripDelay(self, name, value):
print('trying to set cfg_I_LineLossTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_LineLossTripDelay', float(value))
def vfdipp_cfgIOvercurrentInhibitTime(self, name, value):
print('trying to set cfg_I_OvercurrentInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_OvercurrentInhibitTime', int(value))
def vfdipp_cfgIOvercurrentTripDelay(self, name, value):
print('trying to set cfg_I_OvercurrentTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_OvercurrentTripDelay', float(value))
def vfdipp_cfgIOvercurrentTripLevel(self, name, value):
print('trying to set cfg_I_OvercurrentTripLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_OvercurrentTripLevel', int(value))
def vfdipp_cfgIOvercurrentWarningLevel(self, name, value):
print('trying to set cfg_I_OvercurrentWarningLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_OvercurrentWarningLevel', int(value))
def vfdipp_cfgIStallEnabledTime(self, name, value):
print('trying to set cfg_I_StallEnabledTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_StallEnabledTime', int(value))
def vfdipp_cfgIStallTripLevel(self, name, value):
print('trying to set cfg_I_StallTripLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_StallTripLevel', int(value))
def vfdipp_cfgIUndercurrentInhibitTime(self, name, value):
print('trying to set cfg_I_UndercurrentInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_UndercurrentInhibitTime', int(value))
def vfdipp_cfgIUndercurrentTripDelay(self, name, value):
print('trying to set cfg_I_UndercurrentTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_UndercurrentTripDelay', float(value))
def vfdipp_cfgIUndercurrentTripLevel(self, name, value):
print('trying to set cfg_I_UndercurrentTripLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_UndercurrentTripLevel', int(value))
def vfdipp_cfgIUndercurrentWarningLevel(self, name, value):
print('trying to set cfg_I_UndercurrentWarningLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_UndercurrentWarningLevel', int(value))
def vfdipp_cfgIUnderloadInhibitTime(self, name, value):
print('trying to set cfg_I_UnderloadInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_UnderloadInhibitTime', int(value))
def vfdipp_cfgIUnderloadTripDelay(self, name, value):
print('trying to set cfg_I_UnderloadTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_UnderloadTripDelay', float(value))
def vfdipp_cfgIUnderloadTripLevel(self, name, value):
print('trying to set cfg_I_UnderloadTripLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_UnderloadTripLevel', int(value))
def vfdipp_cfgIUnderloadWarningLevel(self, name, value):
print('trying to set cfg_I_UnderloadWarningLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_I_UnderloadWarningLevel', int(value))
def vfdipp_cfgOverloadTripCountLimit(self, name, value):
print('trying to set cfg_OverloadTripCountLimit to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_OverloadTripCountLimit', int(value))
def vfdipp_cfgPLPhaseLossInhibitTime(self, name, value):
print('trying to set cfg_PL_PhaseLossInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_PL_PhaseLossInhibitTime', int(value))
def vfdipp_cfgPLPhaseLossTripDelay(self, name, value):
print('trying to set cfg_PL_PhaseLossTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_PL_PhaseLossTripDelay', float(value))
def vfdipp_cfgREAD(self, name, value):
print('trying to set cfg_READ to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_READ', int(value))
def vfdipp_cfgSpecificGravity(self, name, value):
print('trying to set cfg_SpecificGravity to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_SpecificGravity', float(value))
def vfdipp_cfgTCUTripClass(self, name, value):
print('trying to set cfg_TCU_TripClass to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_TCU_TripClass', int(value))
def vfdipp_cfgTimerModeEnabled(self, name, value):
print('trying to set cfg_TimerModeEnabled to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_TimerModeEnabled', int(value))
def vfdipp_cfgTimerRunTime(self, name, value):
print('trying to set cfg_TimerRunTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_TimerRunTime', int(value))
def vfdipp_cfgTimerWaitTime(self, name, value):
print('trying to set cfg_TimerWaitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_TimerWaitTime', int(value))
def vfdipp_cfgTripCountLimit(self, name, value):
print('trying to set cfg_TripCountLimit to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_TripCountLimit', int(value))
def vfdipp_cfgVOverfrequencyInhibitTime(self, name, value):
print('trying to set cfg_V_OverfrequencyInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_OverfrequencyInhibitTime', int(value))
def vfdipp_cfgVOverfrequencyTripDelay(self, name, value):
print('trying to set cfg_V_OverfrequencyTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_OverfrequencyTripDelay', float(value))
def vfdipp_cfgVOverfrequencyTripLevel(self, name, value):
print('trying to set cfg_V_OverfrequencyTripLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_OverfrequencyTripLevel', int(value))
def vfdipp_cfgVOverfrequencyWarningLevel(self, name, value):
print('trying to set cfg_V_OverfrequencyWarningLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_OverfrequencyWarningLevel', int(value))
def vfdipp_cfgVOvervoltageInhibitTime(self, name, value):
print('trying to set cfg_V_OvervoltageInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_OvervoltageInhibitTime', int(value))
def vfdipp_cfgVOvervoltageTripDelay(self, name, value):
print('trying to set cfg_V_OvervoltageTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_OvervoltageTripDelay', float(value))
def vfdipp_cfgVOvervoltageTripLevel(self, name, value):
print('trying to set cfg_V_OvervoltageTripLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_OvervoltageTripLevel', float(value))
def vfdipp_cfgVOvervoltageWarningLevel(self, name, value):
print('trying to set cfg_V_OvervoltageWarningLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_OvervoltageWarningLevel', float(value))
def vfdipp_cfgVPTPrimary(self, name, value):
print('trying to set cfg_V_PTPrimary to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_PTPrimary', int(value))
def vfdipp_cfgVPTSecondary(self, name, value):
print('trying to set cfg_V_PTSecondary to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_PTSecondary', int(value))
def vfdipp_cfgVPhaseRotationInhibitTime(self, name, value):
print('trying to set cfg_V_PhaseRotationInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_PhaseRotationInhibitTime', int(value))
def vfdipp_cfgVPhaseRotationTripType(self, name, value):
print('trying to set cfg_V_PhaseRotationTripType to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_PhaseRotationTripType', int(value))
def vfdipp_cfgVUnderfrequencyInhibitTime(self, name, value):
print('trying to set cfg_V_UnderfrequencyInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_UnderfrequencyInhibitTime', int(value))
def vfdipp_cfgVUnderfrequencyTripDelay(self, name, value):
print('trying to set cfg_V_UnderfrequencyTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_UnderfrequencyTripDelay', float(value))
def vfdipp_cfgVUnderfrequencyTripLevel(self, name, value):
print('trying to set cfg_V_UnderfrequencyTripLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_UnderfrequencyTripLevel', int(value))
def vfdipp_cfgVUnderfrequencyWarningLevel(self, name, value):
print('trying to set cfg_V_UnderfrequencyWarningLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_UnderfrequencyWarningLevel', int(value))
def vfdipp_cfgVUndervoltageInhibitTime(self, name, value):
print('trying to set cfg_V_UndervoltageInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_UndervoltageInhibitTime', int(value))
def vfdipp_cfgVUndervoltageTripDelay(self, name, value):
print('trying to set cfg_V_UndervoltageTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_UndervoltageTripDelay', float(value))
def vfdipp_cfgVUndervoltageTripLevel(self, name, value):
print('trying to set cfg_V_UndervoltageTripLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_UndervoltageTripLevel', float(value))
def vfdipp_cfgVUndervoltageWarningLevel(self, name, value):
print('trying to set cfg_V_UndervoltageWarningLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_UndervoltageWarningLevel', float(value))
def vfdipp_cfgVVoltageImbalanceInhibitTime(self, name, value):
print('trying to set cfg_V_VoltageImbalanceInhibitTime to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_VoltageImbalanceInhibitTime', int(value))
def vfdipp_cfgVVoltageImbalanceTripDelay(self, name, value):
print('trying to set cfg_V_VoltageImbalanceTripDelay to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_VoltageImbalanceTripDelay', float(value))
def vfdipp_cfgVVoltageImbalanceTripLevel(self, name, value):
print('trying to set cfg_V_VoltageImbalanceTripLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_VoltageImbalanceTripLevel', int(value))
def vfdipp_cfgVVoltageImbalanceWarningLevel(self, name, value):
print('trying to set cfg_V_VoltageImbalanceWarningLevel to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_VoltageImbalanceWarningLevel', int(value))
def vfdipp_cfgVVoltageMode(self, name, value):
print('trying to set cfg_V_VoltageMode to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_V_VoltageMode', int(value))
def vfdipp_cfgWRITE(self, name, value):
print('trying to set cfg_WRITE to {}'.format(value))
return u800.writeMicroTag(addr, 'cfg_WRITE', int(value))
def vfdipp_downtimeTimeParameter(self, name, value):
print('trying to set Downtime_Time_Parameter to {}'.format(value))
return u800.writeMicroTag(addr, 'Downtime_Time_Parameter', int(value))
def vfdipp_downtimeTimeParameterOL(self, name, value):
print('trying to set Downtime_Time_Parameter_OL to {}'.format(value))
return u800.writeMicroTag(addr, 'Downtime_Time_Parameter_OL', int(value))
def vfdipp_pressureAlarmDelay(self, name, value):
print('trying to set Pressure_Alarm_Delay to {}'.format(value))
return u800.writeMicroTag(addr, 'Pressure_Alarm_Delay', int(value))
def vfdipp_pressureAlarmStartupDelay(self, name, value):
print('trying to set Pressure_Alarm_Startup_Delay to {}'.format(value))
return u800.writeMicroTag(addr, 'Pressure_Alarm_Startup_Delay', int(value))
def vfdipp_pressureEUMax(self, name, value):
print('trying to set Pressure_EU_Max to {}'.format(value))
return u800.writeMicroTag(addr, 'Pressure_EU_Max', float(value))
def vfdipp_pressureEUMin(self, name, value):
print('trying to set Pressure_EU_Min to {}'.format(value))
return u800.writeMicroTag(addr, 'Pressure_EU_Min', float(value))
def vfdipp_pressureHiSP(self, name, value):
print('trying to set Pressure_Hi_SP to {}'.format(value))
return u800.writeMicroTag(addr, 'Pressure_Hi_SP', float(value))
def vfdipp_pressureLoSP(self, name, value):
print('trying to set Pressure_Lo_SP to {}'.format(value))
return u800.writeMicroTag(addr, 'Pressure_Lo_SP', float(value))
def vfdipp_pressureShutdown(self, name, value):
print('trying to set Pressure_Shutdown to {}'.format(value))
return u800.writeMicroTag(addr, 'Pressure_Shutdown', float(value))
def vfdipp_pressureShutdownEnabled(self, name, value):
print('trying to set Pressure_Shutdown_Enabled to {}'.format(value))
return u800.writeMicroTag(addr, 'Pressure_Shutdown_Enabled', int(value))
def vfdipp_pressureStartup(self, name, value):
print('trying to set Pressure_Startup to {}'.format(value))
return u800.writeMicroTag(addr, 'Pressure_Startup', float(value))
def vfdipp_pressureStartupEnabled(self, name, value):
print('trying to set Pressure_Startup_Enabled to {}'.format(value))
return u800.writeMicroTag(addr, 'Pressure_Startup_Enabled', int(value))
def vfdipp_pressureSwitchEnabled(self, name, value):
print('trying to set Pressure_Switch_Enabled to {}'.format(value))
return u800.writeMicroTag(addr, 'Pressure_Switch_Enabled', int(value))
def vfdipp_pressureTransducerEnabled(self, name, value):
print('trying to set Pressure_Transducer_Enabled to {}'.format(value))
return u800.writeMicroTag(addr, 'Pressure_Transducer_Enabled', int(value))
def vfdipp_startCommand(self, name, value):
print('trying to set Start_Command to {}'.format(value))
return u800.writeMicroTag(addr, 'Start_Command', int(value))
def vfdipp_stopCommand(self, name, value):
print('trying to set Stop_Command to {}'.format(value))
return u800.writeMicroTag(addr, 'Stop_Command', int(value))
def vfdipp_tempShutdown(self, name, value):
print('trying to set Temp_Shutdown to {}'.format(value))
return u800.writeMicroTag(addr, 'Temp_Shutdown', float(value))
def vfdipp_tempShutdownEnabled(self, name, value):
print('trying to set Temp_Shutdown_Enabled to {}'.format(value))
return u800.writeMicroTag(addr, 'Temp_Shutdown_Enabled', int(value))
def vfdipp_tempStartup(self, name, value):
print('trying to set Temp_Startup to {}'.format(value))
return u800.writeMicroTag(addr, 'Temp_Startup', float(value))
def vfdipp_tempStartupEnabled(self, name, value):
print('trying to set Temp_Startup_Enabled to {}'.format(value))
return u800.writeMicroTag(addr, 'Temp_Startup_Enabled', int(value))
def vfdipp_tripEnableVOverfrequency(self, name, value):
print('trying to set TripEnable_V_Overfrequency to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnable_V_Overfrequency', int(value))
def vfdipp_tripEnableVOvervoltage(self, name, value):
print('trying to set TripEnable_V_Overvoltage to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnable_V_Overvoltage', int(value))
def vfdipp_tripEnableVPhaseRotation(self, name, value):
print('trying to set TripEnable_V_PhaseRotation to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnable_V_PhaseRotation', int(value))
def vfdipp_tripEnableVUnderfrequency(self, name, value):
print('trying to set TripEnable_V_Underfrequency to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnable_V_Underfrequency', int(value))
def vfdipp_tripEnableVUndervoltage(self, name, value):
print('trying to set TripEnable_V_Undervoltage to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnable_V_Undervoltage', int(value))
def vfdipp_tripEnableVVoltageUnbalance(self, name, value):
print('trying to set TripEnable_V_VoltageUnbalance to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnable_V_VoltageUnbalance', int(value))
def vfdipp_tripEnabledICurrentImbalance(self, name, value):
print('trying to set TripEnabled_I_CurrentImbalance to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnabled_I_CurrentImbalance', int(value))
def vfdipp_tripEnabledIGroundFault(self, name, value):
print('trying to set TripEnabled_I_GroundFault to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnabled_I_GroundFault', int(value))
def vfdipp_tripEnabledIJam(self, name, value):
print('trying to set TripEnabled_I_Jam to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnabled_I_Jam', int(value))
def vfdipp_tripEnabledILineLoss(self, name, value):
print('trying to set TripEnabled_I_LineLoss to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnabled_I_LineLoss', int(value))
def vfdipp_tripEnabledIOvercurrent(self, name, value):
print('trying to set TripEnabled_I_Overcurrent to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnabled_I_Overcurrent', int(value))
def vfdipp_tripEnabledIOverload(self, name, value):
print('trying to set TripEnabled_I_Overload to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnabled_I_Overload', int(value))
def vfdipp_tripEnabledIPhaseLoss(self, name, value):
print('trying to set TripEnabled_I_PhaseLoss to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnabled_I_PhaseLoss', int(value))
def vfdipp_tripEnabledIStall(self, name, value):
print('trying to set TripEnabled_I_Stall to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnabled_I_Stall', int(value))
def vfdipp_tripEnabledIUndercurrent(self, name, value):
print('trying to set TripEnabled_I_Undercurrent to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnabled_I_Undercurrent', int(value))
def vfdipp_tripEnabledIUnderload(self, name, value):
print('trying to set TripEnabled_I_Underload to {}'.format(value))
return u800.writeMicroTag(addr, 'TripEnabled_I_Underload', int(value))
def vfdipp_tripResetCmd(self, name, value):
print('trying to set TripResetCmd to {}'.format(value))
return u800.writeMicroTag(addr, 'TripResetCmd', int(value))
def vfdipp_warningEnableVOverfrequency(self, name, value):
print('trying to set WarningEnable_V_Overfrequency to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnable_V_Overfrequency', int(value))
def vfdipp_warningEnableVOvervoltage(self, name, value):
print('trying to set WarningEnable_V_Overvoltage to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnable_V_Overvoltage', int(value))
def vfdipp_warningEnableVPhaseRotation(self, name, value):
print('trying to set WarningEnable_V_PhaseRotation to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnable_V_PhaseRotation', int(value))
def vfdipp_warningEnableVUnderfrequency(self, name, value):
print('trying to set WarningEnable_V_Underfrequency to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnable_V_Underfrequency', int(value))
def vfdipp_warningEnableVUndervoltage(self, name, value):
print('trying to set WarningEnable_V_Undervoltage to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnable_V_Undervoltage', int(value))
def vfdipp_warningEnableVVoltageUnbalance(self, name, value):
print('trying to set WarningEnable_V_VoltageUnbalance to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnable_V_VoltageUnbalance', int(value))
def vfdipp_warningEnabledICurrentImbalance(self, name, value):
print('trying to set WarningEnabled_I_CurrentImbalance to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnabled_I_CurrentImbalance', int(value))
def vfdipp_warningEnabledIGroundFault(self, name, value):
print('trying to set WarningEnabled_I_GroundFault to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnabled_I_GroundFault', int(value))
def vfdipp_warningEnabledIJam(self, name, value):
print('trying to set WarningEnabled_I_Jam to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnabled_I_Jam', int(value))
def vfdipp_warningEnabledILineLoss(self, name, value):
print('trying to set WarningEnabled_I_LineLoss to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnabled_I_LineLoss', int(value))
def vfdipp_warningEnabledIOvercurrent(self, name, value):
print('trying to set WarningEnabled_I_Overcurrent to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnabled_I_Overcurrent', int(value))
def vfdipp_warningEnabledIOverload(self, name, value):
print('trying to set WarningEnabled_I_Overload to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnabled_I_Overload', int(value))
def vfdipp_warningEnabledIPhaseLoss(self, name, value):
print('trying to set WarningEnabled_I_PhaseLoss to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnabled_I_PhaseLoss', int(value))
def vfdipp_warningEnabledIStall(self, name, value):
print('trying to set WarningEnabled_I_Stall to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnabled_I_Stall', int(value))
def vfdipp_warningEnabledIUndercurrent(self, name, value):
print('trying to set WarningEnabled_I_Undercurrent to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnabled_I_Undercurrent', int(value))
def vfdipp_warningEnabledIUnderload(self, name, value):
print('trying to set WarningEnabled_I_Underload to {}'.format(value))
return u800.writeMicroTag(addr, 'WarningEnabled_I_Underload', int(value))

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,94 @@
from pycomm_micro.ab_comm.clx import Driver as u800Driver
import logging
import sys
def readMicroTag(addr, tag):
logging.basicConfig(
filename="u800Driver.log",
format="%(levelname)-10s %(asctime)s %(message)s",
level=logging.DEBUG
)
c = u800Driver()
if c.open(addr):
try:
v = c.read_tag(tag)
# print(v)
return v
except Exception as e:
err = c.get_status()
c.close()
print err
pass
c.close()
def getTagType(addr, tag):
logging.basicConfig(
filename="u800Driver.log",
format="%(levelname)-10s %(asctime)s %(message)s",
level=logging.DEBUG
)
c = u800Driver()
if c.open(addr):
try:
return c.read_tag(tag)[1]
except Exception as e:
err = c.get_status()
c.close()
print err
pass
c.close()
def writeMicroTag(addr, tag, val):
logging.basicConfig(
filename="u800Driver.log",
format="%(levelname)-10s %(asctime)s %(message)s",
level=logging.DEBUG
)
c = u800Driver()
if c.open(addr):
try:
#typ = getTagType(addr, tag)
cv = c.read_tag(tag)
wt = c.write_tag(tag, val, cv[1])
# print(wt)
return wt
except Exception as e:
err = c.get_status()
c.close()
print err
pass
c.close()
def readMicroTagList(addr, tList):
logging.basicConfig(
filename="u800Driver.log",
format="%(levelname)-10s %(asctime)s %(message)s",
level=logging.DEBUG
)
c = u800Driver()
if c.open(addr):
vals = []
try:
for t in tList:
v = c.read_tag(t)
vals.append({"tag":t,"val":v[0], "type":v[1]})
# print(v)
# print("{0} - {1}".format(t, v))
except Exception as e:
err = c.get_status()
c.close()
print err
pass
c.close()
return vals
if __name__ == '__main__':
if len(sys.argv) > 2:
print(readMicroTag(sys.argv[1], sys.argv[2]))
else:
print ("Did not pass a target and tag name.")

343
POCloud_Driver/parseTags.py Normal file
View File

@@ -0,0 +1,343 @@
import pickle
import xml.etree.ElementTree as ET
tree = ET.parse('tags.xml')
root = tree.getroot()
channels = {}
unreadable_channels = {}
ignored_channels = {}
writeable_channels = {}
ignore_tags = [
"cmd_Run",
"cmd_TimerRun",
"DH_DischargePressure",
"DH_DischargeTemperature",
"DH_VibrationX",
"DH_VibrationY",
"DH_WindingTemperature",
"DigitalInput_Status_0",
"DigitalInput_Status_1",
"DigitalInput_Status_2",
"DigitalInput_Status_3",
"DigitalInput_Status_4",
"DigitalInput_Status_5",
"E300_OUTPUT_NUMBER",
"E300_OUTPUT_SET_CORRECTLY",
"E300_Output_Enable",
"E300_Output_Toggled",
"E300_SCAN_RATE",
"Enable_IO_Read",
"Pressure_OOT_Scans",
"Pressure_OOT_Seconds",
"Restart_Allowed",
"Restart_Command",
"Run_Time",
"Shutdown_Time"
"Start_Button",
"Start_Time",
"Start_Time_Set",
"sts_TimerRunTimeSet",
"sts_TimerCycleActive",
"sts_TimerWaitTimeSet",
"sts_TripCountIncreased",
"time_CurrentTime",
"time_TimerRunTime",
"time_TimerWaitTime",
"Time_Until_Startup",
"timer_RunTimeLeft",
"timer_WaitTimeLeft",
"TripResetWriteStatus",
"cfg_I_L1LossTripDelay", # Individual Line tags handled by generic Line tags
"cfg_I_L1_OvercurrentTripDelay",
"cfg_I_L1_OvercurrentTripLevel",
"cfg_I_L1_OvercurrentWarningLevel",
"cfg_I_L1_UndercurrentTripDelay",
"cfg_I_L1_UndercurrentTripLevel",
"cfg_I_L1_UndercurrentWarningLevel",
"cfg_I_L2LossTripDelay",
"cfg_I_L2_OvercurrentTripDelay",
"cfg_I_L2_OvercurrentTripLevel",
"cfg_I_L2_OvercurrentWarningLevel",
"cfg_I_L2_UndercurrentTripDelay",
"cfg_I_L2_UndercurrentTripLevel",
"cfg_I_L2_UndercurrentWarningLevel",
"cfg_I_L3LossTripDelay",
"cfg_I_L3_OvercurrentTripDelay",
"cfg_I_L3_OvercurrentTripLevel",
"cfg_I_L3_OvercurrentWarningLevel",
"cfg_I_L3_UndercurrentTripDelay",
"cfg_I_L3_UndercurrentTripLevel",
"cfg_I_L3_UndercurrentWarningLevel",
"cfg_I_TripEnableCurrent", # Enables get build by the enable bits
"cfg_I_WarningEnableCurrent",
"cfg_P_OverApparentPowerInhibitTime", # We're not going to worry about the power configuration for this panel
"cfg_P_OverApparentPowerTripDelay",
"cfg_P_OverApparentPowerTripLevel",
"cfg_P_OverApparentPowerWarningLevel",
"cfg_P_OverPowerFactorLagInhibitTime",
"cfg_P_OverPowerFactorLagTripDelay",
"cfg_P_OverPowerFactorLagTripLevel",
"cfg_P_OverPowerFactorLagWarningLevel",
"cfg_P_OverPowerFactorLeadInhibitTime",
"cfg_P_OverPowerFactorLeadTripDelay",
"cfg_P_OverPowerFactorLeadTripLevel",
"cfg_P_OverPowerFactorLeadWarningLevel",
"cfg_P_OverReactiveConsumedInhibitTime",
"cfg_P_OverReactiveConsumedTripDelay",
"cfg_P_OverReactiveConsumedTripLevel",
"cfg_P_OverReactiveConsumedWarningLevel",
"cfg_P_OverReactiveGeneratedInhibitTime",
"cfg_P_OverReactiveGeneratedTripDelay",
"cfg_P_OverReactiveGeneratedTripLevel",
"cfg_P_OverReactiveGeneratedWarningLevel",
"cfg_P_OverRealPowerInhibitTime",
"cfg_P_OverRealPowerTripDelay",
"cfg_P_OverRealPowerTripLevel",
"cfg_P_OverRealPowerWarningLevel",
"cfg_P_TripEnablePower",
"cfg_P_UnderApparentPowerInhibitTime",
"cfg_P_UnderApparentPowerTripDelay",
"cfg_P_UnderApparentPowerTripLevel",
"cfg_P_UnderApparentPowerWarningLevel",
"cfg_P_UnderPowerFactorLagInhibitTime",
"cfg_P_UnderPowerFactorLagTripDelay",
"cfg_P_UnderPowerFactorLagTripLevel",
"cfg_P_UnderPowerFactorLagWarningLevel",
"cfg_P_UnderPowerFactorLeadInhibitTime",
"cfg_P_UnderPowerFactorLeadTripDelay",
"cfg_P_UnderPowerFactorLeadTripLevel",
"cfg_P_UnderPowerFactorLeadWarningLevel",
"cfg_P_UnderReactiveConsumedInhibitTime",
"cfg_P_UnderReactiveConsumedTripDelay",
"cfg_P_UnderReactiveConsumedTripLevel",
"cfg_P_UnderReactiveConsumedWarningLevel",
"cfg_P_UnderReactiveGeneratedInhibitTime",
"cfg_P_UnderReactiveGeneratedTripDelay",
"cfg_P_UnderReactiveGeneratedTripLevel",
"cfg_P_UnderReactiveGeneratedWarningLevel",
"cfg_P_UnderRealPowerInhibitTime",
"cfg_P_UnderRealPowerTripDelay",
"cfg_P_UnderRealPowerTripLevel",
"cfg_P_UnderRealPowerWarningLevel",
"cfg_P_WarningEnablePower",
"cfg_V_TripEnableVoltage",
"cfg_V_WarningEnableVoltage"
]
writeable_tags = [
"cfg_C_FLASetting",
"cfg_C_TripEnableControl",
"cfg_C_WarningEnableControl",
"cfg_ClearTripCountAfter",
"cfg_GF_GroundFaultInhibitTime",
"cfg_GF_GroundFaultTripDelay",
"cfg_GF_GroundFaultTripLevel",
"cfg_GF_GroundFaultWarningDelay",
"cfg_GF_GroundFaultWarningLevel",
"cfg_I_CTPrimary",
"cfg_I_CTSecondary",
"cfg_I_CurrentImbalanceInhibitTime",
"cfg_I_CurrentImbalanceTripDelay",
"cfg_I_CurrentImbalanceTripLevel",
"cfg_I_CurrentImbalanceWarningLevel",
"cfg_I_JamInhibitTime",
"cfg_I_JamTripDelay",
"cfg_I_JamWarningLevel",
"cfg_I_LineLossInhibitTime",
"cfg_I_LineLossTripDelay",
"cfg_I_OvercurrentInhibitTime",
"cfg_I_OvercurrentTripDelay",
"cfg_I_OvercurrentTripLevel",
"cfg_I_OvercurrentWarningLevel",
"cfg_I_StallEnabledTime",
"cfg_I_StallTripLevel",
"cfg_I_UndercurrentInhibitTime",
"cfg_I_UndercurrentTripDelay",
"cfg_I_UndercurrentTripLevel",
"cfg_I_UndercurrentWarningLevel",
"cfg_I_UnderloadInhibitTime",
"cfg_I_UnderloadTripDelay",
"cfg_I_UnderloadTripLevel",
"cfg_I_UnderloadWarningLevel",
"cfg_OverloadTripCountLimit",
"cfg_PL_PhaseLossInhibitTime",
"cfg_PL_PhaseLossTripDelay",
"cfg_READ",
"cfg_SpecificGravity",
"cfg_TCU_TripClass",
"cfg_TimerModeEnabled",
"cfg_TimerRunTime",
"cfg_TimerWaitTime",
"cfg_TripCountLimit",
"cfg_V_OverfrequencyInhibitTime",
"cfg_V_OverfrequencyTripDelay",
"cfg_V_OverfrequencyTripLevel",
"cfg_V_OverfrequencyWarningLevel",
"cfg_V_OvervoltageInhibitTime",
"cfg_V_OvervoltageTripDelay",
"cfg_V_OvervoltageTripLevel",
"cfg_V_OvervoltageWarningLevel",
"cfg_V_PTPrimary",
"cfg_V_PTSecondary",
"cfg_V_PhaseRotationInhibitTime",
"cfg_V_PhaseRotationTripType",
"cfg_V_UnderfrequencyInhibitTime",
"cfg_V_UnderfrequencyTripDelay",
"cfg_V_UnderfrequencyTripLevel",
"cfg_V_UnderfrequencyWarningLevel",
"cfg_V_UndervoltageInhibitTime",
"cfg_V_UndervoltageTripDelay",
"cfg_V_UndervoltageTripLevel",
"cfg_V_UndervoltageWarningLevel",
"cfg_V_VoltageImbalanceInhibitTime",
"cfg_V_VoltageImbalanceTripDelay",
"cfg_V_VoltageImbalanceTripLevel",
"cfg_V_VoltageImbalanceWarningLevel",
"cfg_V_VoltageMode",
"cfg_WRITE",
"Downtime_Time_Parameter",
"Downtime_Time_Parameter_OL",
"Pressure_Alarm_Delay",
"Pressure_Alarm_Startup_Delay",
"Pressure_EU_Max",
"Pressure_EU_Min",
"Pressure_Hi_SP",
"Pressure_Lo_SP",
"Pressure_Shutdown",
"Pressure_Shutdown_Enabled",
"Pressure_Startup",
"Pressure_Startup_Enabled",
"Pressure_Switch_Enabled",
"Pressure_Transducer_Enabled",
"Start_Command",
"Stop_Command",
"Temp_Shutdown",
"Temp_Shutdown_Enabled",
"Temp_Startup",
"Temp_Startup_Enabled",
"TripEnable_V_Overfrequency",
"TripEnable_V_Overvoltage",
"TripEnable_V_PhaseRotation",
"TripEnable_V_Underfrequency",
"TripEnable_V_Undervoltage",
"TripEnable_V_VoltageUnbalance",
"TripEnabled_I_CurrentImbalance",
"TripEnabled_I_GroundFault",
"TripEnabled_I_Jam",
"TripEnabled_I_LineLoss",
"TripEnabled_I_Overcurrent",
"TripEnabled_I_Overload",
"TripEnabled_I_PhaseLoss",
"TripEnabled_I_Stall",
"TripEnabled_I_Undercurrent",
"TripEnabled_I_Underload",
"TripResetCmd",
"WarningEnable_V_Overfrequency",
"WarningEnable_V_Overvoltage",
"WarningEnable_V_PhaseRotation",
"WarningEnable_V_Underfrequency",
"WarningEnable_V_Undervoltage",
"WarningEnable_V_VoltageUnbalance",
"WarningEnabled_I_CurrentImbalance",
"WarningEnabled_I_GroundFault",
"WarningEnabled_I_Jam",
"WarningEnabled_I_LineLoss",
"WarningEnabled_I_Overcurrent",
"WarningEnabled_I_Overload",
"WarningEnabled_I_PhaseLoss",
"WarningEnabled_I_Stall",
"WarningEnabled_I_Undercurrent",
"WarningEnabled_I_Underload",
]
for child in root:
try:
tagName = child[1].text
tagType = child[2].text
struct = {
'tag':tagName,
"last_value": "",
"data_type": tagType,
"change_amount": .5,
"last_time_uploaded": 0,
"max_time_between_uploads": 360
}
if tagName in writeable_tags:
struct['read_only'] = False
else:
struct['read_only'] = True
chName = tagName.replace("_", "") # Channel names cannot have underscores
chName = chName[0].lower() + chName[1:] # Channel names should all start wth a lowercase letter
if not tagName in ignore_tags:
if tagType == "BOOL":
struct['change_amount'] = None
channels[chName] = struct
elif tagType == "REAL" or tagType[-3:] == "INT":
channels[chName] = struct
else:
unreadable_channels[chName] = struct
else:
ignored_channels[chName] = struct
if struct['read_only'] is False:
writeable_channels[chName] = struct
except Exception, e:
print "oops: {}".format(e)
with open('ipp_channels_setup.py', 'wb') as txtFile:
txtFile.write("import pickle\r\r")
txtFile.write("channels = {\r")
for x in sorted(channels):
c = channels[x]
txtFile.write("\t'{}': {{\r".format(x))
txtFile.write("\t\t'data_type': '{}',\r".format(c['data_type']))
txtFile.write("\t\t'change_amount': {},\r".format(c['change_amount']))
txtFile.write("\t\t'max_time_between_uploads': {},\r".format(c['max_time_between_uploads']))
txtFile.write("\t\t'tag': '{}',\r".format(c['tag']))
txtFile.write("\t\t'last_time_uploaded': {},\r".format(c['last_time_uploaded']))
txtFile.write("\t\t'last_value': '{}',\r".format(c['last_value']))
txtFile.write("\t},\r")
txtFile.write("}\r")
txtFile.write("\rwith open('ipp_channels.p', 'wb') as ch_f:\r")
txtFile.write("\tpickle.dump(channels, ch_f)\r\r")
with open('channels.txt', 'wb') as ch_txt:
for x in sorted(channels):
c = channels[x]
rw = 'read only'
if c['read_only'] is False:
rw = "WRITEABLE"
ch_txt.write('[] - {} - {} - {}\r'.format(x, c['data_type'], rw))
print("UNREADABLE CHANNELS: ")
for y in sorted(unreadable_channels):
print("{} - {}".format(unreadable_channels[y]['data_type'], y))
print("")
print("")
print("")
print("IGNORED CHANNELS: ")
for z in sorted(ignored_channels):
print("{} - {}".format(z, ignored_channels[z]['data_type']))
with open('writeFunctions.txt', 'wb') as wftxt:
for a in sorted(writeable_channels):
c = writeable_channels[a]
wftxt.write("def vfdipp_{0}(self, name, value):\r".format(a))
wftxt.write("\tprint('trying to set {0} to {{}}'.format(value))\r".format(c['tag']))
if c['data_type'] == 'REAL':
wftxt.write("\treturn u800.writeMicroTag(addr, '{0}', float(value))\r".format(c['tag']))
elif (c['data_type'] == 'BOOL') or (c['data_type'][-3:] == "INT"):
wftxt.write("\treturn u800.writeMicroTag(addr, '{0}', int(value))\r".format(c['tag']))
else:
print("!!!! DIDNT WORK FOR {0}".format(c))
wftxt.write("\r")

View File

@@ -0,0 +1 @@
__author__ = 'agostino'

View File

@@ -0,0 +1,2 @@
__author__ = 'agostino'
import logging

View File

@@ -0,0 +1,847 @@
# -*- coding: utf-8 -*-
#
# clx.py - Ethernet/IP Client for Rockwell PLCs
#
#
# Copyright (c) 2014 Agostino Ruscito <ruscito@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
from pycomm_micro.cip.cip_base import *
from pycomm_micro.common import setup_logger
import logging
class Driver(Base):
"""
This Ethernet/IP client is based on Rockwell specification. Please refer to the link below for details.
http://literature.rockwellautomation.com/idc/groups/literature/documents/pm/1756-pm020_-en-p.pdf
The following services have been implemented:
- Read Tag Service (0x4c)
- Read Tag Fragment Service (0x52)
- Write Tag Service (0x4d)
- Write Tag Fragment Service (0x53)
- Multiple Service Packet (0x0a)
The client has been successfully tested with the following PLCs:
- CompactLogix 5330ERM
- CompactLogix 5370
- ControlLogix 5572 and 1756-EN2T Module
"""
def __init__(self, debug=False, filename=None):
if debug:
super(Driver, self).__init__(setup_logger('ab_comm.clx', logging.DEBUG, filename))
else:
super(Driver, self).__init__(setup_logger('ab_comm.clx', logging.INFO, filename))
self._buffer = {}
self._get_template_in_progress = False
self.__version__ = '0.2'
def get_last_tag_read(self):
""" Return the last tag read by a multi request read
:return: A tuple (tag name, value, type)
"""
return self._last_tag_read
def get_last_tag_write(self):
""" Return the last tag write by a multi request write
:return: A tuple (tag name, 'GOOD') if the write was successful otherwise (tag name, 'BAD')
"""
return self._last_tag_write
def _parse_instance_attribute_list(self, start_tag_ptr, status):
""" extract the tags list from the message received
:param start_tag_ptr: The point in the message string where the tag list begin
:param status: The status of the message receives
"""
tags_returned = self._reply[start_tag_ptr:]
tags_returned_length = len(tags_returned)
idx = 0
instance = 0
count = 0
try:
while idx < tags_returned_length:
instance = unpack_dint(tags_returned[idx:idx+4])
idx += 4
tag_length = unpack_uint(tags_returned[idx:idx+2])
idx += 2
tag_name = tags_returned[idx:idx+tag_length]
idx += tag_length
symbol_type = unpack_uint(tags_returned[idx:idx+2])
idx += 2
count += 1
self._tag_list.append({'instance_id': instance,
'tag_name': tag_name,
'symbol_type': symbol_type})
except Exception as e:
raise DataError(e)
if status == SUCCESS:
self._last_instance = -1
elif status == 0x06:
self._last_instance = instance + 1
else:
self._status = (1, 'unknown status during _parse_tag_list')
self._last_instance = -1
def _parse_structure_makeup_attributes(self, start_tag_ptr, status):
""" extract the tags list from the message received
:param start_tag_ptr: The point in the message string where the tag list begin
:param status: The status of the message receives
"""
self._buffer = {}
if status != SUCCESS:
self._buffer['Error'] = status
return
attribute = self._reply[start_tag_ptr:]
idx = 4
try:
if unpack_uint(attribute[idx:idx + 2]) == SUCCESS:
idx += 2
self._buffer['object_definition_size'] = unpack_dint(attribute[idx:idx + 4])
else:
self._buffer['Error'] = 'object_definition Error'
return
idx += 6
if unpack_uint(attribute[idx:idx + 2]) == SUCCESS:
idx += 2
self._buffer['structure_size'] = unpack_dint(attribute[idx:idx + 4])
else:
self._buffer['Error'] = 'structure Error'
return
idx += 6
if unpack_uint(attribute[idx:idx + 2]) == SUCCESS:
idx += 2
self._buffer['member_count'] = unpack_uint(attribute[idx:idx + 2])
else:
self._buffer['Error'] = 'member_count Error'
return
idx += 4
if unpack_uint(attribute[idx:idx + 2]) == SUCCESS:
idx += 2
self._buffer['structure_handle'] = unpack_uint(attribute[idx:idx + 2])
else:
self._buffer['Error'] = 'structure_handle Error'
return
return self._buffer
except Exception as e:
raise DataError(e)
def _parse_template(self, start_tag_ptr, status):
""" extract the tags list from the message received
:param start_tag_ptr: The point in the message string where the tag list begin
:param status: The status of the message receives
"""
tags_returned = self._reply[start_tag_ptr:]
bytes_received = len(tags_returned)
self._buffer += tags_returned
if status == SUCCESS:
self._get_template_in_progress = False
elif status == 0x06:
self._byte_offset += bytes_received
else:
self._status = (1, 'unknown status {0} during _parse_template'.format(status))
self.logger.warning(self._status)
self._last_instance = -1
def _parse_fragment(self, start_ptr, status):
""" parse the fragment returned by a fragment service.
:param start_ptr: Where the fragment start within the replay
:param status: status field used to decide if keep parsing or stop
"""
try:
data_type = unpack_uint(self._reply[start_ptr:start_ptr+2])
fragment_returned = self._reply[start_ptr+2:]
except Exception as e:
raise DataError(e)
fragment_returned_length = len(fragment_returned)
idx = 0
while idx < fragment_returned_length:
try:
typ = I_DATA_TYPE[data_type]
value = UNPACK_DATA_FUNCTION[typ](fragment_returned[idx:idx+DATA_FUNCTION_SIZE[typ]])
idx += DATA_FUNCTION_SIZE[typ]
except Exception as e:
raise DataError(e)
self._tag_list.append((self._last_position, value))
self._last_position += 1
if status == SUCCESS:
self._byte_offset = -1
elif status == 0x06:
self._byte_offset += fragment_returned_length
else:
self._status = (2, 'unknown status during _parse_fragment')
self._byte_offset = -1
def _parse_multiple_request_read(self, tags):
""" parse the message received from a multi request read:
For each tag parsed, the information extracted includes the tag name, the value read and the data type.
Those information are appended to the tag list as tuple
:return: the tag list
"""
offset = 50
position = 50
try:
number_of_service_replies = unpack_uint(self._reply[offset:offset+2])
tag_list = []
for index in range(number_of_service_replies):
position += 2
start = offset + unpack_uint(self._reply[position:position+2])
general_status = unpack_usint(self._reply[start+2:start+3])
if general_status == 0:
data_type = unpack_uint(self._reply[start+4:start+6])
value_begin = start + 6
value_end = value_begin + DATA_FUNCTION_SIZE[I_DATA_TYPE[data_type]]
value = self._reply[value_begin:value_end]
self._last_tag_read = (tags[index], UNPACK_DATA_FUNCTION[I_DATA_TYPE[data_type]](value),
I_DATA_TYPE[data_type])
else:
self._last_tag_read = (tags[index], None, None)
tag_list.append(self._last_tag_read)
return tag_list
except Exception as e:
raise DataError(e)
def _parse_multiple_request_write(self, tags):
""" parse the message received from a multi request writ:
For each tag parsed, the information extracted includes the tag name and the status of the writing.
Those information are appended to the tag list as tuple
:return: the tag list
"""
offset = 50
position = 50
try:
number_of_service_replies = unpack_uint(self._reply[offset:offset+2])
tag_list = []
for index in range(number_of_service_replies):
position += 2
start = offset + unpack_uint(self._reply[position:position+2])
general_status = unpack_usint(self._reply[start+2:start+3])
if general_status == 0:
self._last_tag_write = (tags[index] + ('GOOD',))
else:
self._last_tag_write = (tags[index] + ('BAD',))
tag_list.append(self._last_tag_write)
return tag_list
except Exception as e:
raise DataError(e)
def _check_reply(self):
""" check the replayed message for error
"""
self._more_packets_available = False
try:
if self._reply is None:
self._status = (3, '%s without reply' % REPLAY_INFO[unpack_dint(self._message[:2])])
return False
# Get the type of command
typ = unpack_uint(self._reply[:2])
# Encapsulation status check
if unpack_dint(self._reply[8:12]) != SUCCESS:
self._status = (3, "{0} reply status:{1}".format(REPLAY_INFO[typ],
SERVICE_STATUS[unpack_dint(self._reply[8:12])]))
return False
# Command Specific Status check
if typ == unpack_uint(ENCAPSULATION_COMMAND["send_rr_data"]):
status = unpack_usint(self._reply[42:43])
if status != SUCCESS:
self._status = (3, "send_rr_data reply:{0} - Extend status:{1}".format(
SERVICE_STATUS[status], get_extended_status(self._reply, 42)))
return False
else:
return True
elif typ == unpack_uint(ENCAPSULATION_COMMAND["send_unit_data"]):
status = unpack_usint(self._reply[48:49])
if unpack_usint(self._reply[46:47]) == I_TAG_SERVICES_REPLY["Read Tag Fragmented"]:
self._parse_fragment(50, status)
return True
if unpack_usint(self._reply[46:47]) == I_TAG_SERVICES_REPLY["Get Instance Attributes List"]:
self._parse_instance_attribute_list(50, status)
return True
if unpack_usint(self._reply[46:47]) == I_TAG_SERVICES_REPLY["Get Attributes"]:
self._parse_structure_makeup_attributes(50, status)
return True
if unpack_usint(self._reply[46:47]) == I_TAG_SERVICES_REPLY["Read Template"] and \
self._get_template_in_progress:
self._parse_template(50, status)
return True
if status == 0x06:
self._status = (3, "Insufficient Packet Space")
self._more_packets_available = True
elif status != SUCCESS:
self._status = (3, "send_unit_data reply:{0} - Extend status:{1}".format(
SERVICE_STATUS[status], get_extended_status(self._reply, 48)))
return False
else:
return True
return True
except Exception as e:
raise DataError(e)
def read_tag(self, tag):
""" read tag from a connected plc
Possible combination can be passed to this method:
- ('Counts') a single tag name
- (['ControlWord']) a list with one tag or many
- (['parts', 'ControlWord', 'Counts'])
At the moment there is not a strong validation for the argument passed. The user should verify
the correctness of the format passed.
:return: None is returned in case of error otherwise the tag list is returned
"""
multi_requests = False
if isinstance(tag, list):
multi_requests = True
if not self._target_is_connected:
if not self.forward_open():
self._status = (6, "Target did not connected. read_tag will not be executed.")
self.logger.warning(self._status)
raise Error("Target did not connected. read_tag will not be executed.")
# multi_requests = False
if multi_requests:
rp_list = []
for t in tag:
rp = create_tag_rp(t, multi_requests=True)
if rp is None:
self._status = (6, "Cannot create tag {0} request packet. read_tag will not be executed.".format(tag))
raise DataError("Cannot create tag {0} request packet. read_tag will not be executed.".format(tag))
else:
rp_list.append(chr(TAG_SERVICES_REQUEST['Read Tag']) + rp + pack_uint(1))
message_request = build_multiple_service(rp_list, Base._get_sequence())
else:
rp = create_tag_rp(tag)
if rp is None:
self._status = (6, "Cannot create tag {0} request packet. read_tag will not be executed.".format(tag))
return None
else:
# Creating the Message Request Packet
message_request = [
pack_uint(Base._get_sequence()),
chr(TAG_SERVICES_REQUEST['Read Tag']), # the Request Service
chr(len(rp) / 2), # the Request Path Size length in word
rp, # the request path
pack_uint(1)
]
if self.send_unit_data(
build_common_packet_format(
DATA_ITEM['Connected'],
''.join(message_request),
ADDRESS_ITEM['Connection Based'],
addr_data=self._target_cid,
)) is None:
raise DataError("send_unit_data returned not valid data")
if multi_requests:
return self._parse_multiple_request_read(tag)
else:
# Get the data type
data_type = unpack_uint(self._reply[50:52])
# print I_DATA_TYPE[data_type]
try:
return UNPACK_DATA_FUNCTION[I_DATA_TYPE[data_type]](self._reply[52:]), I_DATA_TYPE[data_type]
except Exception as e:
raise DataError(e)
def read_array(self, tag, counts):
""" read array of atomic data type from a connected plc
At the moment there is not a strong validation for the argument passed. The user should verify
the correctness of the format passed.
:param tag: the name of the tag to read
:param counts: the number of element to read
:return: None is returned in case of error otherwise the tag list is returned
"""
if not self._target_is_connected:
if not self.forward_open():
self._status = (7, "Target did not connected. read_tag will not be executed.")
self.logger.warning(self._status)
raise Error("Target did not connected. read_tag will not be executed.")
self._byte_offset = 0
self._last_position = 0
self._tag_list = []
while self._byte_offset != -1:
rp = create_tag_rp(tag)
if rp is None:
self._status = (7, "Cannot create tag {0} request packet. read_tag will not be executed.".format(tag))
return None
else:
# Creating the Message Request Packet
message_request = [
pack_uint(Base._get_sequence()),
chr(TAG_SERVICES_REQUEST["Read Tag Fragmented"]), # the Request Service
chr(len(rp) / 2), # the Request Path Size length in word
rp, # the request path
pack_uint(counts),
pack_dint(self._byte_offset)
]
if self.send_unit_data(
build_common_packet_format(
DATA_ITEM['Connected'],
''.join(message_request),
ADDRESS_ITEM['Connection Based'],
addr_data=self._target_cid,
)) is None:
raise DataError("send_unit_data returned not valid data")
return self._tag_list
def write_tag(self, tag, value=None, typ=None):
""" write tag/tags from a connected plc
Possible combination can be passed to this method:
- ('tag name', Value, data type) as single parameters or inside a tuple
- ([('tag name', Value, data type), ('tag name2', Value, data type)]) as array of tuples
At the moment there is not a strong validation for the argument passed. The user should verify
the correctness of the format passed.
The type accepted are:
- BOOL
- SINT
- INT'
- DINT
- REAL
- LINT
- BYTE
- WORD
- DWORD
- LWORD
:param tag: tag name, or an array of tuple containing (tag name, value, data type)
:param value: the value to write or none if tag is an array of tuple or a tuple
:param typ: the type of the tag to write or none if tag is an array of tuple or a tuple
:return: None is returned in case of error otherwise the tag list is returned
"""
multi_requests = False
if isinstance(tag, list):
multi_requests = True
if not self._target_is_connected:
if not self.forward_open():
self._status = (8, "Target did not connected. write_tag will not be executed.")
self.logger.warning(self._status)
raise Error("Target did not connected. write_tag will not be executed.")
if multi_requests:
rp_list = []
tag_to_remove = []
idx = 0
for name, value, typ in tag:
# Create the request path to wrap the tag name
rp = create_tag_rp(name, multi_requests=True)
if rp is None:
self._status = (8, "Cannot create tag{0} req. packet. write_tag will not be executed".format(tag))
return None
else:
try: # Trying to add the rp to the request path list
val = PACK_DATA_FUNCTION[typ](value)
rp_list.append(
chr(TAG_SERVICES_REQUEST['Write Tag'])
+ rp
+ pack_uint(S_DATA_TYPE[typ])
+ pack_uint(1)
+ val
)
idx += 1
except (LookupError, struct.error) as e:
self._status = (8, "Tag:{0} type:{1} removed from write list. Error:{2}.".format(name, typ, e))
# The tag in idx position need to be removed from the rp list because has some kind of error
tag_to_remove.append(idx)
# Remove the tags that have not been inserted in the request path list
for position in tag_to_remove:
del tag[position]
# Create the message request
message_request = build_multiple_service(rp_list, Base._get_sequence())
else:
if isinstance(tag, tuple):
name, value, typ = tag
else:
name = tag
rp = create_tag_rp(name)
if rp is None:
self._status = (8, "Cannot create tag {0} request packet. write_tag will not be executed.".format(tag))
self.logger.warning(self._status)
return None
else:
# Creating the Message Request Packet
message_request = [
pack_uint(Base._get_sequence()),
chr(TAG_SERVICES_REQUEST["Write Tag"]), # the Request Service
chr(len(rp) / 2), # the Request Path Size length in word
rp, # the request path
pack_uint(S_DATA_TYPE[typ]), # data type
pack_uint(1), # Add the number of tag to write
PACK_DATA_FUNCTION[typ](value)
]
ret_val = self.send_unit_data(
build_common_packet_format(
DATA_ITEM['Connected'],
''.join(message_request),
ADDRESS_ITEM['Connection Based'],
addr_data=self._target_cid,
)
)
if multi_requests:
return self._parse_multiple_request_write(tag)
else:
if ret_val is None:
raise DataError("send_unit_data returned not valid data")
return ret_val
def write_array(self, tag, data_type, values):
""" write array of atomic data type from a connected plc
At the moment there is not a strong validation for the argument passed. The user should verify
the correctness of the format passed.
:param tag: the name of the tag to read
:param data_type: the type of tag to write
:param values: the array of values to write
"""
if not isinstance(values, list):
self._status = (9, "A list of tags must be passed to write_array.")
self.logger.warning(self._status)
raise DataError("A list of tags must be passed to write_array.")
if not self._target_is_connected:
if not self.forward_open():
self._status = (9, "Target did not connected. write_array will not be executed.")
self.logger.warning(self._status)
raise Error("Target did not connected. write_array will not be executed.")
array_of_values = ""
byte_size = 0
byte_offset = 0
for i, value in enumerate(values):
array_of_values += PACK_DATA_FUNCTION[data_type](value)
byte_size += DATA_FUNCTION_SIZE[data_type]
if byte_size >= 450 or i == len(values)-1:
# create the message and send the fragment
rp = create_tag_rp(tag)
if rp is None:
self._status = (9, "Cannot create tag {0} request packet. \
write_array will not be executed.".format(tag))
return None
else:
# Creating the Message Request Packet
message_request = [
pack_uint(Base._get_sequence()),
chr(TAG_SERVICES_REQUEST["Write Tag Fragmented"]), # the Request Service
chr(len(rp) / 2), # the Request Path Size length in word
rp, # the request path
pack_uint(S_DATA_TYPE[data_type]), # Data type to write
pack_uint(len(values)), # Number of elements to write
pack_dint(byte_offset),
array_of_values # Fragment of elements to write
]
byte_offset += byte_size
if self.send_unit_data(
build_common_packet_format(
DATA_ITEM['Connected'],
''.join(message_request),
ADDRESS_ITEM['Connection Based'],
addr_data=self._target_cid,
)) is None:
raise DataError("send_unit_data returned not valid data")
array_of_values = ""
byte_size = 0
def _get_instance_attribute_list_service(self):
""" Step 1: Finding user-created controller scope tags in a Logix5000 controller
This service returns instance IDs for each created instance of the symbol class, along with a list
of the attribute data associated with the requested attribute
"""
try:
if not self._target_is_connected:
if not self.forward_open():
self._status = (10, "Target did not connected. get_tag_list will not be executed.")
self.logger.warning(self._status)
raise Error("Target did not connected. get_tag_list will not be executed.")
self._last_instance = 0
self._get_template_in_progress = True
while self._last_instance != -1:
# Creating the Message Request Packet
message_request = [
pack_uint(Base._get_sequence()),
chr(TAG_SERVICES_REQUEST['Get Instance Attributes List']), # STEP 1
# the Request Path Size length in word
chr(3),
# Request Path ( 20 6B 25 00 Instance )
CLASS_ID["8-bit"], # Class id = 20 from spec 0x20
CLASS_CODE["Symbol Object"], # Logical segment: Symbolic Object 0x6B
INSTANCE_ID["16-bit"], # Instance Segment: 16 Bit instance 0x25
'\x00',
pack_uint(self._last_instance), # The instance
# Request Data
pack_uint(2), # Number of attributes to retrieve
pack_uint(1), # Attribute 1: Symbol name
pack_uint(2) # Attribute 2: Symbol type
]
if self.send_unit_data(
build_common_packet_format(
DATA_ITEM['Connected'],
''.join(message_request),
ADDRESS_ITEM['Connection Based'],
addr_data=self._target_cid,
)) is None:
raise DataError("send_unit_data returned not valid data")
self._get_template_in_progress = False
except Exception as e:
raise DataError(e)
def _get_structure_makeup(self, instance_id):
"""
get the structure makeup for a specific structure
"""
if not self._target_is_connected:
if not self.forward_open():
self._status = (10, "Target did not connected. get_tag_list will not be executed.")
self.logger.warning(self._status)
raise Error("Target did not connected. get_tag_list will not be executed.")
message_request = [
pack_uint(self._get_sequence()),
chr(TAG_SERVICES_REQUEST['Get Attributes']),
chr(3), # Request Path ( 20 6B 25 00 Instance )
CLASS_ID["8-bit"], # Class id = 20 from spec 0x20
CLASS_CODE["Template Object"], # Logical segment: Template Object 0x6C
INSTANCE_ID["16-bit"], # Instance Segment: 16 Bit instance 0x25
'\x00',
pack_uint(instance_id),
pack_uint(4), # Number of attributes
pack_uint(4), # Template Object Definition Size UDINT
pack_uint(5), # Template Structure Size UDINT
pack_uint(2), # Template Member Count UINT
pack_uint(1) # Structure Handle We can use this to read and write UINT
]
if self.send_unit_data(
build_common_packet_format(DATA_ITEM['Connected'],
''.join(message_request), ADDRESS_ITEM['Connection Based'],
addr_data=self._target_cid,)) is None:
raise DataError("send_unit_data returned not valid data")
return self._buffer
def _read_template(self, instance_id, object_definition_size):
""" get a list of the tags in the plc
"""
if not self._target_is_connected:
if not self.forward_open():
self._status = (10, "Target did not connected. get_tag_list will not be executed.")
self.logger.warning(self._status)
raise Error("Target did not connected. get_tag_list will not be executed.")
self._byte_offset = 0
self._buffer = ""
self._get_template_in_progress = True
try:
while self._get_template_in_progress:
# Creating the Message Request Packet
message_request = [
pack_uint(self._get_sequence()),
chr(TAG_SERVICES_REQUEST['Read Template']),
chr(3), # Request Path ( 20 6B 25 00 Instance )
CLASS_ID["8-bit"], # Class id = 20 from spec 0x20
CLASS_CODE["Template Object"], # Logical segment: Template Object 0x6C
INSTANCE_ID["16-bit"], # Instance Segment: 16 Bit instance 0x25
'\x00',
pack_uint(instance_id),
pack_dint(self._byte_offset), # Offset
pack_uint(((object_definition_size * 4)-23) - self._byte_offset)
]
if not self.send_unit_data(
build_common_packet_format(DATA_ITEM['Connected'], ''.join(message_request),
ADDRESS_ITEM['Connection Based'], addr_data=self._target_cid,)):
raise DataError("send_unit_data returned not valid data")
self._get_template_in_progress = False
return self._buffer
except Exception as e:
raise DataError(e)
def _isolating_user_tag(self):
try:
lst = self._tag_list
self._tag_list = []
for tag in lst:
if tag['tag_name'].find(':') != -1 or tag['tag_name'].find('__') != -1:
continue
if tag['symbol_type'] & 0b0001000000000000:
continue
dimension = tag['symbol_type'] & 0b0110000000000000 >> 13
template_instance_id = tag['symbol_type'] & 0b0000111111111111
if tag['symbol_type'] & 0b1000000000000000 :
tag_type = 'struct'
data_type = 'user-created'
self._tag_list.append({'instance_id': tag['instance_id'],
'template_instance_id': template_instance_id,
'tag_name': tag['tag_name'],
'dim': dimension,
'tag_type': tag_type,
'data_type': data_type,
'template': {},
'udt': {}})
else:
tag_type = 'atomic'
data_type = I_DATA_TYPE[template_instance_id]
self._tag_list.append({'instance_id': tag['instance_id'],
'tag_name': tag['tag_name'],
'dim': dimension,
'tag_type': tag_type,
'data_type': data_type})
except Exception as e:
raise DataError(e)
def _parse_udt_raw(self, tag):
try:
buff = self._read_template(tag['template_instance_id'], tag['template']['object_definition_size'])
member_count = tag['template']['member_count']
names = buff.split('\00')
lst = []
tag['udt']['name'] = 'Not an user defined structure'
for name in names:
if len(name) > 1:
if name.find(';') != -1:
tag['udt']['name'] = name[:name.find(';')]
elif name.find('ZZZZZZZZZZ') != -1:
continue
elif name.isalpha():
lst.append(name)
else:
continue
tag['udt']['internal_tags'] = lst
type_list = []
for i in xrange(member_count):
# skip member 1
if i != 0:
array_size = unpack_uint(buff[:2])
try:
data_type = I_DATA_TYPE[unpack_uint(buff[2:4])]
except Exception:
data_type = "None"
offset = unpack_dint(buff[4:8])
type_list.append((array_size, data_type, offset))
buff = buff[8:]
tag['udt']['data_type'] = type_list
except Exception as e:
raise DataError(e)
def get_tag_list(self):
self._tag_list = []
# Step 1
self._get_instance_attribute_list_service()
# Step 2
self._isolating_user_tag()
# Step 3
for tag in self._tag_list:
if tag['tag_type'] == 'struct':
tag['template'] = self._get_structure_makeup(tag['template_instance_id'])
for idx, tag in enumerate(self._tag_list):
# print (tag)
if tag['tag_type'] == 'struct':
self._parse_udt_raw(tag)
# Step 4
return self._tag_list

View File

@@ -0,0 +1,446 @@
# -*- coding: utf-8 -*-
#
# clx.py - Ethernet/IP Client for Rockwell PLCs
#
#
# Copyright (c) 2014 Agostino Ruscito <ruscito@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
from pycomm_micro.cip.cip_base import *
from pycomm_micro.common import setup_logger
import re
import logging
import math
def parse_tag(tag):
t = re.search(r"(?P<file_type>[CT])(?P<file_number>\d{1,3})"
r"(:)(?P<element_number>\d{1,3})"
r"(.)(?P<sub_element>ACC|PRE|EN|DN|TT|CU|CD|DN|OV|UN|UA)", tag, flags=re.IGNORECASE)
if t:
if (1 <= int(t.group('file_number')) <= 255) \
and (0 <= int(t.group('element_number')) <= 255):
return True, t.group(0), {'file_type': t.group('file_type').upper(),
'file_number': t.group('file_number'),
'element_number': t.group('element_number'),
'sub_element': PCCC_CT[t.group('sub_element').upper()],
'read_func': '\xa2',
'write_func': '\xab',
'address_field': 3}
t = re.search(r"(?P<file_type>[FBN])(?P<file_number>\d{1,3})"
r"(:)(?P<element_number>\d{1,3})"
r"(/(?P<sub_element>\d{1,2}))?",
tag, flags=re.IGNORECASE)
if t:
if t.group('sub_element') is not None:
if (1 <= int(t.group('file_number')) <= 255) \
and (0 <= int(t.group('element_number')) <= 255) \
and (0 <= int(t.group('sub_element')) <= 15):
return True, t.group(0), {'file_type': t.group('file_type').upper(),
'file_number': t.group('file_number'),
'element_number': t.group('element_number'),
'sub_element': t.group('sub_element'),
'read_func': '\xa2',
'write_func': '\xab',
'address_field': 3}
else:
if (1 <= int(t.group('file_number')) <= 255) \
and (0 <= int(t.group('element_number')) <= 255):
return True, t.group(0), {'file_type': t.group('file_type').upper(),
'file_number': t.group('file_number'),
'element_number': t.group('element_number'),
'sub_element': t.group('sub_element'),
'read_func': '\xa2',
'write_func': '\xab',
'address_field': 2}
t = re.search(r"(?P<file_type>[IO])(:)(?P<file_number>\d{1,3})"
r"(.)(?P<element_number>\d{1,3})"
r"(/(?P<sub_element>\d{1,2}))?", tag, flags=re.IGNORECASE)
if t:
if t.group('sub_element') is not None:
if (0 <= int(t.group('file_number')) <= 255) \
and (0 <= int(t.group('element_number')) <= 255) \
and (0 <= int(t.group('sub_element')) <= 15):
return True, t.group(0), {'file_type': t.group('file_type').upper(),
'file_number': t.group('file_number'),
'element_number': t.group('element_number'),
'sub_element': t.group('sub_element'),
'read_func': '\xa2',
'write_func': '\xab',
'address_field': 3}
else:
if (0 <= int(t.group('file_number')) <= 255) \
and (0 <= int(t.group('element_number')) <= 255):
return True, t.group(0), {'file_type': t.group('file_type').upper(),
'file_number': t.group('file_number'),
'element_number': t.group('element_number'),
'read_func': '\xa2',
'write_func': '\xab',
'address_field': 2}
t = re.search(r"(?P<file_type>S)"
r"(:)(?P<element_number>\d{1,3})"
r"(/(?P<sub_element>\d{1,2}))?", tag, flags=re.IGNORECASE)
if t:
if t.group('sub_element') is not None:
if (0 <= int(t.group('element_number')) <= 255) \
and (0 <= int(t.group('sub_element')) <= 15):
return True, t.group(0), {'file_type': t.group('file_type').upper(),
'file_number': '2',
'element_number': t.group('element_number'),
'sub_element': t.group('sub_element'),
'read_func': '\xa2',
'write_func': '\xab',
'address_field': 3}
else:
if 0 <= int(t.group('element_number')) <= 255:
return True, t.group(0), {'file_type': t.group('file_type').upper(),
'file_number': '2',
'element_number': t.group('element_number'),
'read_func': '\xa2',
'write_func': '\xab',
'address_field': 2}
t = re.search(r"(?P<file_type>B)(?P<file_number>\d{1,3})"
r"(/)(?P<element_number>\d{1,4})",
tag, flags=re.IGNORECASE)
if t:
if (1 <= int(t.group('file_number')) <= 255) \
and (0 <= int(t.group('element_number')) <= 4095):
bit_position = int(t.group('element_number'))
element_number = bit_position / 16
sub_element = bit_position - (element_number * 16)
return True, t.group(0), {'file_type': t.group('file_type').upper(),
'file_number': t.group('file_number'),
'element_number': element_number,
'sub_element': sub_element,
'read_func': '\xa2',
'write_func': '\xab',
'address_field': 3}
return False, tag
class Driver(Base):
"""
SLC/PLC_5 Implementation
"""
def __init__(self, debug=False, filename=None):
if debug:
super(Driver, self).__init__(setup_logger('ab_comm.slc', logging.DEBUG, filename))
else:
super(Driver, self).__init__(setup_logger('ab_comm.slc', logging.INFO, filename))
self.__version__ = '0.1'
self._last_sequence = 0
def _check_reply(self):
"""
check the replayed message for error
"""
self._more_packets_available = False
try:
if self._reply is None:
self._status = (3, '%s without reply' % REPLAY_INFO[unpack_dint(self._message[:2])])
return False
# Get the type of command
typ = unpack_uint(self._reply[:2])
# Encapsulation status check
if unpack_dint(self._reply[8:12]) != SUCCESS:
self._status = (3, "{0} reply status:{1}".format(REPLAY_INFO[typ],
SERVICE_STATUS[unpack_dint(self._reply[8:12])]))
return False
# Command Specific Status check
if typ == unpack_uint(ENCAPSULATION_COMMAND["send_rr_data"]):
status = unpack_usint(self._reply[42:43])
if status != SUCCESS:
self._status = (3, "send_rr_data reply:{0} - Extend status:{1}".format(
SERVICE_STATUS[status], get_extended_status(self._reply, 42)))
return False
else:
return True
elif typ == unpack_uint(ENCAPSULATION_COMMAND["send_unit_data"]):
status = unpack_usint(self._reply[48:49])
if unpack_usint(self._reply[46:47]) == I_TAG_SERVICES_REPLY["Read Tag Fragmented"]:
self._parse_fragment(50, status)
return True
if unpack_usint(self._reply[46:47]) == I_TAG_SERVICES_REPLY["Get Instance Attributes List"]:
self._parse_tag_list(50, status)
return True
if status == 0x06:
self._status = (3, "Insufficient Packet Space")
self._more_packets_available = True
elif status != SUCCESS:
self._status = (3, "send_unit_data reply:{0} - Extend status:{1}".format(
SERVICE_STATUS[status], get_extended_status(self._reply, 48)))
return False
else:
return True
return True
except Exception as e:
raise DataError(e)
def read_tag(self, tag, n=1):
""" read tag from a connected plc
Possible combination can be passed to this method:
print c.read_tag('F8:0', 3) return a list of 3 registers starting from F8:0
print c.read_tag('F8:0') return one value
It is possible to read status bit
:return: None is returned in case of error
"""
res = parse_tag(tag)
if not res[0]:
self._status = (1000, "Error parsing the tag passed to read_tag({0},{1})".format(tag, n))
self.logger.warning(self._status)
raise DataError("Error parsing the tag passed to read_tag({0},{1})".format(tag, n))
bit_read = False
bit_position = 0
sub_element = 0
if int(res[2]['address_field'] == 3):
bit_read = True
bit_position = int(res[2]['sub_element'])
if not self._target_is_connected:
if not self.forward_open():
self._status = (5, "Target did not connected. read_tag will not be executed.")
self.logger.warning(self._status)
raise Error("Target did not connected. read_tag will not be executed.")
data_size = PCCC_DATA_SIZE[res[2]['file_type']]
# Creating the Message Request Packet
self._last_sequence = pack_uint(Base._get_sequence())
message_request = [
self._last_sequence,
'\x4b',
'\x02',
CLASS_ID["8-bit"],
PATH["PCCC"],
'\x07',
self.attribs['vid'],
self.attribs['vsn'],
'\x0f',
'\x00',
self._last_sequence[1],
self._last_sequence[0],
res[2]['read_func'],
pack_usint(data_size * n),
pack_usint(int(res[2]['file_number'])),
PCCC_DATA_TYPE[res[2]['file_type']],
pack_usint(int(res[2]['element_number'])),
pack_usint(sub_element)
]
self.logger.debug("SLC read_tag({0},{1})".format(tag, n))
if self.send_unit_data(
build_common_packet_format(
DATA_ITEM['Connected'],
''.join(message_request),
ADDRESS_ITEM['Connection Based'],
addr_data=self._target_cid,)):
sts = int(unpack_usint(self._reply[58]))
try:
if sts != 0:
sts_txt = PCCC_ERROR_CODE[sts]
self._status = (1000, "Error({0}) returned from read_tag({1},{2})".format(sts_txt, tag, n))
self.logger.warning(self._status)
raise DataError("Error({0}) returned from read_tag({1},{2})".format(sts_txt, tag, n))
new_value = 61
if bit_read:
if res[2]['file_type'] == 'T' or res[2]['file_type'] == 'C':
if bit_position == PCCC_CT['PRE']:
return UNPACK_PCCC_DATA_FUNCTION[res[2]['file_type']](
self._reply[new_value+2:new_value+2+data_size])
elif bit_position == PCCC_CT['ACC']:
return UNPACK_PCCC_DATA_FUNCTION[res[2]['file_type']](
self._reply[new_value+4:new_value+4+data_size])
tag_value = UNPACK_PCCC_DATA_FUNCTION[res[2]['file_type']](
self._reply[new_value:new_value+data_size])
return get_bit(tag_value, bit_position)
else:
values_list = []
while len(self._reply[new_value:]) >= data_size:
values_list.append(
UNPACK_PCCC_DATA_FUNCTION[res[2]['file_type']](self._reply[new_value:new_value+data_size])
)
new_value = new_value+data_size
if len(values_list) > 1:
return values_list
else:
return values_list[0]
except Exception as e:
self._status = (1000, "Error({0}) parsing the data returned from read_tag({1},{2})".format(e, tag, n))
self.logger.warning(self._status)
raise DataError("Error({0}) parsing the data returned from read_tag({1},{2})".format(e, tag, n))
else:
raise DataError("send_unit_data returned not valid data")
def write_tag(self, tag, value):
""" write tag from a connected plc
Possible combination can be passed to this method:
c.write_tag('N7:0', [-30, 32767, -32767])
c.write_tag('N7:0', 21)
c.read_tag('N7:0', 10)
It is not possible to write status bit
:return: None is returned in case of error
"""
res = parse_tag(tag)
if not res[0]:
self._status = (1000, "Error parsing the tag passed to read_tag({0},{1})".format(tag, value))
self.logger.warning(self._status)
raise DataError("Error parsing the tag passed to read_tag({0},{1})".format(tag, value))
if isinstance(value, list) and int(res[2]['address_field'] == 3):
self._status = (1000, "Function's parameters error. read_tag({0},{1})".format(tag, value))
self.logger.warning(self._status)
raise DataError("Function's parameters error. read_tag({0},{1})".format(tag, value))
if isinstance(value, list) and int(res[2]['address_field'] == 3):
self._status = (1000, "Function's parameters error. read_tag({0},{1})".format(tag, value))
self.logger.warning(self._status)
raise DataError("Function's parameters error. read_tag({0},{1})".format(tag, value))
bit_field = False
bit_position = 0
sub_element = 0
if int(res[2]['address_field'] == 3):
bit_field = True
bit_position = int(res[2]['sub_element'])
values_list = ''
else:
values_list = '\xff\xff'
multi_requests = False
if isinstance(value, list):
multi_requests = True
if not self._target_is_connected:
if not self.forward_open():
self._status = (1000, "Target did not connected. write_tag will not be executed.")
self.logger.warning(self._status)
raise Error("Target did not connected. write_tag will not be executed.")
try:
n = 0
if multi_requests:
data_size = PCCC_DATA_SIZE[res[2]['file_type']]
for v in value:
values_list += PACK_PCCC_DATA_FUNCTION[res[2]['file_type']](v)
n += 1
else:
n = 1
if bit_field:
data_size = 2
if (res[2]['file_type'] == 'T' or res[2]['file_type'] == 'C') \
and (bit_position == PCCC_CT['PRE'] or bit_position == PCCC_CT['ACC']):
sub_element = bit_position
values_list = '\xff\xff' + PACK_PCCC_DATA_FUNCTION[res[2]['file_type']](value)
else:
sub_element = 0
if value > 0:
values_list = pack_uint(math.pow(2, bit_position)) + pack_uint(math.pow(2, bit_position))
else:
values_list = pack_uint(math.pow(2, bit_position)) + pack_uint(0)
else:
values_list += PACK_PCCC_DATA_FUNCTION[res[2]['file_type']](value)
data_size = PCCC_DATA_SIZE[res[2]['file_type']]
except Exception as e:
self._status = (1000, "Error({0}) packing the values to write to the"
"SLC write_tag({1},{2})".format(e, tag, value))
self.logger.warning(self._status)
raise DataError("Error({0}) packing the values to write to the "
"SLC write_tag({1},{2})".format(e, tag, value))
data_to_write = values_list
# Creating the Message Request Packet
self._last_sequence = pack_uint(Base._get_sequence())
message_request = [
self._last_sequence,
'\x4b',
'\x02',
CLASS_ID["8-bit"],
PATH["PCCC"],
'\x07',
self.attribs['vid'],
self.attribs['vsn'],
'\x0f',
'\x00',
self._last_sequence[1],
self._last_sequence[0],
res[2]['write_func'],
pack_usint(data_size * n),
pack_usint(int(res[2]['file_number'])),
PCCC_DATA_TYPE[res[2]['file_type']],
pack_usint(int(res[2]['element_number'])),
pack_usint(sub_element)
]
self.logger.debug("SLC write_tag({0},{1})".format(tag, value))
if self.send_unit_data(
build_common_packet_format(
DATA_ITEM['Connected'],
''.join(message_request) + data_to_write,
ADDRESS_ITEM['Connection Based'],
addr_data=self._target_cid,)):
sts = int(unpack_usint(self._reply[58]))
try:
if sts != 0:
sts_txt = PCCC_ERROR_CODE[sts]
self._status = (1000, "Error({0}) returned from SLC write_tag({1},{2})".format(sts_txt, tag, value))
self.logger.warning(self._status)
raise DataError("Error({0}) returned from SLC write_tag({1},{2})".format(sts_txt, tag, value))
return True
except Exception as e:
self._status = (1000, "Error({0}) parsing the data returned from "
"SLC write_tag({1},{2})".format(e, tag, value))
self.logger.warning(self._status)
raise DataError("Error({0}) parsing the data returned from "
"SLC write_tag({1},{2})".format(e, tag, value))
else:
raise DataError("send_unit_data returned not valid data")

View File

@@ -0,0 +1 @@
__author__ = 'agostino'

View File

@@ -0,0 +1,827 @@
# -*- coding: utf-8 -*-
#
# cip_base.py - A set of classes methods and structures used to implement Ethernet/IP
#
#
# Copyright (c) 2014 Agostino Ruscito <ruscito@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
import struct
import socket
from os import getpid
from pycomm_micro.cip.cip_const import *
from pycomm_micro.common import PycommError
class CommError(PycommError):
pass
class DataError(PycommError):
pass
def pack_sint(n):
return struct.pack('b', n)
def pack_usint(n):
return struct.pack('B', n)
def pack_int(n):
"""pack 16 bit into 2 bytes little endian"""
return struct.pack('<h', n)
def pack_uint(n):
"""pack 16 bit into 2 bytes little endian"""
# print("N: {0}".format(n))
return struct.pack('<H', n)
def pack_dint(n):
"""pack 32 bit into 4 bytes little endian"""
return struct.pack('<i', n)
def pack_real(r):
"""unpack 4 bytes little endian to int"""
return struct.pack('<f', r)
def pack_lint(l):
"""unpack 4 bytes little endian to int"""
return struct.unpack('<q', l)
def unpack_bool(st):
if int(struct.unpack('B', st[0])[0]) == 0:
return 0
return 1
def unpack_sint(st):
return int(struct.unpack('b', st[0])[0])
def unpack_usint(st):
return int(struct.unpack('B', st[0])[0])
def unpack_int(st):
"""unpack 2 bytes little endian to int"""
return int(struct.unpack('<h', st[0:2])[0])
def unpack_uint(st):
"""unpack 2 bytes little endian to int"""
return int(struct.unpack('<H', st[0:2])[0])
def unpack_dint(st):
"""unpack 4 bytes little endian to int"""
return int(struct.unpack('<i', st[0:4])[0])
def unpack_real(st):
"""unpack 4 bytes little endian to int"""
return float(struct.unpack('<f', st[0:4])[0])
def unpack_lreal(st):
"""unpack 8 bytes little endian to int"""
return float(struct.unpack('<f', st[0:8])[0])
def unpack_lint(st):
"""unpack 4 bytes little endian to int"""
return int(struct.unpack('<q', st[0:8])[0])
def get_bit(value, idx):
""":returns value of bit at position idx"""
return (value & (1 << idx)) != 0
PACK_DATA_FUNCTION = {
'BOOL': pack_sint,
'SINT': pack_sint, # Signed 8-bit integer
'INT': pack_int, # Signed 16-bit integer
'UINT': pack_uint, # Unsigned 16-bit integer
'USINT': pack_usint, # Unsigned 8-bit integer
'DINT': pack_dint, # Signed 32-bit integer
'REAL': pack_real, # 32-bit floating point
'LREAL': pack_real, # 32-bit floating point
'LINT': pack_lint,
'BYTE': pack_sint, # byte string 8-bits
'WORD': pack_uint, # byte string 16-bits
'DWORD': pack_dint, # byte string 32-bits
'LWORD': pack_lint # byte string 64-bits
}
UNPACK_DATA_FUNCTION = {
'BOOL': unpack_bool,
'SINT': unpack_sint, # Signed 8-bit integer
'INT': unpack_int, # Signed 16-bit integer
'UINT': unpack_uint, # Unsigned 16-bit
'USINT': unpack_usint, # Unsigned 8-bit integer
'DINT': unpack_dint, # Signed 32-bit integer
'UDINT': unpack_dint, # Signed 32-bit integer
'REAL': unpack_real, # 32-bit floating point,
'LREAL': unpack_lreal, # 32-bit floating point,
'LINT': unpack_lint,
'BYTE': unpack_sint, # byte string 8-bits
'WORD': unpack_uint, # byte string 16-bits
'DWORD': unpack_dint, # byte string 32-bits
'LWORD': unpack_lint # byte string 64-bits
}
DATA_FUNCTION_SIZE = {
'BOOL': 1,
'SINT': 1, # Signed 8-bit integer
'INT': 2, # Signed 16-bit integer
'UINT': 2, # Unsigned 16-bit integer
'DINT': 4, # Signed 32-bit integer
'REAL': 4, # 32-bit floating point
'LINT': 8,
'BYTE': 1, # byte string 8-bits
'WORD': 2, # byte string 16-bits
'DWORD': 4, # byte string 32-bits
'LWORD': 8 # byte string 64-bits
}
UNPACK_PCCC_DATA_FUNCTION = {
'N': unpack_int,
'B': unpack_int,
'T': unpack_int,
'C': unpack_int,
'S': unpack_int,
'F': unpack_real,
'A': unpack_sint,
'R': unpack_dint,
'O': unpack_int,
'I': unpack_int
}
PACK_PCCC_DATA_FUNCTION = {
'N': pack_int,
'B': pack_int,
'T': pack_int,
'C': pack_int,
'S': pack_int,
'F': pack_real,
'A': pack_sint,
'R': pack_dint,
'O': pack_int,
'I': pack_int
}
def print_bytes_line(msg):
out = ''
for ch in msg:
out += "{:0>2x}".format(ord(ch))
return out
def print_bytes_msg(msg, info=''):
out = info
new_line = True
line = 0
column = 0
for idx, ch in enumerate(msg):
if new_line:
out += "\n({:0>4d}) ".format(line * 10)
new_line = False
out += "{:0>2x} ".format(ord(ch))
if column == 9:
new_line = True
column = 0
line += 1
else:
column += 1
return out
def get_extended_status(msg, start):
status = unpack_usint(msg[start:start+1])
# send_rr_data
# 42 General Status
# 43 Size of additional status
# 44..n additional status
# send_unit_data
# 48 General Status
# 49 Size of additional status
# 50..n additional status
extended_status_size = (unpack_usint(msg[start+1:start+2]))*2
extended_status = 0
if extended_status_size != 0:
# There is an additional status
if extended_status_size == 1:
extended_status = unpack_usint(msg[start+2:start+3])
elif extended_status_size == 2:
extended_status = unpack_uint(msg[start+2:start+4])
elif extended_status_size == 4:
extended_status = unpack_dint(msg[start+2:start+6])
else:
return 'Extended Status Size Unknown'
try:
return '{0}'.format(EXTEND_CODES[status][extended_status])
except LookupError:
return "Extended Status info not present"
def create_tag_rp(tag, multi_requests=False):
""" Create tag Request Packet
It returns the request packed wrapped around the tag passed.
If any error it returns none
"""
tags = tag.split('.')
rp = []
index = []
for tag in tags:
add_index = False
# Check if is an array tag
if tag.find('[') != -1:
# Remove the last square bracket
tag = tag[:len(tag)-1]
# Isolate the value inside bracket
inside_value = tag[tag.find('[')+1:]
# Now split the inside value in case part of multidimensional array
index = inside_value.split(',')
# Flag the existence of one o more index
add_index = True
# Get only the tag part
tag = tag[:tag.find('[')]
tag_length = len(tag)
# Create the request path
rp.append(EXTENDED_SYMBOL) # ANSI Ext. symbolic segment
rp.append(chr(tag_length)) # Length of the tag
# Add the tag to the Request path
for char in tag:
rp.append(char)
# Add pad byte because total length of Request path must be word-aligned
if tag_length % 2:
rp.append(PADDING_BYTE)
# Add any index
if add_index:
for idx in index:
val = int(idx)
if val <= 0xff:
rp.append(ELEMENT_ID["8-bit"])
rp.append(pack_usint(val))
elif val <= 0xffff:
rp.append(ELEMENT_ID["16-bit"]+PADDING_BYTE)
rp.append(pack_uint(val))
elif val <= 0xfffffffff:
rp.append(ELEMENT_ID["32-bit"]+PADDING_BYTE)
rp.append(pack_dint(val))
else:
# Cannot create a valid request packet
return None
# At this point the Request Path is completed,
if multi_requests:
request_path = chr(len(rp)/2) + ''.join(rp)
else:
request_path = ''.join(rp)
return request_path
def build_common_packet_format(message_type, message, addr_type, addr_data=None, timeout=10):
""" build_common_packet_format
It creates the common part for a CIP message. Check Volume 2 (page 2.22) of CIP specification for reference
"""
msg = pack_dint(0) # Interface Handle: shall be 0 for CIP
msg += pack_uint(timeout) # timeout
msg += pack_uint(2) # Item count: should be at list 2 (Address and Data)
msg += addr_type # Address Item Type ID
if addr_data is not None:
msg += pack_uint(len(addr_data)) # Address Item Length
msg += addr_data
else:
msg += pack_uint(0) # Address Item Length
msg += message_type # Data Type ID
msg += pack_uint(len(message)) # Data Item Length
msg += message
return msg
def build_multiple_service(rp_list, sequence=None):
mr = []
if sequence is not None:
mr.append(pack_uint(sequence))
mr.append(chr(TAG_SERVICES_REQUEST["Multiple Service Packet"])) # the Request Service
mr.append(pack_usint(2)) # the Request Path Size length in word
mr.append(CLASS_ID["8-bit"])
mr.append(CLASS_CODE["Message Router"])
mr.append(INSTANCE_ID["8-bit"])
mr.append(pack_usint(1)) # Instance 1
mr.append(pack_uint(len(rp_list))) # Number of service contained in the request
# Offset calculation
offset = (len(rp_list) * 2) + 2
for index, rp in enumerate(rp_list):
if index == 0:
mr.append(pack_uint(offset)) # Starting offset
else:
mr.append(pack_uint(offset))
offset += len(rp)
for rp in rp_list:
mr.append(rp)
return mr
def parse_multiple_request(message, tags, typ):
""" parse_multi_request
This function should be used to parse the message replayed to a multi request service rapped around the
send_unit_data message.
:param message: the full message returned from the PLC
:param tags: The list of tags to be read
:param typ: to specify if multi request service READ or WRITE
:return: a list of tuple in the format [ (tag name, value, data type), ( tag name, value, data type) ].
In case of error the tuple will be (tag name, None, None)
"""
offset = 50
position = 50
number_of_service_replies = unpack_uint(message[offset:offset+2])
tag_list = []
for index in range(number_of_service_replies):
position += 2
start = offset + unpack_uint(message[position:position+2])
general_status = unpack_usint(message[start+2:start+3])
if general_status == 0:
if typ == "READ":
data_type = unpack_uint(message[start+4:start+6])
try:
value_begin = start + 6
value_end = value_begin + DATA_FUNCTION_SIZE[I_DATA_TYPE[data_type]]
value = message[value_begin:value_end]
tag_list.append((tags[index],
UNPACK_DATA_FUNCTION[I_DATA_TYPE[data_type]](value),
I_DATA_TYPE[data_type]))
except LookupError:
tag_list.append((tags[index], None, None))
else:
tag_list.append((tags[index] + ('GOOD',)))
else:
if typ == "READ":
tag_list.append((tags[index], None, None))
else:
tag_list.append((tags[index] + ('BAD',)))
return tag_list
class Socket:
def __init__(self, timeout=5.0):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(timeout)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
def connect(self, host, port):
try:
self.sock.connect((host, port))
except socket.timeout:
raise CommError("Socket timeout during connection.")
def send(self, msg, timeout=0):
if timeout != 0:
self.sock.settimeout(timeout)
total_sent = 0
while total_sent < len(msg):
try:
sent = self.sock.send(msg[total_sent:])
if sent == 0:
raise CommError("socket connection broken.")
total_sent += sent
except socket.error:
raise CommError("socket connection broken.")
return total_sent
def receive(self, timeout=0):
if timeout != 0:
self.sock.settimeout(timeout)
msg_len = 28
chunks = []
bytes_recd = 0
one_shot = True
while bytes_recd < msg_len:
try:
chunk = self.sock.recv(min(msg_len - bytes_recd, 2048))
if chunk == '':
raise CommError("socket connection broken.")
if one_shot:
data_size = int(struct.unpack('<H', chunk[2:4])[0]) # Length
msg_len = HEADER_SIZE + data_size
one_shot = False
chunks.append(chunk)
bytes_recd += len(chunk)
except socket.error as e:
raise CommError(e)
return ''.join(chunks)
def close(self):
self.sock.close()
def parse_symbol_type(symbol):
""" parse_symbol_type
It parse the symbol to Rockwell Spec
:param symbol: the symbol associated to a tag
:return: A tuple containing information about the tag
"""
pass
return None
class Base(object):
_sequence = 0
def __init__(self, logging):
if Base._sequence == 0:
Base._sequence = getpid()
else:
Base._sequence = Base._get_sequence()
self.logger = logging
self.__version__ = '0.1'
self.__sock = None
self._session = 0
self._connection_opened = False
self._reply = None
self._message = None
self._target_cid = None
self._target_is_connected = False
self._tag_list = []
self._buffer = {}
self._device_description = "Device Unknown"
self._last_instance = 0
self._byte_offset = 0
self._last_position = 0
self._more_packets_available = False
self._last_tag_read = ()
self._last_tag_write = ()
self._status = (0, "")
# self.attribs = {'context': '_pycomm_', 'protocol version': 1, 'rpi': 5000, 'port': 0xAF12, 'timeout': 10,
# 'backplane': 1, 'cpu slot': 0, 'option': 0, 'cid': '\x27\x04\x19\x71', 'csn': '\x27\x04',
# 'vid': '\x09\x10', 'vsn': '\x09\x10\x19\x71', 'name': 'Base', 'ip address': None}
self.attribs = {'context': '_pycomm_', 'protocol version': 1, 'rpi': 5000, 'port': 0xAF12, 'timeout': 10,
'backplane': 0, 'cpu slot': 0, 'option': 0, 'cid': '\x27\x04\x19\x71', 'csn': '\x27\x04',
'vid': '\x09\x10', 'vsn': '\x09\x10\x19\x71', 'name': 'Base', 'ip address': None}
def __len__(self):
return len(self.attribs)
def __getitem__(self, key):
return self.attribs[key]
def __setitem__(self, key, value):
self.attribs[key] = value
def __delitem__(self, key):
try:
del self.attribs[key]
except LookupError:
pass
def __iter__(self):
return iter(self.attribs)
def __contains__(self, item):
return item in self.attribs
def _check_reply(self):
raise Socket.ImplementationError("The method has not been implemented")
@staticmethod
def _get_sequence():
""" Increase and return the sequence used with connected messages
:return: The New sequence
"""
if Base._sequence < 65535:
Base._sequence += 1
else:
Base._sequence = getpid()
return Base._sequence
def nop(self):
""" No replay command
A NOP provides a way for either an originator or target to determine if the TCP connection is still open.
"""
self._message = self.build_header(ENCAPSULATION_COMMAND['nop'], 0)
self._send()
def __repr__(self):
return self._device_description
def description(self):
return self._device_description
def list_identity(self):
""" ListIdentity command to locate and identify potential target
return true if the replay contains the device description
"""
self._message = self.build_header(ENCAPSULATION_COMMAND['list_identity'], 0)
self._send()
self._receive()
if self._check_reply():
try:
self._device_description = self._reply[63:-1]
return True
except Exception as e:
raise CommError(e)
return False
def send_rr_data(self, msg):
""" SendRRData transfer an encapsulated request/reply packet between the originator and target
:param msg: The message to be send to the target
:return: the replay received from the target
"""
self._message = self.build_header(ENCAPSULATION_COMMAND["send_rr_data"], len(msg))
self._message += msg
self._send()
self._receive()
return self._check_reply()
def send_unit_data(self, msg):
""" SendUnitData send encapsulated connected messages.
:param msg: The message to be send to the target
:return: the replay received from the target
"""
self._message = self.build_header(ENCAPSULATION_COMMAND["send_unit_data"], len(msg))
self._message += msg
self._send()
self._receive()
return self._check_reply()
def get_status(self):
""" Get the last status/error
This method can be used after any call to get any details in case of error
:return: A tuple containing (error group, error message)
"""
return self._status
def clear(self):
""" Clear the last status/error
:return: return am empty tuple
"""
self._status = (0, "")
def build_header(self, command, length):
""" Build the encapsulate message header
The header is 24 bytes fixed length, and includes the command and the length of the optional data portion.
:return: the headre
"""
try:
h = command # Command UINT
h += pack_uint(length) # Length UINT
h += pack_dint(self._session) # Session Handle UDINT
h += pack_dint(0) # Status UDINT
h += self.attribs['context'] # Sender Context 8 bytes
h += pack_dint(self.attribs['option']) # Option UDINT
return h
except Exception as e:
raise CommError(e)
def register_session(self):
""" Register a new session with the communication partner
:return: None if any error, otherwise return the session number
"""
if self._session:
return self._session
self._session = 0
self._message = self.build_header(ENCAPSULATION_COMMAND['register_session'], 4)
self._message += pack_uint(self.attribs['protocol version'])
self._message += pack_uint(0)
self._send()
self._receive()
if self._check_reply():
self._session = unpack_dint(self._reply[4:8])
self.logger.debug("Session ={0} has been registered.".format(print_bytes_line(self._reply[4:8])))
return self._session
self._status = 'Warning ! the session has not been registered.'
self.logger.warning(self._status)
return None
def forward_open(self):
""" CIP implementation of the forward open message
Refer to ODVA documentation Volume 1 3-5.5.2
:return: False if any error in the replayed message
"""
if self._session == 0:
self._status = (4, "A session need to be registered before to call forward_open.")
raise CommError("A session need to be registered before to call forward open")
forward_open_msg = [
FORWARD_OPEN,
pack_usint(2),
CLASS_ID["8-bit"],
CLASS_CODE["Connection Manager"], # Volume 1: 5-1
INSTANCE_ID["8-bit"],
CONNECTION_MANAGER_INSTANCE['Open Request'],
PRIORITY,
TIMEOUT_TICKS,
pack_dint(0),
self.attribs['cid'],
self.attribs['csn'],
self.attribs['vid'],
self.attribs['vsn'],
TIMEOUT_MULTIPLIER,
'\x00\x00\x00',
pack_dint(self.attribs['rpi'] * 1000),
pack_uint(CONNECTION_PARAMETER['Default']),
pack_dint(self.attribs['rpi'] * 1000),
pack_uint(CONNECTION_PARAMETER['Default']),
TRANSPORT_CLASS, # Transport Class
# CONNECTION_SIZE['Backplane'],
CONNECTION_SIZE['Direct Network'],
# pack_usint(self.attribs['backplane']),
# pack_usint(self.attribs['cpu slot']),
CLASS_ID["8-bit"],
CLASS_CODE["Message Router"],
INSTANCE_ID["8-bit"],
pack_usint(1)
]
if self.send_rr_data(
build_common_packet_format(DATA_ITEM['Unconnected'], ''.join(forward_open_msg), ADDRESS_ITEM['UCMM'],)):
self._target_cid = self._reply[44:48]
self._target_is_connected = True
return True
self._status = (4, "forward_open returned False")
return False
def forward_close(self):
""" CIP implementation of the forward close message
Each connection opened with the froward open message need to be closed.
Refer to ODVA documentation Volume 1 3-5.5.3
:return: False if any error in the replayed message
"""
if self._session == 0:
self._status = (5, "A session need to be registered before to call forward_close.")
raise CommError("A session need to be registered before to call forward_close.")
# print ("Backplane:{0}\nCPU:{1}".format(self.attribs['backplane'], self.attribs['cpu slot']))
forward_close_msg = [
FORWARD_CLOSE,
pack_usint(2),
CLASS_ID["8-bit"],
CLASS_CODE["Connection Manager"], # Volume 1: 5-1
INSTANCE_ID["8-bit"],
CONNECTION_MANAGER_INSTANCE['Open Request'],
PRIORITY,
TIMEOUT_TICKS,
self.attribs['csn'],
self.attribs['vid'],
self.attribs['vsn'],
CONNECTION_SIZE['Direct Network'],
# CONNECTION_SIZE['Backplane'],
'\x00', # Reserved
# pack_usint(self.attribs['backplane']),
# pack_usint(self.attribs['cpu slot']),
CLASS_ID["8-bit"],
CLASS_CODE["Message Router"],
INSTANCE_ID["8-bit"],
pack_usint(1)
]
if self.send_rr_data(
build_common_packet_format(DATA_ITEM['Unconnected'], ''.join(forward_close_msg), ADDRESS_ITEM['UCMM'])):
self._target_is_connected = False
return True
self._status = (5, "forward_close returned False")
self.logger.warning(self._status)
return False
def un_register_session(self):
""" Un-register a connection
"""
self._message = self.build_header(ENCAPSULATION_COMMAND['unregister_session'], 0)
self._send()
self._session = None
def _send(self):
"""
socket send
:return: true if no error otherwise false
"""
try:
self.logger.debug(print_bytes_msg(self._message, '-------------- SEND --------------'))
self.__sock.send(self._message)
except Exception as e:
#self.clean_up()
raise CommError(e)
def _receive(self):
"""
socket receive
:return: true if no error otherwise false
"""
try:
self._reply = self.__sock.receive()
self.logger.debug(print_bytes_msg(self._reply, '----------- RECEIVE -----------'))
except Exception as e:
#self.clean_up()
raise CommError(e)
def open(self, ip_address):
"""
socket open
:return: true if no error otherwise false
"""
# handle the socket layer
if not self._connection_opened:
try:
if self.__sock is None:
self.__sock = Socket()
self.__sock.connect(ip_address, self.attribs['port'])
self._connection_opened = True
self.attribs['ip address'] = ip_address
if self.register_session() is None:
self._status = (13, "Session not registered")
return False
self.forward_close()
return True
except Exception as e:
#self.clean_up()
raise CommError(e)
def close(self):
"""
socket close
:return: true if no error otherwise false
"""
try:
if self._target_is_connected:
self.forward_close()
if self._session != 0:
self.un_register_session()
if self.__sock:
self.__sock.close()
except Exception as e:
raise CommError(e)
self.clean_up()
def clean_up(self):
self.__sock = None
self._target_is_connected = False
self._session = 0
self._connection_opened = False
def is_connected(self):
return self._connection_opened

View File

@@ -0,0 +1,482 @@
# -*- coding: utf-8 -*-
#
# cip_const.py - A set of structures and constants used to implement the Ethernet/IP protocol
#
#
# Copyright (c) 2014 Agostino Ruscito <ruscito@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
ELEMENT_ID = {
"8-bit": '\x28',
"16-bit": '\x29',
"32-bit": '\x2a'
}
CLASS_ID = {
"8-bit": '\x20',
"16-bit": '\x21',
}
INSTANCE_ID = {
"8-bit": '\x24',
"16-bit": '\x25'
}
ATTRIBUTE_ID = {
"8-bit": '\x30',
"16-bit": '\x31'
}
# Path are combined as:
# CLASS_ID + PATHS
# For example PCCC path is CLASS_ID["8-bit"]+PATH["PCCC"] -> 0x20, 0x67, 0x24, 0x01.
PATH = {
'Connection Manager': '\x06\x24\x01',
'Router': '\x02\x24\x01',
'Backplane Data Type': '\x66\x24\x01',
'PCCC': '\x67\x24\x01',
'DHCP Channel A': '\xa6\x24\x01\x01\x2c\x01',
'DHCP Channel B': '\xa6\x24\x01\x02\x2c\x01'
}
ENCAPSULATION_COMMAND = { # Volume 2: 2-3.2 Command Field UINT 2 byte
"nop": '\x00\x00',
"list_targets": '\x01\x00',
"list_services": '\x04\x00',
"list_identity": '\x63\x00',
"list_interfaces": '\x64\x00',
"register_session": '\x65\x00',
"unregister_session": '\x66\x00',
"send_rr_data": '\x6F\x00',
"send_unit_data": '\x70\x00'
}
"""
When a tag is created, an instance of the Symbol Object (Class ID 0x6B) is created
inside the controller.
When a UDT is created, an instance of the Template object (Class ID 0x6C) is
created to hold information about the structure makeup.
"""
CLASS_CODE = {
"Message Router": '\x02', # Volume 1: 5-1
"Symbol Object": '\x6b',
"Template Object": '\x6c',
"Connection Manager": '\x06' # Volume 1: 3-5
}
CONNECTION_MANAGER_INSTANCE = {
'Open Request': '\x01',
'Open Format Rejected': '\x02',
'Open Resource Rejected': '\x03',
'Open Other Rejected': '\x04',
'Close Request': '\x05',
'Close Format Request': '\x06',
'Close Other Request': '\x07',
'Connection Timeout': '\x08'
}
TAG_SERVICES_REQUEST = {
"Read Tag": 0x4c,
"Read Tag Fragmented": 0x52,
"Write Tag": 0x4d,
"Write Tag Fragmented": 0x53,
"Read Modify Write Tag": 0x4e,
"Multiple Service Packet": 0x0a,
"Get Instance Attributes List": 0x55,
"Get Attributes": 0x03,
"Read Template": 0x4c,
}
TAG_SERVICES_REPLY = {
0xcc: "Read Tag",
0xd2: "Read Tag Fragmented",
0xcd: "Write Tag",
0xd3: "Write Tag Fragmented",
0xce: "Read Modify Write Tag",
0x8a: "Multiple Service Packet",
0xd5: "Get Instance Attributes List",
0x83: "Get Attributes",
0xcc: "Read Template"
}
I_TAG_SERVICES_REPLY = {
"Read Tag": 0xcc,
"Read Tag Fragmented": 0xd2,
"Write Tag": 0xcd,
"Write Tag Fragmented": 0xd3,
"Read Modify Write Tag": 0xce,
"Multiple Service Packet": 0x8a,
"Get Instance Attributes List": 0xd5,
"Get Attributes": 0x83,
"Read Template": 0xcc
}
"""
EtherNet/IP Encapsulation Error Codes
Standard CIP Encapsulation Error returned in the cip message header
"""
STATUS = {
0x0000: "Success",
0x0001: "The sender issued an invalid or unsupported encapsulation command",
0x0002: "Insufficient memory",
0x0003: "Poorly formed or incorrect data in the data portion",
0x0064: "An originator used an invalid session handle when sending an encapsulation message to the target",
0x0065: "The target received a message of invalid length",
0x0069: "Unsupported Protocol Version"
}
"""
MSG Error Codes:
The following error codes have been taken from:
Rockwell Automation Publication
1756-RM003P-EN-P - December 2014
"""
SERVICE_STATUS = {
0x01: "Connection failure (see extended status)",
0x02: "Insufficient resource",
0x03: "Invalid value",
0x04: "IOI syntax error. A syntax error was detected decoding the Request Path (see extended status)",
0x05: "Destination unknown, class unsupported, instance \nundefined or structure element undefined (see extended status)",
0x06: "Insufficient Packet Space",
0x07: "Connection lost",
0x08: "Service not supported",
0x09: "Error in data segment or invalid attribute value",
0x0A: "Attribute list error",
0x0B: "State already exist",
0x0C: "Object state conflict",
0x0D: "Object already exist",
0x0E: "Attribute not settable",
0x0F: "Permission denied",
0x10: "Device state conflict",
0x11: "Reply data too large",
0x12: "Fragmentation of a primitive value",
0x13: "Insufficient command data",
0x14: "Attribute not supported",
0x15: "Too much data",
0x1A: "Bridge request too large",
0x1B: "Bridge response too large",
0x1C: "Attribute list shortage",
0x1D: "Invalid attribute list",
0x1E: "Request service error",
0x1F: "Connection related failure (see extended status)",
0x22: "Invalid reply received",
0x25: "Key segment error",
0x26: "Invalid IOI error",
0x27: "Unexpected attribute in list",
0x28: "DeviceNet error - invalid member ID",
0x29: "DeviceNet error - member not settable",
0xD1: "Module not in run state",
0xFB: "Message port not supported",
0xFC: "Message unsupported data type",
0xFD: "Message uninitialized",
0xFE: "Message timeout",
0xff: "General Error (see extended status)"
}
EXTEND_CODES = {
0x01: {
0x0100: "Connection in use",
0x0103: "Transport not supported",
0x0106: "Ownership conflict",
0x0107: "Connection not found",
0x0108: "Invalid connection type",
0x0109: "Invalid connection size",
0x0110: "Module not configured",
0x0111: "EPR not supported",
0x0114: "Wrong module",
0x0115: "Wrong device type",
0x0116: "Wrong revision",
0x0118: "Invalid configuration format",
0x011A: "Application out of connections",
0x0203: "Connection timeout",
0x0204: "Unconnected message timeout",
0x0205: "Unconnected send parameter error",
0x0206: "Message too large",
0x0301: "No buffer memory",
0x0302: "Bandwidth not available",
0x0303: "No screeners available",
0x0305: "Signature match",
0x0311: "Port not available",
0x0312: "Link address not available",
0x0315: "Invalid segment type",
0x0317: "Connection not scheduled"
},
0x04: {
0x0000: "Extended status out of memory",
0x0001: "Extended status out of instances"
},
0x05: {
0x0000: "Extended status out of memory",
0x0001: "Extended status out of instances"
},
0x1F: {
0x0203: "Connection timeout"
},
0xff: {
0x7: "Wrong data type",
0x2001: "Excessive IOI",
0x2002: "Bad parameter value",
0x2018: "Semaphore reject",
0x201B: "Size too small",
0x201C: "Invalid size",
0x2100: "Privilege failure",
0x2101: "Invalid keyswitch position",
0x2102: "Password invalid",
0x2103: "No password issued",
0x2104: "Address out of range",
0x2105: "Address and how many out of range",
0x2106: "Data in use",
0x2107: "Type is invalid or not supported",
0x2108: "Controller in upload or download mode",
0x2109: "Attempt to change number of array dimensions",
0x210A: "Invalid symbol name",
0x210B: "Symbol does not exist",
0x210E: "Search failed",
0x210F: "Task cannot start",
0x2110: "Unable to write",
0x2111: "Unable to read",
0x2112: "Shared routine not editable",
0x2113: "Controller in faulted mode",
0x2114: "Run mode inhibited"
}
}
DATA_ITEM = {
'Connected': '\xb1\x00',
'Unconnected': '\xb2\x00'
}
ADDRESS_ITEM = {
'Connection Based': '\xa1\x00',
'Null': '\x00\x00',
'UCMM': '\x00\x00'
}
UCMM = {
'Interface Handle': 0,
'Item Count': 2,
'Address Type ID': 0,
'Address Length': 0,
'Data Type ID': 0x00b2
}
CONNECTION_SIZE = {
'Backplane': '\x03', # CLX
'Direct Network': '\x02'
}
HEADER_SIZE = 24
EXTENDED_SYMBOL = '\x91'
BOOL_ONE = 0xff
REQUEST_SERVICE = 0
REQUEST_PATH_SIZE = 1
REQUEST_PATH = 2
SUCCESS = 0
INSUFFICIENT_PACKETS = 6
OFFSET_MESSAGE_REQUEST = 40
FORWARD_CLOSE = '\x4e'
UNCONNECTED_SEND = '\x52'
FORWARD_OPEN = '\x54'
LARGE_FORWARD_OPEN = '\x5b'
GET_CONNECTION_DATA = '\x56'
SEARCH_CONNECTION_DATA = '\x57'
GET_CONNECTION_OWNER = '\x5a'
MR_SERVICE_SIZE = 2
PADDING_BYTE = '\x00'
PRIORITY = '\x0a'
TIMEOUT_TICKS = '\x05'
TIMEOUT_MULTIPLIER = '\x01'
TRANSPORT_CLASS = '\xa3'
CONNECTION_PARAMETER = {
'PLC5': 0x4302,
'SLC500': 0x4302,
'CNET': 0x4320,
'DHP': 0x4302,
'Default': 0x43f8,
}
"""
Atomic Data Type:
Bit = Bool
Bit array = DWORD (32-bit boolean aray)
8-bit integer = SINT
16-bit integer = UINT
32-bit integer = DINT
32-bit float = REAL
64-bit integer = LINT
From Rockwell Automation Publication 1756-PM020C-EN-P November 2012:
When reading a BOOL tag, the values returned for 0 and 1 are 0 and 0xff, respectively.
"""
S_DATA_TYPE = {
'BOOL': 0xc1,
'SINT': 0xc2, # Signed 8-bit integer
'INT': 0xc3, # Signed 16-bit integer
'DINT': 0xc4, # Signed 32-bit integer
'LINT': 0xc5, # Signed 64-bit integer
'USINT': 0xc6, # Unsigned 8-bit integer
'UINT': 0xc7, # Unsigned 16-bit integer
'UDINT': 0xc8, # Unsigned 32-bit integer
'ULINT': 0xc9, # Unsigned 64-bit integer
'REAL': 0xca, # 32-bit floating point
'LREAL': 0xcb, # 64-bit floating point
'STIME': 0xcc, # Synchronous time
'DATE': 0xcd,
'TIME_OF_DAY': 0xce,
'DATE_AND_TIME': 0xcf,
'STRING': 0xd0, # character string (1 byte per character)
'BYTE': 0xd1, # byte string 8-bits
'WORD': 0xd2, # byte string 16-bits
'DWORD': 0xd3, # byte string 32-bits
'LWORD': 0xd4, # byte string 64-bits
'STRING2': 0xd5, # character string (2 byte per character)
'FTIME': 0xd6, # Duration high resolution
'LTIME': 0xd7, # Duration long
'ITIME': 0xd8, # Duration short
'STRINGN': 0xd9, # character string (n byte per character)
'SHORT_STRING': 0xda, # character string (1 byte per character, 1 byte length indicator)
'TIME': 0xdb, # Duration in milliseconds
'EPATH': 0xdc, # CIP Path segment
'ENGUNIT': 0xdd, # Engineering Units
'STRINGI': 0xde # International character string
}
I_DATA_TYPE = {
0xc1: 'BOOL',
0xc2: 'SINT', # Signed 8-bit integer
0xc3: 'INT', # Signed 16-bit integer
0xc4: 'DINT', # Signed 32-bit integer
0xc5: 'LINT', # Signed 64-bit integer
0xc6: 'USINT', # Unsigned 8-bit integer
0xc7: 'UINT', # Unsigned 16-bit integer
0xc8: 'UDINT', # Unsigned 32-bit integer
0xc9: 'ULINT', # Unsigned 64-bit integer
0xca: 'REAL', # 32-bit floating point
0xcb: 'LREAL', # 64-bit floating point
0xcc: 'STIME', # Synchronous time
0xcd: 'DATE',
0xce: 'TIME_OF_DAY',
0xcf: 'DATE_AND_TIME',
0xd0: 'STRING', # character string (1 byte per character)
0xd1: 'BYTE', # byte string 8-bits
0xd2: 'WORD', # byte string 16-bits
0xd3: 'DWORD', # byte string 32-bits
0xd4: 'LWORD', # byte string 64-bits
0xd5: 'STRING2', # character string (2 byte per character)
0xd6: 'FTIME', # Duration high resolution
0xd7: 'LTIME', # Duration long
0xd8: 'ITIME', # Duration short
0xd9: 'STRINGN', # character string (n byte per character)
0xda: 'SHORT_STRING', # character string (1 byte per character, 1 byte length indicator)
0xdb: 'TIME', # Duration in milliseconds
0xdc: 'EPATH', # CIP Path segment
0xdd: 'ENGUNIT', # Engineering Units
0xde: 'STRINGI' # International character string
}
REPLAY_INFO = {
0x4e: 'FORWARD_CLOSE (4E,00)',
0x52: 'UNCONNECTED_SEND (52,00)',
0x54: 'FORWARD_OPEN (54,00)',
0x6f: 'send_rr_data (6F,00)',
0x70: 'send_unit_data (70,00)',
0x00: 'nop',
0x01: 'list_targets',
0x04: 'list_services',
0x63: 'list_identity',
0x64: 'list_interfaces',
0x65: 'register_session',
0x66: 'unregister_session',
}
PCCC_DATA_TYPE = {
'N': '\x89',
'B': '\x85',
'T': '\x86',
'C': '\x87',
'S': '\x84',
'F': '\x8a',
'ST': '\x8d',
'A': '\x8e',
'R': '\x88',
'O': '\x8b',
'I': '\x8c'
}
PCCC_DATA_SIZE = {
'N': 2,
'B': 2,
'T': 6,
'C': 6,
'S': 2,
'F': 4,
'ST': 84,
'A': 2,
'R': 6,
'O': 2,
'I': 2
}
PCCC_CT = {
'PRE': 1,
'ACC': 2,
'EN': 15,
'TT': 14,
'DN': 13,
'CU': 15,
'CD': 14,
'OV': 12,
'UN': 11,
'UA': 10
}
PCCC_ERROR_CODE = {
-2: "Not Acknowledged (NAK)",
-3: "No Reponse, Check COM Settings",
-4: "Unknown Message from DataLink Layer",
-5: "Invalid Address",
-6: "Could Not Open Com Port",
-7: "No data specified to data link layer",
-8: "No data returned from PLC",
-20: "No Data Returned",
16: "Illegal Command or Format, Address may not exist or not enough elements in data file",
32: "PLC Has a Problem and Will Not Communicate",
48: "Remote Node Host is Missing, Disconnected, or Shut Down",
64: "Host Could Not Complete Function Due To Hardware Fault",
80: "Addressing problem or Memory Protect Rungs",
96: "Function not allows due to command protection selection",
112: "Processor is in Program mode",
128: "Compatibility mode file missing or communication zone problem",
144: "Remote node cannot buffer command",
240: "Error code in EXT STS Byte"
}

View File

@@ -0,0 +1,32 @@
__author__ = 'Agostino Ruscito'
__version__ = "1.0.7"
__date__ = "08 03 2015"
import logging
logging.basicConfig(
filename="pycomm.log",
filemode='w',
level=logging.INFO,
format="%(name)-13s %(levelname)-10s %(asctime)s %(message)s",
# propagate=0,
)
LOGGER = logging.getLogger('pycomm')
class PycommError(Exception):
pass
def setup_logger(name, level, filename=None):
log = logging.getLogger('pycomm.'+name)
log.setLevel(level)
if filename:
fh = logging.FileHandler(filename, mode='w')
fh.setFormatter(logging.Formatter("%(levelname)-10s %(asctime)s %(message)s"))
log.addHandler(fh)
log.propagate = False
return log

8856
POCloud_Driver/tags.xml Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long