Added POCloud driver

This commit is contained in:
Patrick McDonagh
2016-03-17 09:30:34 -05:00
parent ea692ba469
commit 348d6c3d53
7 changed files with 2101 additions and 0 deletions

View File

@@ -0,0 +1,159 @@
<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="30" 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>
<div class='clearfix col-xs-12' style='height: 300px' id="dynamicChart" data-chart="dynamicchart" data-daysofhistory="30" data-chartlabel="Data" data-ylabel="" data-xlabel="Date" data-units="" data-channelnames="poc.go_kwh,poc.go_electricity_cost,poc.go_peak_load,poc.go_min_load,poc.go_average_spm,poc.go_production_calculated,poc.go_full_card_production,poc.go_polished_rod_hp,poc.go_lifting_cost,poc.go_fluid_above_pump,poc.go_pump_intake_pressure,poc.go_kwh_regen,poc.go_inflow_rate"></div>
<div class='col-xs-12' style='margin-top: 2em;'>
<table class="table">
<thead>
<th>Date</th>
<th>% Run</th>
<th>kWh_Regen</th>
<th>Electricity Cost</th>
<th>Peak Load</th>
<th>Min. Load</th>
<th>Average SPM</th>
<th>Production</th>
<th>Full Card Production</th>
<th>Polished Rod HP</th>
<th>Lifting Cost</th>
<th>Fluid Level</th>
<th>Pump Intake Pressure</th>
<th>kWh Regen</th>
<th>Inflow Rate</th>
</thead>
<tbody id="output">
</tbody>
</table>
<!--<%= JSON.stringify(channels['poc.events'].value) %>-->
</div>
<style>
.dynamic-chart-form {
background-color: whiteSmoke;
padding: 1em 0.5em;
margin-top: 1em;
}
</style>
<script>
/*go_channels = {
"percent_run":{"meshifyName":"go_percent_run","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"kWh":{"meshifyName":"go_kwh","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"electricity_cost":{"meshifyName":"go_electricity_cost","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"peak_load":{"meshifyName":"go_peak_load","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"min_load":{"meshifyName":"go_min_load","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"average_SPM":{"meshifyName":"go_average_spm","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"production_calculated":{"meshifyName":"go_production_calculated","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"full_card_production":{"meshifyName":"go_full_card_production","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"polished_rod_HP":{"meshifyName":"go_polished_rod_hp","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"lifting_cost":{"meshifyName":"go_lifting_cost","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"fluid_above_pump":{"meshifyName":"go_fluid_above_pump","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"pump_intake_pressure":{"meshifyName":"go_pump_intake_pressure","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"kWh_regen":{"meshifyName":"go_kwh_regen","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
"inflow_rate":{"meshifyName":"go_inflow_rate","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
}*/
var nodeID = <%= node.nodeId %>;
var nodeType = '<%= node.nodetypeName %>';
var channelIDs = {
go_percent_run: <%= channels['poc.go_percent_run'].channelId %>,
go_kwh: <%= channels['poc.go_kwh'].channelId %>,
go_electricity_cost: <%= channels['poc.go_electricity_cost'].channelId %>,
go_peak_load: <%= channels['poc.go_peak_load'].channelId %>,
go_min_load: <%= channels['poc.go_min_load'].channelId %>,
go_average_spm: <%= channels['poc.go_average_spm'].channelId %>,
go_production_calculated: <%= channels['poc.go_production_calculated'].channelId %>,
go_full_card_production: <%= channels['poc.go_full_card_production'].channelId %>,
go_polished_rod_hp: <%= channels['poc.go_polished_rod_hp'].channelId %>,
go_lifting_cost: <%= channels['poc.go_lifting_cost'].channelId %>,
go_fluid_above_pump: <%= channels['poc.go_fluid_above_pump'].channelId %>,
go_pump_intake_pressure: <%= channels['poc.go_pump_intake_pressure'].channelId %>,
go_kwh_regen: <%= channels['poc.go_kwh_regen'].channelId %>,
go_inflow_rate: <%= channels['poc.go_inflow_rate'].channelId %>
};
var go_percent_run = <%= channels['poc.go_percent_run'].channelId %>;
var go_kwh = <%= channels['poc.go_kwh'].channelId %>;
var go_electricity_cost = <%= channels['poc.go_electricity_cost'].channelId %>;
var go_peak_load = <%= channels['poc.go_peak_load'].channelId %>;
var go_min_load = <%= channels['poc.go_min_load'].channelId %>;
var go_average_spm = <%= channels['poc.go_average_spm'].channelId %>;
var go_production_calculated = <%= channels['poc.go_production_calculated'].channelId %>;
var go_full_card_production = <%= channels['poc.go_full_card_production'].channelId %>;
var go_polished_rod_hp = <%= channels['poc.go_polished_rod_hp'].channelId %>;
var go_lifting_cost = <%= channels['poc.go_lifting_cost'].channelId %>;
var go_fluid_above_pump = <%= channels['poc.go_fluid_above_pump'].channelId %>;
var go_pump_intake_pressure = <%= channels['poc.go_pump_intake_pressure'].channelId %>;
var go_kwh_regen = <%= channels['poc.go_kwh_regen'].channelId %>;
var go_inflow_rate = <%= channels['poc.go_inflow_rate'].channelId %>;
var formatDate = function(str){
var c1, c2;
c1 = new Date(str);
c2 = (c1.getTime() / 1000);
c2 = Math.floor(c2);
return c2.toString();
};
var updateTable = function(chID){
var apiData, start, end;
var $output = $('#output');
start = $('#datePicker').find('#fromDate');
dateString = start.val().replace(/-/g, "/");
start = formatDate(dateString);
end = $('#datePicker').find('#toDate');
dateString = end.val().replace(/-/g, "/");
end = formatDate(dateString);
apiData = "&nodelist[0][nodeId]=" + nodeID.toString() + "&nodelist[0][channelId]=" + chID.toString();
apiData += "&start=" + start + "&end=" + end;
$.ajax({
url: "http://henrypump.meshify.com/api2/Nodechannels",
data: apiData,
dataType: "json",
type: "GET",
success: function(data) {
console.log(channeldata:data);
/*var events = data.listofstreams[0];
for(var i = events.stream.length-1; i > 0; i--) {
var event = events.stream[i];
var timestamp = event.x;
var jsonBlock = event.y;
var ev = JSON.parse(jsonBlock);
var row = "<tr>";
row += "<td>" + ev.id + "</td>";
row += "<td>" + ev.datetime + "</td>";
row += "<td>" + ev.type + "</td>";
row += "<td>" + ev.cond + "</td>";
row += "<td>" + ev.tag + "</td>";
row += "<td>" + ev.value + "</td>";
row += "<td>" + ev.device_name + "</td>";
row += "<td>" + ev.stroke_number + "</td>";
row += "</tr>"
$output.append(row)
//$output.append(JSON.stringify(jsonBlock));*/
//}
}
});
}
$(document).ready(function(){
for (var channel in channelIDs){
if(channelIDs.hasOwnProperty(channel)){
updateTable(channelIDs[channel]);
}
}
});
</script>

View File

@@ -0,0 +1,96 @@
<div style='margin-top: 1em;' class='col-xs-12'>
<div class="input-daterange input-group" id="datePicker">
<input id="fromDate" data-daysofhistory="30" type="text" class="form-control" name="start">
<span class="input-group-addon">to</span>
<input class="form-control" id="toDate" type="text" name="end">
<span class='input-group-btn'>
<a href="" id="runPickerBtn" class="btn btn-theme">Run</a>
</span>
</div>
</div>
<div class='col-xs-12' style='margin-top: 2em;'>
<table class="table">
<thead>
<th>Event ID</th>
<th>Date & Time</th>
<th>Type</th>
<th>Condition</th>
<th>Tag</th>
<th>Value</th>
<th>Device Name</th>
<th>Stroke Number</th>
</thead>
<tbody id="output">
</tbody>
</table>
<!--<%= JSON.stringify(channels['poc.events'].value) %>-->
</div>
<script>
var nodeID = <%= node.nodeId %>;
var nodeType = '<%= node.nodetypeName %>';
var channelID = <%= channels['poc.events'].channelId %>;
console.log({nodeID:nodeID, nodeType:nodeType, channelID: channelID})
var formatDate = function(str){
var c1, c2;
c1 = new Date(str);
c2 = (c1.getTime() / 1000);
c2 = Math.floor(c2);
return c2.toString();
};
var updateTable = function(){
var apiData, start, end;
var $output = $('#output');
start = $('#datePicker').find('#fromDate');
dateString = start.val().replace(/-/g, "/");
start = formatDate(dateString);
end = $('#datePicker').find('#toDate');
dateString = end.val().replace(/-/g, "/");
end = formatDate(dateString);
apiData = "&nodelist[0][nodeId]=" + nodeID.toString() + "&nodelist[0][channelId]=" + channelID.toString();
apiData += "&start=" + start + "&end=" + end;
$.ajax({
url: "http://henrypump.meshify.com/api2/Nodechannels",
data: apiData,
dataType: "json",
type: "GET",
success: function(data) {
var events = data.listofstreams[0];
for(var i = events.stream.length-1; i > 0; i--) {
var event = events.stream[i];
var timestamp = event.x;
var jsonBlock = event.y;
var ev = JSON.parse(jsonBlock);
var row = "<tr>";
row += "<td>" + ev.id + "</td>";
row += "<td>" + ev.datetime + "</td>";
row += "<td>" + ev.type + "</td>";
row += "<td>" + ev.cond + "</td>";
row += "<td>" + ev.tag + "</td>";
row += "<td>" + ev.value + "</td>";
row += "<td>" + ev.device_name + "</td>";
row += "<td>" + ev.stroke_number + "</td>";
row += "</tr>"
$output.append(row)
//$output.append(JSON.stringify(jsonBlock));
}
}
});
}
$(document).on('click', '#runPickerBtn', function(e){
e.preventDefault();
updateTable();
});
$(document).ready(function(){
updateTable();
})
</script>

View File

@@ -0,0 +1,173 @@
<div class="text-center"><h1>TODAY'S TOTALS</h1></div>
<div class='row overview'>
<div class='col-xs-4 text-center'>
<h2>Percent Run</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge1" data-chart="solidgauge" data-nodename="poc.dt_percent_run" data-units="%" data-min="0" data-max="100" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B"></div>
<span data-timeupdate="dt_percent_run"><%= channels["poc.dt_percent_run"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center'>
<h2>Average Speed</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge2" data-chart="solidgauge" data-nodename="poc.dt_average_spm" data-units="SPM" data-min="0" data-max="20" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B" data-decimals="2"></div>
<span data-timeupdate="dt_average_spm"><%= channels["poc.dt_average_spm"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center'>
<h2>Calculated Production</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge3" data-chart="solidgauge" data-nodename="poc.dt_calculated_production" data-units="BBL" data-min="0" data-max="1000" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B"></div>
<span data-timeupdate="dt_calculated_production"><%= channels["poc.dt_calculated_production"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center'>
<h2>Projected Production</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge4" data-chart="solidgauge" data-nodename="poc.dt_projected_production" data-units="HP" data-min="0" data-max="1000" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B"></div>
<span data-timeupdate="dt_projected_production"><%= channels["poc.dt_projected_production"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center'>
<h2>Pump Intake Pressure</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge5" data-chart="solidgauge" data-nodename="poc.dt_pump_intake_pressure" data-units="PSI" data-min="0" data-max="2000" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B"></div>
<span data-timeupdate="dt_pump_intake_pressure"><%= channels["poc.dt_pump_intake_pressure"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center'>
<h2>Energy Consumed</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge6" data-chart="solidgauge" data-nodename="poc.dt_kWh" data-units="kWh" data-min="0" data-max="200" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B"></div>
<span data-timeupdate="dt_kWh"><%= channels["poc.dt_kWh"].timestamp %></span>
</div>
</div>
</div>
<!-- TOTALS -->
<div class="text-center"><h1>LATEST STROKE</h1></div>
<div class='row overview'>
<div class='col-xs-4 text-center'>
<h2>Pump Fillage</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge7" data-chart="solidgauge" data-nodename="poc.fillage_percent" data-units="%" data-min="0" data-max="100" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B"></div>
<span data-timeupdate="fillage_percent"><%= channels["poc.fillage_percent"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center'>
<h2>Fluid Above Pump</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge8" data-chart="solidgauge" data-nodename="poc.fluid_above_pump" data-units="ft." data-min="0" data-max="5000" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B"></div>
<span data-timeupdate="fluid_above_pump"><%= channels["poc.fluid_above_pump"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center'>
<h2>Speed</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge9" data-chart="solidgauge" data-nodename="poc.SPM" data-units="SPM" data-min="0" data-max="20" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B"></div>
<span data-timeupdate="SPM"><%= channels["poc.SPM"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center'>
<h2>Polished Rod HP</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge10" data-chart="solidgauge" data-nodename="poc.polished_rod_hp" data-units="HP" data-min="0" data-max="50" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B"></div>
<span data-timeupdate="polished_rod_hp"><%= channels["poc.polished_rod_hp"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center'>
<h2>Pump HP</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge11" data-chart="solidgauge" data-nodename="poc.pump_hp" data-units="HP" data-min="0" data-max="50" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B"></div>
<span data-timeupdate="pump_hp"><%= channels["poc.pump_hp"].timestamp %></span>
</div>
</div>
<div class='col-xs-4 text-center'>
<h2>Downhole Fluid Load</h2>
<div class="gauge-box">
<div data-labelheight="10" style="height: 170px; background: transparent; margin: 0 auto;" id="gauge12" data-chart="solidgauge" data-nodename="poc.downhole_fluid_load" data-units="lbs." data-min="0" data-max="10000" data-colors="0.1:#DF5353,0.5:#DDDF0D,0.9:#55BF3B"></div>
<span data-timeupdate="downhole_fluid_load"><%= channels["poc.downhole_fluid_load"].timestamp %></span>
</div>
</div>
</div>
<div class="col-xs-12" style="padding: 1em 0;">
<div class="progress" style="margin:1em 5%">
<div class="progress-bar progress-bar-striped active" id="surface_stroke_length" role="progressbar" aria-valuenow="<%= channels["poc.surface_stroke_length"].value %>" aria-valuemin="0" aria-valuemax="100" style="width: <%= channels["poc.surface_stroke_length"].value %>%;">
Surface Stroke Length: <%= channels["poc.surface_stroke_length"].value %> in.
</div>
</div>
<div class="progress" style="margin:1em 5%">
<div class="progress-bar progress-bar-striped active" id="downhole_gross_stroke" role="progressbar" aria-valuenow="<%= channels["poc.downhole_gross_stroke"].value %>" aria-valuemin="0" aria-valuemax="100" style="width: <%= channels["poc.downhole_gross_stroke"].value %>%;">
Downhole Gross Stroke: <%= channels["poc.downhole_gross_stroke"].value %> in.
</div>
</div>
<div class="progress" style="margin:1em 5%">
<div class="progress-bar progress-bar-striped active" id="downhole_adjusted_gross_stroke" role="progressbar" aria-valuenow="<%= channels["poc.downhole_adjusted_gross_stroke"].value %>" aria-valuemin="0" aria-valuemax="100" style="width: <%= channels["poc.downhole_adjusted_gross_stroke"].value %>%;">
Downhole Adjusted Gross Stroke: <%= channels["poc.downhole_adjusted_gross_stroke"].value %> in.
</div>
</div>
<div class="progress" style="margin:1em 5%">
<div class="progress-bar progress-bar-striped active" id="downhole_net_stroke" role="progressbar" aria-valuenow="<%= channels["poc.downhole_net_stroke"].value %>" aria-valuemin="0" aria-valuemax="100" style="width: <%= channels["poc.downhole_net_stroke"].value %>%;">
Downhole Net Stroke: <%= channels["poc.downhole_net_stroke"].value %> in.
</div>
</div>
<table style="margin-top: 1.5em;" class="table table-striped">
<thead>
<tr><th>Measurement</th><th>Value</th></tr>
</thead>
<tbody>
<!-- <tr><td>Well Name</td><td><span data-valueupdate="well_name"><%= channels["poc.well_name"].value %></span></td></tr>
<tr><td>Fillage Percent</td><td><span data-valueupdate="fillage_percent"><%= channels["poc.fillage_percent"].value %> %</span></td></tr> -->
<tr><td>Fluid Gradient</td><td><span data-valueupdate="fluid_gradient"><%= channels["poc.fluid_gradient"].value %> lbs/ft</span></td></tr>
<tr><td>dt</td><td><span data-valueupdate="dt"><%= channels["poc.dt"].value %> sec</span></td></tr>
<tr><td>Tubing Head Pressure</td><td><span data-valueupdate="tubing_head_pressure"><%= channels["poc.tubing_head_pressure"].value %> PSI</span></td></tr>
<tr><td>Stuffing Box Friction</td><td><span data-valueupdate="stuffing_box_friction"><%= channels["poc.stuffing_box_friction"].value %> lbs.</span></td></tr>
<tr><td>Surface Stroke Length</td><td><span data-valueupdate="surface_stroke_length"><%= channels["poc.surface_stroke_length"].value %> in.</span></td></tr>
<tr><td>Surface Min. Load</td><td><span data-valueupdate="surface_min_load"><%= channels["poc.surface_min_load"].value %> lbs.</span></td></tr>
<tr><td>Surface Max. Load</td><td><span data-valueupdate="surface_max_load"><%= channels["poc.surface_max_load"].value %> lbs.</span></td></tr>
<tr><td>Downhole Gross Stroke</td><td><span data-valueupdate="downhole_gross_stroke"><%= channels["poc.downhole_gross_stroke"].value %> in.</span></td></tr>
<tr><td>Tubing Movement</td><td><span data-valueupdate="tubing_movement"><%= channels["poc.tubing_movement"].value %> in.</span></td></tr>
<tr><td>Downhole Adjusted Gross Stroke</td><td><span data-valueupdate="downhole_adjusted_gross_stroke"><%= channels["poc.downhole_adjusted_gross_stroke"].value %> in.</span></td></tr>
<tr><td>Downhole Net Stroke</td><td><span data-valueupdate="downhole_net_stroke"><%= channels["poc.downhole_net_stroke"].value %> in.</span></td></tr>
<tr><td>Downhole Fluid Load</td><td><span data-valueupdate="downhole_fluid_load"><%= channels["poc.downhole_fluid_load"].value %> lbs.</span></td></tr>
<tr><td>Polished Rod HP</td><td><span data-valueupdate="polished_rod_hp"><%= channels["poc.polished_rod_hp"].value %> HP</span></td></tr>
<tr><td>Pump HP</td><td><span data-valueupdate="pump_hp"><%= channels["poc.pump_hp"].value %> HP</span></td></tr>
<tr><td>Fluid Level</td><td><span data-valueupdate="fluid_above_pump"><%= channels["poc.fluid_above_pump"].value %> ft.</span></td></tr>
</tbody>
</table>
<style>
.overview .col-xs-4 {
position: relative;
padding: 0.5em;
padding-bottom: 1.5em;
border: 1px solid #eee;
/*margin: 1em 0;*/
}
.overview .gauge-box {
margin-top: -0.25em;
}
.overview h2 {
text-transform: uppercase;
font-size: 14px;
color: #666;
font-weight: 400;
letter-spacing: 1px;
z-index: 100;
}
</style>

View File

@@ -0,0 +1,311 @@
<div class="container">
<div class="row">
<div class="col-xs-6">
<h1>Rod String & Pump</h1>
<br />
<div id="output">
<canvas id="taperCanvas" width="300" height="500"></canvas>
<!-- <%= channels["poc.well_setup"].value %> -->
</div>
</div>
<div class="col-xs-5">
<br />
<ul class="nav nav-tabs" id="taperTabs" role="tablist">
</ul>
<table class="table tablestriped" >
<thead>
<tr><th>Measurement</th><th>Value</th></tr>
</thead>
<tbody id="data_table">
<tr><td>Length</td><td><span id="tLength"></span> ft.</td></tr>
<tr><td>Diameter</td><td><span id="tDiameter"></span> in.</td></tr>
<tr><td>Material</td><td><span id="tMaterial"></span></td></tr>
<tr><td>Damping Factor</td><td><span id="tDamping"></span></td></tr>
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col-xs-5">
<h1>Motor Data</h1>
<table class="table tablestriped" >
<thead>
<tr><th>Measurement</th><th>Value</th></tr>
</thead>
<tbody id="motor_data_table">
<tr><td>Volts</td><td><span id="mVolts"></span> V</td></tr>
<tr><td>Hertz</td><td><span id="mHertz"></span> Hz</td></tr>
<tr><td>Poles</td><td><span id="mPoles"></span></td></tr>
<tr><td>Amps</td><td><span id="mAmps"></span> A</td></tr>
<tr><td>Horsepower</td><td><span id="mHorsepower"></span> HP</td></tr>
<tr><td>Service Factor</td><td><span id="mServiceFactor"></span></td></tr>
<tr><td>RPM</td><td><span id="mRPM"></span> RPM</td></tr>
<tr><td>Motor Sheave</td><td><span id="mMotorSheave"></span> in.</td></tr>
<tr><td>Gearbox Rating</td><td><span id="mGbxRating"></span> x 1000 in-lbs</td></tr>
<tr><td>Gearbox Ratio</td><td><span id="mGbxRatio"></span></td></tr>
<tr><td>Gearbox Limit</td><td><span id="mGbxLimit"></span></td></tr>
<tr><td>Gearbox Sheave</td><td><span id="mGbxSheave"></span> in.</td></tr>
<tr><td>Max Frequency</td><td><span id="mMaxFreq"></span> Hz</td></tr>
<tr><td>Min RPM</td><td><span id="mMinRPM"></span> RPM</td></tr>
<tr><td>Max RPM</td><td><span id="mMaxRPM"></span> RPM</td></tr>
</tbody>
</table>
</div>
<div class="col-xs-5 col-xs-offset-1">
<h1>Well Parameters</h1>
<table class="table tablestriped" >
<thead>
<tr><th>Measurement</th><th>Value</th></tr>
</thead>
<tbody id="well_data_table">
<tr><td>API Gravity Oil</td><td><span id="wAPIOil"></span></td></tr>
<tr><td>Specific Gravity Water</td><td><span id="wSGWater"></span></td></tr>
<tr><td>Young's Modulus (Steel)</td><td><span id="wYMSteel"></span> x 10^6</td></tr>
<tr><td>Young's Modulus (Fiberglass)</td><td><span id="wYMFiberglass"></span> x 10^6</td></tr>
<tr><td>Water Cut</td><td><span id="wWaterCut"></span> %</td></tr>
<tr><td>Casing ID</td><td><span id="wCasingID"></span> in.</td></tr>
<tr><td>Tubing OD</td><td><span id="wTubingOD"></span> in.</td></tr>
<tr><td>Tubing ID</td><td><span id="wTubingID"></span> in.</td></tr>
<tr><td>Tubing Anchor Depth</td><td><span id="wAnchorDepth"></span> ft.</td></tr>
<tr><td>Pump Diameter</td><td><span id="wPumpDiameter"></span> in.</td></tr>
<tr><td>Pump Constant</td><td><span id="wPumpConstant"></span></td></tr>
<tr><td>Structural Rating</td><td><span id="wStructuralRating"></span> x 100 lbs.</td></tr>
<tr><td>Motor Control Mode</td><td><span id="wMotorControlMode"></span></td></tr>
<tr><td>Total Vertical Depth</td><td><span id="wTotalVerticalDepth"></span> ft.</td></tr>
<tr><td>Well Type</td><td><span id="wWellType"></span></td></tr>
<tr><td>Surface Stroke Length</td><td><span id="wSurfaceStrokeLength"></span> in.</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- {"backupData":{
a"Youngs_Modulus_Steel":"30.5",
"unitConfig":{
a"SG_Water":"1.25",
a"API_Oil":"1.1",
a"Gearbox_Sheave":"35.75",
a"Percent_Water":"91.667",
a"Total_Vertical_Depth_Input":"12000.0",
a"Tubing_Size_ID":"1.995",
a"Anchor_Depth":"8923.0",
a"motorNameplate":{
a "Volts":"480.0",
a "Hertz":"60.0",
a "Poles":"6",
a "Amps":"52.0",
a "Horsepower":"40.0",
a "ServiceFactor":"1.15",
a "RPM":"1100.0"
},
a"RPM_Minimum":"0.0",
a"Total_Vertical_Depth":"10395.0",
a"Tubing_Size_OD":"2.375",
a"Pump_Diameter":"1.25",
a"Motor_Sheave_Size":"4.75",
a"Rating_Gearbox":"320.0",
a"Gearbox_Limit":"100.0",
a"Rating_Structural":"305.0",
a"Speed_Torque_Mode":"3",
a"Pump_Constant":"0.0",
a"Gearbox_Ratio":"28.7",
"Well_Type":"0",
a"MaxFreq":"155.0",
a"RPM_Maximum":"2500.0",
a"MotorCntrlMode":"3",
"Total_Stroke_Length":"99.0"
},
"Youngs_Modulus_Fiberglass":"7.2",
"Casing_ID":"4.892",
"taper":[
{"setup":
{
"Diameter":"0.0",
"c":"0.0",
"Material":"0",
"Length":"0.0",
"RodCount":"0",
"UseRodCount":"0"
}
},
{"setup":{"Diameter":"0.75","c":"0.08","Material":"1","Length":"10095.0","RodCount":"0","UseRodCount":"0"}},{"setup":{"Diameter":"1.5","c":"0.08","Material":"1","Length":"300.0","RodCount":"0","UseRodCount":"0"}},{"setup":{"Diameter":"1.5","c":"0.08","Material":"1","Length":"0.0","RodCount":"0","UseRodCount":"0"}},{"setup":{"Diameter":"0.75","c":"0.0","Material":"1","Length":"0.0","RodCount":"0","UseRodCount":"0"}},{"setup":{"Diameter":"1.5","c":"0.0","Material":"1","Length":"0.0","RodCount":"0","UseRodCount":"0"}},{"setup":{"Diameter":"1.5","c":"0.0","Material":"1","Length":"0.0","RodCount":"0","UseRodCount":"0"}},{"setup":{"Diameter":"0.0","c":"0.0","Material":"1","Length":"0.0","RodCount":"0","UseRodCount":"0"}},{"setup":{"Diameter":"0.0","c":"0.0","Material":"1","Length":"0.0","RodCount":"0","UseRodCount":"0"}},{"setup":{"Diameter":"0.0","c":"0.0","Material":"1","Length":"0.0","RodCount":"0","UseRodCount":"0"}},{"setup":{"Diameter":"0.0","c":"0.0","Material":"1","Length":"0.0","RodCount":"0","UseRodCount":"0"}}]}} -->
<script>
var raw = <%= channels["poc.well_setup"].value %>;
// var parsed = JSON.stringify(raw);
var backupData = raw.backupData;
var taperData = backupData.taper;
var unitConfig = backupData.unitConfig;
var taper_sel = 1;
var taperLength = [];
var taperWidth = [];
var rodDepth = [];
var taperDepth = [];
var context = document.getElementById("taperCanvas").getContext("2d");
var canvas_width = $('#taperCanvas').width();
var canvas_height = $('#taperCanvas').height();
var pump_height = 100;
var taper_height = canvas_height - pump_height;
var max_width = canvas_width * 0.5;
var total_depth = parseFloat(unitConfig.Total_Vertical_Depth);
var currentDepth = 0;
for(var i = 0; i< taperData.length; i++){
if (taperData[i].setup.Length > 0.0){
$('#taperTabs').append('<li class="t_tab" id="taper'+i+'" taper='+i+'><a href="#" style="color:#337AB7">'+i+'</a></li>');
taperLength.push((taperData[i].setup.Length / total_depth) * taper_height);
taperWidth.push(taperData[i].setup.Diameter * (max_width / 2.5));
rodDepth.push(currentDepth);
taperDepth.push((currentDepth /total_depth) * taper_height);
currentDepth = currentDepth + parseFloat(taperData[i].setup.Length);
}
}
console.log({rodDepth:rodDepth});
console.log({taperDepth:taperDepth});
var drawTapers = function(active){
var horiz_space = 0;
var gradient=context.createLinearGradient((canvas_width - max_width) / 2,0,((canvas_width - max_width) / 2)+max_width,0);
gradient.addColorStop(0,"black");
gradient.addColorStop(0.5,"white");
gradient.addColorStop(1,"black");
context.fillStyle=gradient;
context.lineWidth = 2;
for (i=0;i<taperLength.length; i++){
horiz_space = (canvas_width - taperWidth[i]) / 2;
context.beginPath();
context.moveTo(horiz_space, taperDepth[i]);
context.lineTo(horiz_space + taperWidth[i], taperDepth[i]);
context.lineTo(horiz_space + taperWidth[i], taperDepth[i]+ taperLength[i]);
context.lineTo(horiz_space, taperDepth[i] + taperLength[i]);
context.lineTo(horiz_space, taperDepth[i]);
console.log(active);
if (i+1 == active){
context.strokeStyle = 'red';
} else {
context.strokeStyle = 'black';
}
// context.strokeStyle = 'black';
context.fill();
context.stroke()
context.closePath();
}
var pump_width = unitConfig.Pump_Diameter * (max_width/2.5);
horiz_space = (canvas_width - pump_width) / 2;
if (active =="Unit"){
context.strokeStyle = 'red';
} else {
context.strokeStyle = 'black';
}
// context.strokeStyle = 'blue';
context.beginPath();
context.moveTo(horiz_space, taper_height);
context.lineTo(horiz_space + pump_width, taper_height);
context.lineTo(horiz_space + pump_width, taper_height + pump_height);
context.lineTo(horiz_space, taper_height + pump_height);
context.lineTo(horiz_space, taper_height);
context.fill();
context.stroke()
context.closePath();
}
drawTapers(1);
var updateTable = function(taper_selected){
$('#data_table').html('<tr><td>Length</td><td><span id="tLength"></span> ft.</td></tr><tr><td>Diameter</td><td><span id="tDiameter"></span> in.</td></tr><tr><td>Material</td><td><span id="tMaterial"></span></td></tr><tr><td>Damping Factor</td><td><span id="tDamping"></span></td></tr>');
var material;
$('#tLength').text(taperData[taper_selected].setup.Length);
$('#tDiameter').text(taperData[taper_selected].setup.Diameter);
if (parseInt(taperData[taper_selected].setup.Material) == 1){
material = "Steel";
} else if (parseInt(taperData[taper_selected].setup.Material) == 2){
material = "Fiberglass";
}
$('#tMaterial').text(material);
$('#tDamping').text(taperData[taper_selected].setup.c);
}
updateTable(1);
$('#taper1').addClass('active');
$(".t_tab").click(function(){
$("#taperTabs>.active").removeClass('active');
$(this).addClass('active');
taper_sel = $(this).attr("taper");
if (taper_sel != "Unit"){
updateTable(taper_sel);
} else {
$("#data_table").html("<tr><td>Pump Diameter</td><td>"+ taperData["Unit"].Pump_Diameter+ " in.</td></tr>");
}
drawTapers(taper_sel);
})
$('#mVolts').text(unitConfig.motorNameplate.Volts);
$('#mHertz').text(unitConfig.motorNameplate.Hertz);
$('#mPoles').text(unitConfig.motorNameplate.Poles);
$('#mAmps').text(unitConfig.motorNameplate.Amps);
$('#mHorsepower').text(unitConfig.motorNameplate.Horsepower);
$('#mServiceFactor').text(unitConfig.motorNameplate.ServiceFactor);
$('#mRPM').text(unitConfig.motorNameplate.RPM);
$('#mMotorSheave').text(unitConfig.Motor_Sheave_Size);
$('#mGbxRating').text(unitConfig.Rating_Gearbox);
$('#mGbxRatio').text(unitConfig.Gearbox_Ratio);
$('#mGbxLimit').text(unitConfig.Gearbox_Limit);
$('#mGbxSheave').text(unitConfig.Gearbox_Sheave);
$('#mMaxFreq').text(unitConfig.MaxFreq);
$('#mMinRPM').text(unitConfig.RPM_Minimum);
$('#mMaxRPM').text(unitConfig.RPM_Maximum);
$('#wAPIOil').text(unitConfig.API_Oil);
$('#wSGWater').text(unitConfig.SG_Water);
$('#wYMSteel').text(backupData.Youngs_Modulus_Steel);
$('#wYMFiberglass').text(backupData.Youngs_Modulus_Fiberglass);
$('#wWaterCut').text(unitConfig.Percent_Water);
$('#wTubingOD').text(unitConfig.Tubing_Size_OD);
$('#wTubingID').text(unitConfig.Tubing_Size_ID);
$('#wCasingID').text(backupData.Casing_ID);
$('#wAnchorDepth').text(unitConfig.Anchor_Depth);
$('#wPumpDiameter').text(unitConfig.Pump_Diameter);
$('#wPumpConstant').text(unitConfig.Pump_Constant);
$('#wStructuralRating').text(unitConfig.Rating_Structural);
if (parseInt(unitConfig.MotorCntrlMode) == 3){
$('#wMotorControlMode').text("Torque");
} else if (parseInt(unitConfig.MotorCntrlMode) == 1) {
$('#wMotorControlMode').text("Speed");
}
$('#wTotalVerticalDepth').text(unitConfig.Total_Vertical_Depth);
if (parseInt(unitConfig.Well_Type) == 0){
$('#wWellType').text("Vertical");
} else if (parseInt(unitConfig.Well_Type) == 1) {
$('#wWellType').text("Directional");
}
$('#wSurfaceStrokeLength').text(unitConfig.Total_Stroke_Length);
</script>

467
POCloud/w_csv/poc.py Normal file
View File

@@ -0,0 +1,467 @@
#!/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
from datetime import datetime
import requests
try:
import json
except:
import simplejson as json
import calendar
def min_max_check(val, min, max):
if val < min:
return min
elif val > max:
return max
else:
return val
go_channels = {
"percent_run": {"meshifyName": "go_percent_run", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"kWh": {"meshifyName": "go_kwh", "last_value": "", "last_send_time": 0, "data_type": " float", "change_amount": 0},
"electricity_cost": {"meshifyName": "go_electricity_cost", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"peak_load": {"meshifyName": "go_peak_load", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"min_load": {"meshifyName": "go_min_load", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"average_SPM": {"meshifyName": "go_average_spm", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"production_calculated": {"meshifyName": "go_production_calculated", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"full_card_production": {"meshifyName": "go_full_card_production", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"polished_rod_HP": {"meshifyName": "go_polished_rod_hp", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"lifting_cost": {"meshifyName": "go_lifting_cost", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"fluid_above_pump": {"meshifyName": "go_fluid_above_pump", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"pump_intake_pressure": {"meshifyName": "go_pump_intake_pressure", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"kWh_regen": {"meshifyName": "go_kwh_regen", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"inflow_rate": {"meshifyName": "go_inflow_rate", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
}
stroke_data_min_upload_time = 300 # seconds
channels = {
"status": {"last_value": "", "data_type": "str", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": 0},
"card_history": {"last_value": "", "data_type": "str", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": 0},
"well_name": {"last_value": "", "data_type": "str", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"tubing_head_pressure": {"last_value": "", "data_type": "float", "change_amount": 5, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"fluid_gradient": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"stuffing_box_friction": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"dt": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_gross_stroke": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_adjusted_gross_stroke": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_net_stroke": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_fluid_load": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"surface_max_load": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"surface_min_load": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"tubing_movement": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"surface_stroke_length": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"fillage_percent": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"polished_rod_hp": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"pump_hp": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"SPM": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"fluid_above_pump": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"pump_intake_pressure": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"stroke_production": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"drive_torque_mode": {"last_value": "", "data_type": "int", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"torque_reference": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"speed_reference": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_min_position": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_max_position": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
}
total_min_upload_time = 300 # seconds
dt_channels = { # Current Daily Totals
"Average_SPM": {"meshify_channel": "dt_average_spm", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Downhole_Net_Stroke": {"meshify_channel": "dt_downhole_net_stroke", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Electricity_Cost": {"meshify_channel": "dt_electricity_cost", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Fluid_Level": {"meshify_channel": "dt_fluid_level", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Full_Card_Production": {"meshify_channel": "dt_full_card_production", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Inflow_Rate": {"meshify_channel": "dt_inflow_rate", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"kWh": {"meshify_channel": "dt_kWh", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"kWh_Regen": {"meshify_channel": "dt_kWh_regen", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Lifting_Cost": {"meshify_channel": "dt_lifting_cost", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Peak_Load": {"meshify_channel": "dt_peak_load", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Min_Load": {"meshify_channel": "dt_min_load", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Percent_Run": {"meshify_channel": "dt_percent_run", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Polished_Rod_HP": {"meshify_channel": "dt_polished_rod_hp", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Calculated_Production": {"meshify_channel": "dt_calculated_production", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Projected_Production": {"meshify_channel": "dt_projected_production", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Pump_HP": {"meshify_channel": "dt_pump_hp", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Pump_Intake_Presure": {"meshify_channel": "dt_pump_intake_pressure", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Surface_Stroke_Length": {"meshify_channel": "dt_surface_stroke_length", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Tubing_Movement": {"meshify_channel": "dt_tubing_movement", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
}
class start(threading.Thread, deviceBase):
def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None, companyId=None, offset=None, mqtt=None, Nodes=None):
threading.Thread.__init__(self)
deviceBase.__init__(self, name=name, number=number, mac=mac, Q=Q, mcu=mcu, companyId=companyId, offset=offset, mqtt=mqtt, Nodes=Nodes)
self.daemon = True
self.forceSend = True
self.version = "2"
self.device_address = "http://192.168.1.30/"
self.cardLoopTimer = 600
self.finished = threading.Event()
threading.Thread.start(self)
self.statusChanged = False
self.al_status_last = False
self.dl_status_last = False
# load stored event ID's
try:
with open('eventIds.p', 'rb') as handle:
self.eventIds = pickle.load(handle)
print "found pickled eventID dictionary: {0}".format(self.eventIds)
except:
print "couldn't load enent ID's from pickle"
self.eventIds = []
# load stored wellconfig's
try:
with open('wellSetup.p', 'rb') as handle:
self.wellSetup = pickle.load(handle)
print "Found pickled Well Setup (but it's going to be too long to print)"
# print self.wellConfig
except:
print "couldn't load Well Setup from pickle"
self.wellSetup = []
self.sendtodbJSON("device_address", self.device_address, 0)
# 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):
channels["status"]["last_value"] = ""
def run(self):
self.runLoopStatus = ""
checkBackupEvery = 100
checkBackupSkipped = 1
while True:
try:
runLoopStatus = "checkEvents"
self.checkEvents()
runLoopStatus = "checkStatus"
self.checkStatus()
runLoopStatus = "checkDailyTotals"
self.checkDailyTotals()
runLoopStatus = "checkGaugeOffData"
self.checkGaugeOffData()
runLoopStatus = "getDataLoggerStatus()"
self.getDataLoggerStatus()
if self.statusChanged:
runLoopStatus = "getLatestXCards"
self.getLatestXCards(5)
else:
runLoopStatus = "checkLatestCard"
self.checkLatestCard()
if self.forceSend or (checkBackupSkipped > checkBackupEvery):
runLoopStatus = "checkBackup"
self.checkBackup()
checkBackupSkipped = 0
checkBackupSkipped = checkBackupSkipped + 1
runLoopStatus = "Complete"
time.sleep(3)
self.forceSend = False
except Exception, e:
sleep_timer = 20
print "Error during {0} of run loop: {1}\nWill try again in {2} seconds...".format(runLoopStatus, e, sleep_timer)
time.sleep(sleep_timer)
def checkBackup(self):
backupList = json.loads(requests.get(self.device_address + "/json/backups").text)
file = backupList["backups"][0]
data = json.loads(requests.get(self.device_address + "/json/backups/" + file).text)
timestamp = time.time()
if data != self.wellSetup or self.forceSend:
self.sendtodbJSON("well_setup", json.dumps(data), timestamp)
self.wellSetup = data
with open('wellSetup.p', 'wb') as handle:
pickle.dump(self.wellSetup, handle)
def checkEvents(self):
data = json.loads(requests.get(self.device_address + "/json/event_list").text)
events = data["events"]
for event in events:
if int(event["id"]) not in self.eventIds:
# timestamp = calendar.timegm(time.strptime(event["datetime"], '%Y-%m-%dT%H:%M:%S.%fZ'))
date = event['datetime']
reg = "(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d*)Z"
fd = re.search(reg, date)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)), int(fd.group(7)))
# timestamp = int(time.mktime(time.strptime(date, '%Y-%m-%dT%H:%M:%S.%fZ')))
timestamp = calendar.timegm(dt.timetuple())
# we have a new event
self.sendtodbJSON("events", json.dumps(event), timestamp)
self.eventIds.append(int(event["id"]))
if len(self.eventIds) > 50:
del self.eventIds[0]
with open('eventIds.p', 'wb') as handle:
pickle.dump(self.eventIds, handle)
def checkStatus(self):
statusMap = {
0: 'Stopped',
1: 'Running',
2: 'Pumped Off',
3: 'Faulted',
4: 'Starting',
5: 'Recovering',
100: 'Read Error',
1000: 'PLC Error',
9999: 'No Response'
}
st_response = requests.get(self.device_address + "/json/status")
if st_response.status_code == 200:
data = json.loads(st_response.text)
date = data["ISOdate"]
status = statusMap[int(data["status"])]
if channels["status"]["last_value"] != status:
self.statusChanged = True
print "Status has changed from {0} to {1} @ {2}".format(channels["status"]["last_value"], status, time.time())
else:
self.statusChanged = False
if self.statusChanged or self.forceSend:
self.status = status
# timestamp = int(time.mktime(time.strptime(date, '%Y-%m-%dT%H:%M:%S.%fZ')))
reg = "(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d*)Z"
fd = re.search(reg, date)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)), int(fd.group(7)))
timestamp = calendar.timegm(dt.timetuple())
self.sendtodb("status", status, timestamp)
channels["status"]["last_value"] = status
self.checkLatestCard()
def checkDailyTotals(self):
data = json.loads(requests.get(self.device_address + "/json/totals").text)
total = data["totals"]
if total['status'] == "success":
timestamp = 0
for val in total['values']:
if dt_channels.has_key(val['name']):
if ((time.time() - int(dt_channels[val['name']]['last_time_uploaded'])) > int(dt_channels[val['name']]['min_time_between_uploads'])):
if (float(val['value']) >= (float(dt_channels[val['name']]["last_value"]) + float(dt_channels[val['name']]["change_amount"]))) or (float(val['value']) <= (float(dt_channels[val['name']]["last_value"]) - float(dt_channels[val['name']]["change_amount"]))):
print("[dailyTotal] {0}: {1}".format(val['name'], val['value']))
self.sendtodb(dt_channels[val['name']]["meshify_channel"], float(val['value']), timestamp)
dt_channels[val['name']]["last_value"] = float(val['value'])
dt_channels[val['name']]["last_time_uploaded"] = time.time()
else:
print("checkDailyTotalsError: {0}".format(total.message))
def checkGaugeOffData(self):
data = json.loads(requests.get(self.device_address + "/json/history").text)
day = data["hist"]
date = day['gauge_date']
# print day["gauge_date"]
# timestamp = time.mktime(time.strptime(day["gauge_date"], '%Y-%m-%dT%H:%M:%S.%fZ'))
reg = "(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d*)Z"
fd = re.search(reg, date)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)), int(fd.group(7)))
# timestamp = int(time.mktime(time.strptime(date, '%Y-%m-%dT%H:%M:%S.%fZ')))
timestamp = calendar.timegm(dt.timetuple())
for entry in day:
if go_channels.has_key(entry):
# "percent_run":{"meshifyName":"go_percent_run","last_value":"","last_send_time":0,"data_type":"float","change_amount":0},
if go_channels[entry]["last_value"] != day[entry]:
print entry, day[entry]
print go_channels[entry]["meshifyName"], day[entry], timestamp
self.sendtodb(go_channels[entry]["meshifyName"], day[entry], timestamp)
go_channels[entry]["last_value"] = day[entry]
def checkLatestCard(self):
latest = requests.get(self.device_address + "/json/latest")
latest = json.loads(latest.text)
folder = str(latest["folder"])
file = latest["file"].replace(".csv", "")
# check the card to see if its new
# 1. if its new send the folder/file_name to the card_history channel
# 2. if its new and its been 10 minutes since you last sent an entire card, then send up all of the data
if channels["card_history"]["last_value"] != (folder + "/" + file):
# we have a new card
# get the data for this event
data = json.loads(requests.get(self.device_address + "/json/" + folder + "/" + file).text)
dateTime = str(data["contents"]["utctime"])
# timestamp = time.mktime(time.strptime(dateTime, '%Y-%m-%d %H:%M:%S.%f'))
reg = "(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}).(\d*)"
fd = re.search(reg, dateTime)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)), int(fd.group(7)))
timestamp = calendar.timegm(dt.timetuple())
card_timestamp = int(time.mktime(dt.timetuple()))
print "New card detected @ {0}".format(datetime.strftime(datetime.fromtimestamp(timestamp), "%Y-%m-%d %H:%M:%S.%f"))
# set the last value = to current value and upload your data
channels["card_history"]["last_value"] = (folder + "/" + file)
self.sendtodb("card_history", (folder + "/" + file), card_timestamp)
# check the last time the card was updated
if (time.time() - int(channels["card_history"]["last_time_uploaded"])) > self.cardLoopTimer or self.statusChanged or self.forceSend:
# its been 10 minutes, send the full upload
print "Either status has changed or last stored card is too old."
channels["card_history"]["last_time_uploaded"] = time.time()
self.process_card(data, timestamp, card_timestamp, sendCards=True)
return
else:
self.process_card(data, timestamp, card_timestamp, sendCards=False)
def process_card(self, data, data_timestamp, card_timestamp, sendCards=False):
# if sendCards = True then we upload all data no matter what, including cards
# check what type of data it is
# check if its changed, if it has, how long has it been since it changed
# NOTE: the initial vaue of "" is given to all channels in the channels object,
# so to avoid comparing a string to a float, and to make sure on startup we send all of the values, the first time through we send everything that has a "" as its last value
# We don't want to store any data on starting, just the cards
if self.status != 'Starting':
for channel in data["contents"]:
if channels.has_key(channel):
if channels[channel]["data_type"] == "str":
if (data["contents"][channel] != channels[channel]["last_value"] and ((time.time() - int(channels[channel]["last_time_uploaded"])) > int(channels[channel]["min_time_between_uploads"]))) or sendCards:
print "new value for: ", channel
print data["contents"][channel]
self.sendtodb(channel, str(data["contents"][channel]), int(data_timestamp))
channels[channel]["last_value"] = data["contents"][channel]
channels[channel]["last_time_uploaded"] = time.time()
if channels[channel]["data_type"] == "float" or channels[channel]["data_type"] == "int":
if channels[channel]["last_value"] == "":
# print "first time getting data"
print "new value for: ", channel
print data["contents"][channel]
self.sendtodb(channel, str(data["contents"][channel]), int(data_timestamp))
channels[channel]["last_value"] = data["contents"][channel]
channels[channel]["last_time_uploaded"] = time.time()
if (abs(float(data["contents"][channel]) - float(channels[channel]["last_value"])) > channels[channel]["change_amount"] and ((time.time() - int(channels[channel]["last_time_uploaded"])) > int(channels[channel]["min_time_between_uploads"]))) or sendCards:
# print "first time getting data"
print "new value for: ", channel
print data["contents"][channel]
self.sendtodb(channel, str(data["contents"][channel]), int(data_timestamp))
channels[channel]["last_value"] = data["contents"][channel]
channels[channel]["last_time_uploaded"] = time.time()
if sendCards:
sc = data["s"]
dc = data["d"]
for i in range(len(data["d"])):
try:
for x in range(len(data["d"][i])):
data["d"][i][x] = float('%.3f' % data["d"][i][x])
except Exception, e:
print e
for i in range(len(data["s"])):
try:
for x in range(len(data["s"][i])):
data["s"][i][x] = float('%.3f' % data["s"][i][x])
except Exception, e:
print e
sc = data["s"]
dc = data["d"]
newSc = "["
for i in sc:
try:
if i[0] is None:
continue
if i[0] != 0.0 and i[1] != 0.0:
newSc += "[" + str(i[0]) + "," + str(i[1]) + "],"
except:
pass
newSc += "[" + str(sc[0][0]) + "," + str(sc[0][1]) + "]"
newSc += "]"
newDc = "["
for i in dc:
try:
if i[0] is None:
continue
if i[0] != 0.0 and i[1] != 0.0:
newDc += "[" + str(i[0]) + "," + str(i[1]) + "],"
except:
pass
newDc += "[" + str(dc[0][0]) + "," + str(dc[0][1]) + "]"
newDc += "]"
self.sendtodb("sc", newSc, card_timestamp)
self.sendtodb("dc", newDc, card_timestamp)
def getLatestXCards(self, numCards):
data = json.loads(requests.get(self.device_address + "/json/latest/" + str(int(numCards))).text)
for card in data['cards']:
card_data = json.loads(requests.get(self.device_address + "/json/" + data['folder'] + "/" + card).text)
dateTime = str(card_data["contents"]["utctime"])
# timestamp = time.mktime(time.strptime(dateTime, '%Y-%m-%d %H:%M:%S.%f'))
reg = "(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}).(\d*)"
fd = re.search(reg, dateTime)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)), int(fd.group(7)))
timestamp = calendar.timegm(dt.timetuple())
card_timestamp = int(time.mktime(dt.timetuple()))
channels["card_history"]["last_value"] = (data['folder'] + "/" + card)
self.sendtodb("card_history", (data['folder'] + "/" + card), card_timestamp)
self.process_card(card_data, timestamp, card_timestamp, sendCards=True)
def getDataLoggerStatus(self):
data = json.loads(requests.get(self.device_address + "/json/pythonstatus/").text)
al_status = "Not OK"
if data['status']['alarmLogger']:
al_status = "OK"
if al_status != self.al_status_last:
self.sendtodb("alarmlogger_status", al_status, 0)
self.al_status_last = al_status
dl_status = "Not OK"
if data['status']['dataLogger']:
dl_status = "OK"
if al_status != self.dl_status_last:
self.sendtodb("datalogger_status", dl_status, 0)
self.dl_status_last = dl_status
def poc_get_card(self, name, value):
self.getcard(value)
def poc_sync(self, name, value):
self.sendtodb("connected", "true", 0)
return True
def poc_set_address(self, name, value):
self.device_address = value
return True
def poc_refresh_data(self, name, value):
self.forceSend = True
return True

446
POCloud/w_mysql/poc.py Normal file
View File

@@ -0,0 +1,446 @@
#!/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
from datetime import datetime
import requests
try:
import json
except:
import simplejson as json
import calendar
def min_max_check(val, min, max):
if val < min:
return min
elif val > max:
return max
else:
return val
go_channels = {
"percent_run": {"meshifyName": "go_percent_run", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"kWh": {"meshifyName": "go_kwh", "last_value": "", "last_send_time": 0, "data_type": " float", "change_amount": 0},
"electricity_cost": {"meshifyName": "go_electricity_cost", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"peak_load": {"meshifyName": "go_peak_load", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"min_load": {"meshifyName": "go_min_load", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"average_SPM": {"meshifyName": "go_average_spm", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"production_calculated": {"meshifyName": "go_production_calculated", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"full_card_production": {"meshifyName": "go_full_card_production", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"polished_rod_HP": {"meshifyName": "go_polished_rod_hp", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"lifting_cost": {"meshifyName": "go_lifting_cost", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"fluid_above_pump": {"meshifyName": "go_fluid_above_pump", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"pump_intake_pressure": {"meshifyName": "go_pump_intake_pressure", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"kWh_regen": {"meshifyName": "go_kwh_regen", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"inflow_rate": {"meshifyName": "go_inflow_rate", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
}
stroke_data_min_upload_time = 300 # seconds
channels = {
"status": {"last_value": "", "data_type": "str", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": 0},
"card_history": {"last_value": "", "data_type": "str", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": 0},
"well_name": {"last_value": "", "data_type": "str", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"tubing_head_pressure": {"last_value": "", "data_type": "float", "change_amount": 5, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"fluid_gradient": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"stuffing_box_friction": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"dt": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_gross_stroke": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_adjusted_gross_stroke": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_net_stroke": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_fluid_load": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"surface_max_load": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"surface_min_load": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"tubing_movement": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"surface_stroke_length": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"fillage_percent": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"polished_rod_hp": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"pump_hp": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"SPM": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"fluid_above_pump": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"pump_intake_pressure": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"stroke_production": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"drive_torque_mode": {"last_value": "", "data_type": "int", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"torque_reference": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"speed_reference": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_min_position": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_max_position": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
}
total_min_upload_time = 300 # seconds
dt_channels = { # Current Daily Totals
"Average_SPM": {"meshify_channel": "dt_average_spm", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Downhole_Net_Stroke": {"meshify_channel": "dt_downhole_net_stroke", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Electricity_Cost": {"meshify_channel": "dt_electricity_cost", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Fluid_Level": {"meshify_channel": "dt_fluid_level", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Full_Card_Production": {"meshify_channel": "dt_full_card_production", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Inflow_Rate": {"meshify_channel": "dt_inflow_rate", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"kWh": {"meshify_channel": "dt_kWh", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"kWh_Regen": {"meshify_channel": "dt_kWh_regen", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Lifting_Cost": {"meshify_channel": "dt_lifting_cost", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Peak_Load": {"meshify_channel": "dt_peak_load", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Min_Load": {"meshify_channel": "dt_min_load", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Percent_Run": {"meshify_channel": "dt_percent_run", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Polished_Rod_HP": {"meshify_channel": "dt_polished_rod_hp", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Calculated_Production": {"meshify_channel": "dt_calculated_production", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Projected_Production": {"meshify_channel": "dt_projected_production", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Pump_HP": {"meshify_channel": "dt_pump_hp", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Pump_Intake_Presure": {"meshify_channel": "dt_pump_intake_pressure", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Surface_Stroke_Length": {"meshify_channel": "dt_surface_stroke_length", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Tubing_Movement": {"meshify_channel": "dt_tubing_movement", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
}
class start(threading.Thread, deviceBase):
def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None, companyId=None, offset=None, mqtt=None, Nodes=None):
threading.Thread.__init__(self)
deviceBase.__init__(self, name=name, number=number, mac=mac, Q=Q, mcu=mcu, companyId=companyId, offset=offset, mqtt=mqtt, Nodes=Nodes)
self.daemon = True
self.forceSend = True
self.version = "2"
# self.device_address = "http://192.168.1.30/"
self.device_address = "http://localhost/"
self.cardLoopTimer = 600
self.finished = threading.Event()
threading.Thread.start(self)
self.statusChanged = False
self.al_status_last = False
self.dl_status_last = False
# load stored event ID's
try:
with open('eventIds.p', 'rb') as handle:
self.eventIds = pickle.load(handle)
print "found pickled eventID dictionary: {0}".format(self.eventIds)
except:
print "couldn't load enent ID's from pickle"
self.eventIds = []
# load stored wellconfig's
try:
with open('wellSetup.p', 'rb') as handle:
self.wellSetup = pickle.load(handle)
print "Found pickled Well Setup (but it's going to be too long to print)"
# print self.wellConfig
except:
print "couldn't load Well Setup from pickle"
self.wellSetup = []
self.sendtodbJSON("device_address", self.device_address, 0)
# 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):
channels["status"]["last_value"] = ""
def run(self):
self.runLoopStatus = ""
checkBackupEvery = 100
checkBackupSkipped = 1
while True:
try:
runLoopStatus = "checkEvents"
self.checkEvents()
runLoopStatus = "checkStatus"
self.checkStatus()
runLoopStatus = "checkDailyTotals"
self.checkDailyTotals()
runLoopStatus = "checkGaugeOffData"
self.checkGaugeOffData()
runLoopStatus = "getDataLoggerStatus()"
self.getDataLoggerStatus()
if self.statusChanged:
runLoopStatus = "getLatestXCards"
self.getLatestXCards(5)
else:
runLoopStatus = "checkLatestCard"
self.checkLatestCard()
if self.forceSend or (checkBackupSkipped > checkBackupEvery):
runLoopStatus = "checkBackup"
self.checkBackup()
checkBackupSkipped = 0
checkBackupSkipped = checkBackupSkipped + 1
runLoopStatus = "Complete"
time.sleep(3)
self.forceSend = False
except Exception, e:
sleep_timer = 20
print "Error during {0} of run loop: {1}\nWill try again in {2} seconds...".format(runLoopStatus, e, sleep_timer)
time.sleep(sleep_timer)
def checkBackup(self):
backupList = json.loads(requests.get(self.device_address + "/json/backups").text)
file = backupList["backups"][0]
data = json.loads(requests.get(self.device_address + "/json/backups/" + file).text)
timestamp = time.time()
if data != self.wellSetup or self.forceSend:
self.sendtodbJSON("well_setup", json.dumps(data), timestamp)
self.wellSetup = data
with open('wellSetup.p', 'wb') as handle:
pickle.dump(self.wellSetup, handle)
def checkEvents(self):
data = json.loads(requests.get(self.device_address + "/json/event_list").text)
events = data["events"]
for event in events:
if int(event["id"]) not in self.eventIds:
timestamp = calendar.timegm(time.strptime(event["datetime"], '%Y-%m-%dT%H:%M:%S.%fZ'))
# we have a new event
self.sendtodbJSON("events", json.dumps(event), timestamp)
self.eventIds.append(int(event["id"]))
if len(self.eventIds) > 50:
del self.eventIds[0]
with open('eventIds.p', 'wb') as handle:
pickle.dump(self.eventIds, handle)
def checkStatus(self):
statusMap = {
0: 'Stopped',
1: 'Running',
2: 'Pumped Off',
3: 'Faulted',
4: 'Starting',
5: 'Recovering',
100: 'Read Error',
1000: 'PLC Error',
9999: 'No Response'
}
st_response = requests.get(self.device_address + "/json/status")
if st_response.status_code == 200:
data = json.loads(st_response.text)
date = data["ISOdate"]
status = statusMap[int(data["status"])]
if channels["status"]["last_value"] != status:
self.statusChanged = True
print "Status has changed from {0} to {1} @ {2}".format(channels["status"]["last_value"], status, time.time())
else:
self.statusChanged = False
if self.statusChanged or self.forceSend:
self.status = status
reg = "(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d{3})Z"
fd = re.search(reg, date)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)), int(fd.group(7)))
# timestamp = int(time.mktime(time.strptime(date, '%Y-%m-%dT%H:%M:%S.%fZ')))
timestamp = calendar.timegm(dt.timetuple())
self.sendtodb("status", status, timestamp)
channels["status"]["last_value"] = status
def checkDailyTotals(self):
data = json.loads(requests.get(self.device_address + "/json/totals").text)
total = data["totals"]
if total['status'] == "success":
timestamp = 0
for val in total['values']:
if dt_channels.has_key(val['name']):
if ((time.time() - int(dt_channels[val['name']]['last_time_uploaded'])) > int(dt_channels[val['name']]['min_time_between_uploads'])):
if (float(val['value']) >= (float(dt_channels[val['name']]["last_value"]) + float(dt_channels[val['name']]["change_amount"]))) or (float(val['value']) <= (float(dt_channels[val['name']]["last_value"]) - float(dt_channels[val['name']]["change_amount"]))):
print("[dailyTotal] {0}: {1}".format(val['name'], val['value']))
self.sendtodb(dt_channels[val['name']]["meshify_channel"], float(val['value']), timestamp)
dt_channels[val['name']]["last_value"] = float(val['value'])
dt_channels[val['name']]["last_time_uploaded"] = time.time()
else:
print("checkDailyTotalsError: {0}".format(total.message))
def checkGaugeOffData(self):
data = json.loads(requests.get(self.device_address + "/json/history").text)
day = data["hist"]
date = day['gauge_date']
# print day["gauge_date"]
# timestamp = time.mktime(time.strptime(day["gauge_date"], '%Y-%m-%dT%H:%M:%S.%fZ'))
reg = "(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d{3})Z"
fd = re.search(reg, date)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)), int(fd.group(7)))
# timestamp = int(time.mktime(time.strptime(date, '%Y-%m-%dT%H:%M:%S.%fZ')))
timestamp = calendar.timegm(dt.timetuple())
for entry in day:
if go_channels.has_key(entry):
# "percent_run": {"meshifyName": "go_percent_run", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
if go_channels[entry]["last_value"] != day[entry]:
print entry, day[entry]
print go_channels[entry]["meshifyName"], day[entry], timestamp
self.sendtodb(go_channels[entry]["meshifyName"], day[entry], timestamp)
go_channels[entry]["last_value"] = day[entry]
def checkLatestCard(self):
latest = requests.get(self.device_address + "/json/latest")
latest = json.loads(latest.text)
folder = str(latest["folder"])
file = latest["file"].replace(".csv", "")
# check the card to see if its new
# 1. if its new send the folder/file_name to the card_history channel
# 2. if its new and its been 10 minutes since you last sent an entire card, then send up all of the data
if channels["card_history"]["last_value"] != (folder + "/" + file):
# we have a new card
# get the data for this event
data = json.loads(requests.get(self.device_address + "/json/" + folder + "/" + file).text)
dateTime = str(data["card_data"]["Stroke_Time"])
# timestamp = time.mktime(time.strptime(dateTime, '%Y-%m-%dT%H:%M:%S.%fZ'))
reg = "(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d{3})Z"
fd = re.search(reg, dateTime)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)), int(fd.group(7)))
timestamp = calendar.timegm(dt.timetuple())
card_timestamp = int(time.mktime(dt.timetuple()))
print "New card detected @ {0}".format(datetime.strftime(datetime.fromtimestamp(timestamp), "%Y-%m-%d %H:%M:%S.%f"))
# set the last value = to current value and upload your data
channels["card_history"]["last_value"] = (folder + "/" + file)
self.sendtodb("card_history", (folder + "/" + file), timestamp)
# check the last time the card was updated
if (time.time() - int(channels["card_history"]["last_time_uploaded"])) > self.cardLoopTimer or self.statusChanged or self.forceSend:
# its been 10 minutes, send the full upload
print "Either status has changed or last stored card is too old."
channels["card_history"]["last_time_uploaded"] = time.time()
self.process_card(data, timestamp, card_timestamp, sendCards=True)
return
else:
self.process_card(data, timestamp, card_timestamp, sendCards=False)
def process_card(self, data, data_timestamp, card_timestamp, sendCards=False):
# if sendCards = True then we upload all data no matter what, including cards
# check what type of data it is
# check if its changed, if it has, how long has it been since it changed
# NOTE: the initial vaue of "" is given to all channels in the channels object,
# so to avoid comparing a string to a float, and to make sure on startup we send all of the values, the first time through we send everything that has a "" as its last value
# We don't want to store any data on starting, just the cards
if self.status != 'Starting':
for channel in data["card_data"]:
if channels.has_key(channel):
if channels[channel]["data_type"] == "str":
if (data["card_data"][channel] != channels[channel]["last_value"] and ((time.time() - int(channels[channel]["last_time_uploaded"])) > int(channels[channel]["min_time_between_uploads"]))) or sendCards:
print "new value for: ", channel
print data["card_data"][channel]
self.sendtodb(channel, str(data["card_data"][channel]), int(data_timestamp))
channels[channel]["last_value"] = data["card_data"][channel]
channels[channel]["last_time_uploaded"] = time.time()
if channels[channel]["data_type"] == "float" or channels[channel]["data_type"] == "int":
if channels[channel]["last_value"] == "":
# print "first time getting data"
print "new value for: ", channel
print data["card_data"][channel]
self.sendtodb(channel, str(data["card_data"][channel]), int(data_timestamp))
channels[channel]["last_value"] = data["card_data"][channel]
channels[channel]["last_time_uploaded"] = time.time()
if (abs(float(data["card_data"][channel]) - float(channels[channel]["last_value"])) > channels[channel]["change_amount"] and ((time.time() - int(channels[channel]["last_time_uploaded"])) > int(channels[channel]["min_time_between_uploads"]))) or sendCards:
# print "first time getting data"
print "new value for: ", channel
print data["card_data"][channel]
self.sendtodb(channel, str(data["card_data"][channel]), int(data_timestamp))
channels[channel]["last_value"] = data["card_data"][channel]
channels[channel]["last_time_uploaded"] = time.time()
if sendCards:
s_p = data["card_data"]["Surface_Position"]
s_l = data["card_data"]["Surface_Load"]
d_p = data["card_data"]["Downhole_Position"]
d_l = data["card_data"]["Downhole_Load"]
newSc = "["
newDc = "["
for i in range(len(s_p)):
try:
if s_p[i] is None:
continue
if s_p[i] != 0.0 and s_l[i] != 0.0:
newSc += "[" + str(s_p[i]) + ", " + str(s_l[i]) + "], "
except:
pass
newSc += "[" + str(s_p[0]) + ", " + str(s_l[0]) + "]"
newSc += "]"
for i in range(len(d_p)):
try:
if d_p[i] is None:
continue
if d_p[i] != 0.0 and d_l[i] != 0.0:
newDc += "[" + str(d_p[i]) + ", " + str(d_l[i]) + "], "
except:
pass
newDc += "[" + str(d_p[0]) + ", " + str(d_l[0]) + "]"
newDc += "]"
self.sendtodb("sc", newSc, card_timestamp)
self.sendtodb("dc", newDc, card_timestamp)
def getLatestXCards(self, numCards):
data = json.loads(requests.get(self.device_address + "/json/latest/" + str(int(numCards))).text)
for card in data['cards']:
card_data = json.loads(requests.get(self.device_address + "/json/" + data['folder'] + "/" + card).text)
dateTime = str(card_data["card_data"]["Stroke_Time"])
# timestamp = time.mktime(time.strptime(dateTime,'%Y-%m-%dT%H:%M:%S.%fZ'))
reg = "(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d{3})Z"
fd = re.search(reg, dateTime)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)), int(fd.group(7)))
timestamp = calendar.timegm(dt.timetuple())
card_timestamp = int(time.mktime(dt.timetuple()))
channels["card_history"]["last_value"] = (data['folder'] + "/" + card)
self.sendtodb("card_history", (data['folder'] + "/" + card), card_timestamp)
self.process_card(card_data, timestamp, sendCards=True)
def getDataLoggerStatus(self):
data = json.loads(requests.get(self.device_address + "/json/pythonstatus/").text)
al_status = "Not OK"
if data['status']['alarmLogger']:
al_status = "OK"
if al_status != self.al_status_last:
self.sendtodb("alarmlogger_status", al_status, 0)
self.al_status_last = al_status
dl_status = "Not OK"
if data['status']['dataLogger']:
dl_status = "OK"
if al_status != self.dl_status_last:
self.sendtodb("datalogger_status", dl_status, 0)
self.dl_status_last = dl_status
def poc_get_card(self, name, value):
self.getcard(value)
def poc_sync(self, name, value):
self.sendtodb("connected", "true", 0)
return True
def poc_set_address(self, name, value):
self.device_address = value
return True
def poc_refresh_data(self, name, value):
self.forceSend = True
return True

449
POCloud/w_sqlite/poc.py Normal file
View File

@@ -0,0 +1,449 @@
#!/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
from datetime import datetime
import requests
try:
import json
except:
import simplejson as json
import calendar
def min_max_check(val, min, max):
if val < min:
return min
elif val > max:
return max
else:
return val
go_channels = {
"percent_run": {"meshifyName": "go_percent_run", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"kWh": {"meshifyName": "go_kwh", "last_value": "", "last_send_time": 0, "data_type": " float", "change_amount": 0},
"electricity_cost": {"meshifyName": "go_electricity_cost", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"peak_load": {"meshifyName": "go_peak_load", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"min_load": {"meshifyName": "go_min_load", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"average_SPM": {"meshifyName": "go_average_spm", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"production_calculated": {"meshifyName": "go_production_calculated", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"full_card_production": {"meshifyName": "go_full_card_production", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"polished_rod_HP": {"meshifyName": "go_polished_rod_hp", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"lifting_cost": {"meshifyName": "go_lifting_cost", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"fluid_above_pump": {"meshifyName": "go_fluid_above_pump", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"pump_intake_pressure": {"meshifyName": "go_pump_intake_pressure", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"kWh_regen": {"meshifyName": "go_kwh_regen", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
"inflow_rate": {"meshifyName": "go_inflow_rate", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
}
stroke_data_min_upload_time = 300 # seconds
channels = {
"status": {"last_value": "", "data_type": "str", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": 0},
"card_history": {"last_value": "", "data_type": "str", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": 0},
"well_name": {"last_value": "", "data_type": "str", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"tubing_head_pressure": {"last_value": "", "data_type": "float", "change_amount": 5, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"fluid_gradient": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"stuffing_box_friction": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"dt": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_gross_stroke": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_adjusted_gross_stroke": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_net_stroke": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_fluid_load": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"surface_max_load": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"surface_min_load": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"tubing_movement": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"surface_stroke_length": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"fillage_percent": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"polished_rod_hp": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"pump_hp": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"SPM": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"fluid_above_pump": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"pump_intake_pressure": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"stroke_production": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"drive_torque_mode": {"last_value": "", "data_type": "int", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"torque_reference": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"speed_reference": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_min_position": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
"downhole_max_position": {"last_value": "", "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": stroke_data_min_upload_time},
}
total_min_upload_time = 300 # seconds
dt_channels = { # Current Daily Totals
"Average_SPM": {"meshify_channel": "dt_average_spm", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Downhole_Net_Stroke": {"meshify_channel": "dt_downhole_net_stroke", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Electricity_Cost": {"meshify_channel": "dt_electricity_cost", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Fluid_Level": {"meshify_channel": "dt_fluid_level", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Full_Card_Production": {"meshify_channel": "dt_full_card_production", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Inflow_Rate": {"meshify_channel": "dt_inflow_rate", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"kWh": {"meshify_channel": "dt_kWh", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"kWh_Regen": {"meshify_channel": "dt_kWh_regen", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Lifting_Cost": {"meshify_channel": "dt_lifting_cost", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Peak_Load": {"meshify_channel": "dt_peak_load", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Min_Load": {"meshify_channel": "dt_min_load", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Percent_Run": {"meshify_channel": "dt_percent_run", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Polished_Rod_HP": {"meshify_channel": "dt_polished_rod_hp", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Calculated_Production": {"meshify_channel": "dt_calculated_production", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Projected_Production": {"meshify_channel": "dt_projected_production", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Pump_HP": {"meshify_channel": "dt_pump_hp", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Pump_Intake_Presure": {"meshify_channel": "dt_pump_intake_pressure", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Surface_Stroke_Length": {"meshify_channel": "dt_surface_stroke_length", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
"Tubing_Movement": {"meshify_channel": "dt_tubing_movement", "last_value": 0, "data_type": "float", "change_amount": 0, "last_time_uploaded": 0, "min_time_between_uploads": total_min_upload_time},
}
class start(threading.Thread, deviceBase):
def __init__(self, name=None, number=None, mac=None, Q=None, mcu=None, companyId=None, offset=None, mqtt=None, Nodes=None):
threading.Thread.__init__(self)
deviceBase.__init__(self, name=name, number=number, mac=mac, Q=Q, mcu=mcu, companyId=companyId, offset=offset, mqtt=mqtt, Nodes=Nodes)
self.daemon = True
self.forceSend = True
self.version = "2"
# self.device_address = "http://192.168.1.30/"
self.device_address = "http://localhost/"
self.cardLoopTimer = 600
self.finished = threading.Event()
threading.Thread.start(self)
self.statusChanged = False
self.al_status_last = False
self.dl_status_last = False
# load stored event ID's
try:
with open('eventIds.p', 'rb') as handle:
self.eventIds = pickle.load(handle)
print "found pickled eventID dictionary: {0}".format(self.eventIds)
except:
print "couldn't load enent ID's from pickle"
self.eventIds = []
# load stored wellconfig's
try:
with open('wellSetup.p', 'rb') as handle:
self.wellSetup = pickle.load(handle)
print "Found pickled Well Setup (but it's going to be too long to print)"
# print self.wellConfig
except:
print "couldn't load Well Setup from pickle"
self.wellSetup = []
self.sendtodbJSON("device_address", self.device_address, 0)
# 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):
channels["status"]["last_value"] = ""
def run(self):
self.runLoopStatus = ""
checkBackupEvery = 100
checkBackupSkipped = 1
while True:
try:
runLoopStatus = "checkEvents"
self.checkEvents()
runLoopStatus = "checkStatus"
self.checkStatus()
runLoopStatus = "checkDailyTotals"
self.checkDailyTotals()
runLoopStatus = "checkGaugeOffData"
self.checkGaugeOffData()
runLoopStatus = "getDataLoggerStatus()"
self.getDataLoggerStatus()
if self.statusChanged:
runLoopStatus = "getLatestXCards"
self.getLatestXCards(5)
else:
runLoopStatus = "checkLatestCard"
self.checkLatestCard()
if self.forceSend or (checkBackupSkipped > checkBackupEvery):
runLoopStatus = "checkBackup"
self.checkBackup()
checkBackupSkipped = 0
checkBackupSkipped = checkBackupSkipped + 1
runLoopStatus = "Complete"
time.sleep(3)
self.forceSend = False
except Exception, e:
sleep_timer = 20
print "Error during {0} of run loop: {1}\nWill try again in {2} seconds...".format(runLoopStatus, e, sleep_timer)
time.sleep(sleep_timer)
def checkBackup(self):
backupList = json.loads(requests.get(self.device_address + "/json/backups").text)
file = backupList["backups"][0]
data = json.loads(requests.get(self.device_address + "/json/backups/" + file).text)
timestamp = time.time()
if data != self.wellSetup or self.forceSend:
self.sendtodbJSON("well_setup", json.dumps(data), timestamp)
self.wellSetup = data
with open('wellSetup.p', 'wb') as handle:
pickle.dump(self.wellSetup, handle)
def checkEvents(self):
data = json.loads(requests.get(self.device_address + "/json/event_list").text)
events = data["events"]
for event in events:
if int(event["id"]) not in self.eventIds:
timestamp = calendar.timegm(time.strptime(event["datetime"], '%Y-%m-%dT%H:%M:%S.%fZ'))
# we have a new event
self.sendtodbJSON("events", json.dumps(event), timestamp)
self.eventIds.append(int(event["id"]))
if len(self.eventIds) > 50:
del self.eventIds[0]
with open('eventIds.p', 'wb') as handle:
pickle.dump(self.eventIds, handle)
def checkStatus(self):
statusMap = {
0: 'Stopped',
1: 'Running',
2: 'Pumped Off',
3: 'Faulted',
4: 'Starting',
5: 'Recovering',
100: 'Read Error',
1000: 'PLC Error',
9999: 'No Response'
}
st_response = requests.get(self.device_address + "/json/status")
if st_response.status_code == 200:
data = json.loads(st_response.text)
date = data["ISOdate"]
status = statusMap[int(data["status"])]
if channels["status"]["last_value"] != status:
self.statusChanged = True
print "Status has changed from {0} to {1} @ {2}".format(channels["status"]["last_value"], status, time.time())
else:
self.statusChanged = False
if self.statusChanged or self.forceSend:
self.status = status
reg = "(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).(\d{3})Z"
fd = re.search(reg, date)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)), int(fd.group(7)))
# timestamp = int(time.mktime(time.strptime(date, '%Y-%m-%dT%H:%M:%S.%fZ')))
timestamp = calendar.timegm(dt.timetuple())
self.sendtodb("status", status, timestamp)
channels["status"]["last_value"] = status
def checkDailyTotals(self):
data = json.loads(requests.get(self.device_address + "/json/totals").text)
total = data["totals"]
if total['status'] == "success":
timestamp = 0
for val in total['values']:
# if dt_channels.has_key(val['name']):
if val['name'] in dt_channels:
if ((time.time() - int(dt_channels[val['name']]['last_time_uploaded'])) > int(dt_channels[val['name']]['min_time_between_uploads'])):
if (float(val['value']) >= (float(dt_channels[val['name']]["last_value"]) + float(dt_channels[val['name']]["change_amount"]))) or (float(val['value']) <= (float(dt_channels[val['name']]["last_value"]) - float(dt_channels[val['name']]["change_amount"]))):
print("[dailyTotal] {0}: {1}".format(val['name'], val['value']))
self.sendtodb(dt_channels[val['name']]["meshify_channel"], float(val['value']), timestamp)
dt_channels[val['name']]["last_value"] = float(val['value'])
dt_channels[val['name']]["last_time_uploaded"] = time.time()
else:
print("checkDailyTotalsError: {0}".format(total.message))
def checkGaugeOffData(self):
data = json.loads(requests.get(self.device_address + "/json/history").text)
day = data["hist"]
date = day['gauge_date']
# print day["gauge_date"]
# timestamp = time.mktime(time.strptime(day["gauge_date"], '%Y-%m-%dT%H:%M:%S.%fZ'))
reg = "(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})"
fd = re.search(reg, date)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)))
# timestamp = int(time.mktime(time.strptime(date, '%Y-%m-%dT%H:%M:%S.%fZ')))
timestamp = calendar.timegm(dt.timetuple())
for entry in day:
# if go_channels.has_key(entry):
if entry in go_channels:
# "percent_run": {"meshifyName": "go_percent_run", "last_value": "", "last_send_time": 0, "data_type": "float", "change_amount": 0},
if go_channels[entry]["last_value"] != day[entry]:
print entry, day[entry]
print go_channels[entry]["meshifyName"], day[entry], timestamp
self.sendtodb(go_channels[entry]["meshifyName"], day[entry], timestamp)
go_channels[entry]["last_value"] = day[entry]
def checkLatestCard(self):
latest = requests.get(self.device_address + "/json/latest")
latest = json.loads(latest.text)
folder = str(latest["folder"])
file = latest["file"].replace(".csv", "")
# check the card to see if its new
# 1. if its new send the folder/file_name to the card_history channel
# 2. if its new and its been 10 minutes since you last sent an entire card, then send up all of the data
if channels["card_history"]["last_value"] != (folder + "/" + file):
# we have a new card
# get the data for this event
data = json.loads(requests.get(self.device_address + "/json/" + folder + "/" + file).text)
dateTime = str(data["card_data"]["Stroke_Time"])
# timestamp = time.mktime(time.strptime(dateTime, '%Y-%m-%dT%H:%M:%S.%fZ'))
reg = "(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})"
fd = re.search(reg, dateTime)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)))
timestamp = calendar.timegm(dt.timetuple())
card_timestamp = int(time.mktime(dt.timetuple()))
print "New card detected @ {0}".format(datetime.strftime(datetime.fromtimestamp(timestamp), "%Y-%m-%d %H:%M:%S.%f"))
# set the last value = to current value and upload your data
channels["card_history"]["last_value"] = (folder + "/" + file)
self.sendtodb("card_history", (folder + "/" + file), timestamp)
# check the last time the card was updated
if (time.time() - int(channels["card_history"]["last_time_uploaded"])) > self.cardLoopTimer or self.statusChanged or self.forceSend:
# its been 10 minutes, send the full upload
print "Either status has changed or last stored card is too old."
channels["card_history"]["last_time_uploaded"] = time.time()
self.process_card(data, timestamp, card_timestamp, sendCards=True)
return
else:
self.process_card(data, timestamp, card_timestamp, sendCards=False)
def process_card(self, data, data_timestamp, card_timestamp, sendCards=False):
# if sendCards = True then we upload all data no matter what, including cards
# check what type of data it is
# check if its changed, if it has, how long has it been since it changed
# NOTE: the initial vaue of "" is given to all channels in the channels object,
# so to avoid comparing a string to a float, and to make sure on startup we send all of the values, the first time through we send everything that has a "" as its last value
# We don't want to store any data on starting, just the cards
if self.status != 'Starting':
for channel in data["card_data"]:
# if channels.has_key(channel):
if channel in channels:
if channels[channel]["data_type"] == "str":
if (data["card_data"][channel] != channels[channel]["last_value"] and ((time.time() - int(channels[channel]["last_time_uploaded"])) > int(channels[channel]["min_time_between_uploads"]))) or sendCards:
print "new value for: ", channel
print data["card_data"][channel]
self.sendtodb(channel, str(data["card_data"][channel]), int(data_timestamp))
channels[channel]["last_value"] = data["card_data"][channel]
channels[channel]["last_time_uploaded"] = time.time()
if channels[channel]["data_type"] == "float" or channels[channel]["data_type"] == "int":
if channels[channel]["last_value"] == "":
# print "first time getting data"
print "new value for: ", channel
print data["card_data"][channel]
self.sendtodb(channel, str(data["card_data"][channel]), int(data_timestamp))
channels[channel]["last_value"] = data["card_data"][channel]
channels[channel]["last_time_uploaded"] = time.time()
if (abs(float(data["card_data"][channel]) - float(channels[channel]["last_value"])) > channels[channel]["change_amount"] and ((time.time() - int(channels[channel]["last_time_uploaded"])) > int(channels[channel]["min_time_between_uploads"]))) or sendCards:
# print "first time getting data"
print "new value for: ", channel
print data["card_data"][channel]
self.sendtodb(channel, str(data["card_data"][channel]), int(data_timestamp))
channels[channel]["last_value"] = data["card_data"][channel]
channels[channel]["last_time_uploaded"] = time.time()
if sendCards:
s_p = data["card_data"]["Surface_Position"]
s_l = data["card_data"]["Surface_Load"]
d_p = data["card_data"]["Downhole_Position"]
d_l = data["card_data"]["Downhole_Load"]
newSc = "["
newDc = "["
for i in range(len(s_p)):
try:
if s_p[i] is None:
continue
if s_p[i] != 0.0 and s_l[i] != 0.0:
newSc += "[" + str(s_p[i]) + ", " + str(s_l[i]) + "], "
except:
pass
newSc += "[" + str(s_p[0]) + ", " + str(s_l[0]) + "]"
newSc += "]"
for i in range(len(d_p)):
try:
if d_p[i] is None:
continue
if d_p[i] != 0.0 and d_l[i] != 0.0:
newDc += "[" + str(d_p[i]) + ", " + str(d_l[i]) + "], "
except:
pass
newDc += "[" + str(d_p[0]) + ", " + str(d_l[0]) + "]"
newDc += "]"
self.sendtodb("sc", newSc, card_timestamp)
self.sendtodb("dc", newDc, card_timestamp)
def getLatestXCards(self, numCards):
data = json.loads(requests.get(self.device_address + "/json/latest/" + str(int(numCards))).text)
for card in data['cards']:
card_data = json.loads(requests.get(self.device_address + "/json/" + data['folder'] + "/" + card).text)
dateTime = str(card_data["card_data"]["Stroke_Time"])
# timestamp = time.mktime(time.strptime(dateTime,'%Y-%m-%dT%H:%M:%S.%fZ'))
reg = "(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})"
fd = re.search(reg, dateTime)
dt = datetime(int(fd.group(1)), int(fd.group(2)), int(fd.group(3)), int(fd.group(4)), int(fd.group(5)), int(fd.group(6)))
timestamp = calendar.timegm(dt.timetuple())
card_timestamp = int(time.mktime(dt.timetuple()))
channels["card_history"]["last_value"] = (data['folder'] + "/" + card)
self.sendtodb("card_history", (data['folder'] + "/" + card), card_timestamp)
self.process_card(card_data, timestamp, card_timestamp, sendCards=True)
def getDataLoggerStatus(self):
data = json.loads(requests.get(self.device_address + "/json/pythonstatus/").text)
al_status = "Not OK"
if data['status']['alarmLogger']:
al_status = "OK"
if al_status != self.al_status_last:
self.sendtodb("alarmlogger_status", al_status, 0)
self.al_status_last = al_status
dl_status = "Not OK"
if data['status']['dataLogger']:
dl_status = "OK"
if al_status != self.dl_status_last:
self.sendtodb("datalogger_status", dl_status, 0)
self.dl_status_last = dl_status
def poc_get_card(self, name, value):
self.getcard(value)
def poc_sync(self, name, value):
self.sendtodb("connected", "true", 0)
return True
def poc_set_address(self, name, value):
self.device_address = value
return True
def poc_refresh_data(self, name, value):
self.forceSend = True
return True