Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A process to manipulate feeds through arithmetic operation #8

Merged
merged 9 commits into from
Feb 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions common.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

function getmeta($dir,$id)
{
if (!file_exists($dir.$id.".meta")) {
print "input file $id.meta does not exist\n";
return false;
}

$meta = new stdClass();
$metafile = fopen($dir.$id.".meta", 'rb');
fseek($metafile,8);
Expand All @@ -27,3 +32,27 @@ function createmeta($dir,$id,$meta)
fwrite($metafile,pack("I",$meta->start_time));
fclose($metafile);
}

//compute meta datas of different feeds intended for a preprocessing
function compute_meta()
{
$numargs = func_num_args();
$arg_list = func_get_args();
$all_intervals=[];
$all_start_times=[];
$all_ending_times=[];
$meta=new stdClass();
for ($i = 0; $i < $numargs; $i++) {
$all_intervals[]=$arg_list[$i]->interval;
$all_start_times[]=$arg_list[$i]->start_time;
$all_ending_times[]=$arg_list[$i]->start_time+$arg_list[$i]->npoints*$arg_list[$i]->interval;
}
$meta->interval=max($all_intervals);
$meta->start_time=floor(max($all_start_times)/$meta->interval)*$meta->interval;
$meta->writing_end_time=min($all_ending_times);
//print("intervals.....");print_r($all_intervals);
//print("start_times....");print_r($all_start_times);
//print("ending_times.....");print_r($all_ending_times);
print("NOTICE : output interval=$meta->interval, start=$meta->start_time, end=$meta->writing_end_time \n");
return $meta;
}
86 changes: 86 additions & 0 deletions postprocess-module/postprocess_controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,24 @@ function postprocess_controller()
"input"=>array("type"=>"feed", "engine"=>5, "short"=>"Select input feed:"),
"maxrate"=>array("type"=>"value", "short"=>"Max accumulation rate:"),
"output"=>array("type"=>"newfeed", "engine"=>5, "short"=>"Enter output feed name:")
),
"liquidorairflow_tokwh"=>array(
"vhc"=>array("type"=>"value", "short"=>"volumetric heat capacity in Wh/m3/K"),
"flow"=>array("type"=>"feed", "engine"=>5, "short"=>"flow in m3/h"),
"tint"=>array("type"=>"feed", "engine"=>5, "short"=>"Internal temperature feed / start temperature feed :"),
"text"=>array("type"=>"feed", "engine"=>5, "short"=>"External temperature feed / return temperature feed :"),
"output"=>array("type"=>"newfeed", "engine"=>5, "short"=>"Enter output feed name for permeability losses in m3/h :")
),
"constantflow_tokwh"=>array(
"vhc"=>array("type"=>"value", "short"=>"volumetric heat capacity in Wh/m3/K"),
"flow"=>array("type"=>"value", "short"=>"constant flow in m3/h"),
"tint"=>array("type"=>"feed", "engine"=>5, "short"=>"Internal temperature feed / start temperature feed :"),
"text"=>array("type"=>"feed", "engine"=>5, "short"=>"External temperature feed / return temperature feed :"),
"output"=>array("type"=>"newfeed", "engine"=>5, "short"=>"Enter output feed name for permeability losses in m3/h :")
),
"basic_formula"=>array(
"formula"=>array("type"=>"formula", "short"=>"Enter your formula (e.g. f1+2*f2-f3/12 if you work on feeds 1,2,3) - brackets not implemented"),
"output"=>array("type"=>"newfeed", "engine"=>5, "short"=>"Enter output feed name :")
)
);

Expand Down Expand Up @@ -120,6 +138,39 @@ function postprocess_controller()
$valid = false;
}
}

if ($option['type']=="formula"){
$formula=$processlist[$i]->$key;
$f=[];
$f['expression']=$formula;
//we catch feed numbers in the formula
$feed_ids=[];
while(preg_match("/(f\d+)/",$formula,$b)){
$feed_ids[]=substr($b[0],1,strlen($b[0])-1);
$formula=str_replace($b[0],"",$formula);
}
$all_intervals=[];
$all_start_times=[];
$all_ending_times=[];
//we check feeds existence and stores all usefull metas
foreach($feed_ids as $id) {
if ($feed->exist((int)$id)){
$m=$feed->get_meta($id);
$all_intervals[]=$m->interval;
$all_start_times[]=$m->start_time;
$all_ending_times[]=$feed->get_timevalue($id)['time'];
} else {
$valid = false;
}
}
if ($valid){
$f['interval'] = max($all_intervals);
$f['start_time']= max($all_start_times);
$f['time']= min($all_ending_times);

$item->$key = $f;
}
}
}
} else {
$valid = false;
Expand Down Expand Up @@ -289,5 +340,40 @@ function postprocess_controller()
return array('content'=>$params);
}

if ($route->action == 'getlog') {
$route->format = "text";
$log_filename = "$homedir/data/postprocess.log";
if (file_exists($log_filename)) {
ob_start();
$handle = fopen($log_filename, "r");
$lines = 200;
$linecounter = $lines;
$pos = -2;
$beginning = false;
$text = array();
while ($linecounter > 0) {
$t = " ";
while ($t != "\n") {
if(!empty($handle) && fseek($handle, $pos, SEEK_END) == -1) {
$beginning = true;
break;
}
if(!empty($handle)) $t = fgetc($handle);
$pos --;
}
$linecounter --;
if ($beginning) {
rewind($handle);
}
$text[$lines-$linecounter-1] = fgets($handle);
if ($beginning) break;
}
foreach (array_reverse($text) as $line) {
echo $line;
}
$result = trim(ob_get_clean());
} else $result="no logging yet available";
}

return array('content'=>$result, 'fullwidth'=>false);
}
98 changes: 87 additions & 11 deletions postprocess-module/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,31 @@ $("#process_select").change(function(){

options += "<b>"+processes[process][z]["short"]+"</b><br>";
if (processes[process][z]["type"]=="feed") {
options += "<select class='process_option' option="+z+">";
for (var n in feeds) options += "<option value="+feeds[n].id+">"+feeds[n].name+"</option>";
options += "</select><br>";
options += "<select class='process_option' option="+z+">";
//for (var n in feeds) options += "<option value="+feeds[n].id+">"+feeds[n].name+"</option>";

var datatype = 1; // 0:UNDEFINED, 1:REALTIME, 2:DAILY, 3:HISTOGRAM
var feedgroups = [];
for (n in feeds) {
if (feeds[n].datatype == datatype) {
if (parseInt(feeds[n].engine) == 7) continue; // Dont list virtual feed
var group = (feeds[n].tag === null ? "NoGroup" : feeds[n].tag);
if (group!="Deleted") {
if (!feedgroups[group]) feedgroups[group] = []
feedgroups[group].push(feeds[n]);
}
}
}
var out = "<option value=-1>CHOOSE FEED:</option>";
for (n in feedgroups) {
out += "<optgroup label='"+n+"'>";
for (p in feedgroups[n]) {
out += "<option value="+feedgroups[n][p]['id']+">"+feedgroups[n][p].name+"</option>";
}
out += "</optgroup>";
}
options+=out;
options += "</select><br>";
}

if (processes[process][z]["type"]=="newfeed") {
Expand All @@ -40,8 +62,12 @@ $("#process_select").change(function(){
if (processes[process][z]["type"]=="value") {
options += "<input class='process_option' option="+z+" type='text' /><br>";
}

if (processes[process][z]["type"]=="formula") {
options += "<input class='process_option' option="+z+" type='text' /><br>";
}
}
$("#process_options").html(options);
$("#process_options").html(options);
validate();
});

Expand Down Expand Up @@ -78,6 +104,19 @@ function validate()
$(".process_option[option="+z+"]").css("background-color","#eeffee");
}
}

if (processes[process][z]["type"]=="formula") {
$(".process_option[option="+z+"]").css("width","400px");
var formula = $(".process_option[option="+z+"]").val();
var regex1 = /[^-\+\*\/\df]/;
var regex2 = /f/;
if (formula.match(regex1) || !formula.match(regex2)){
$(".process_option[option="+z+"]").css("background-color","#ffeeee");
valid = false;
} else {
$(".process_option[option="+z+"]").css("background-color","#eeffee");
}
}
}

if (valid) $("#create").show(); else $("#create").hide();
Expand Down Expand Up @@ -138,20 +177,53 @@ function processlist_update()
out += "<td>";
var base_npoints = 0;
var out_npoints = 0;

var fstart_time=[];
var ftime=[];
var finterval=[];
for (var key in processes[process]) {
out += "<div style='width:250px; float:left'><b>"+key+":</b>";
if (processes[process][key].type=="feed" || processes[process][key].type=="newfeed")
out += processlist[z][key].id+":"+processlist[z][key].name;
out += "</div>";

if (processes[process][key].type=="feed") {
base_npoints = processlist[z][key].npoints;
//if formula, should show it but in a wider div
//formula details are reduced to its expression
if (processes[process][key].type=="formula"){
out += "<div style='width:500px; float:left'><b>"+key+":</b>";
out += processlist[z][key].expression+"</div>";
//we should also extract the feeds from the formula
var myformula=processlist[z][key].expression;
var formula_feeds=[];
var delimiter=/f/;
while (delimiter.test(myformula)){
var regex = /(f\d+)/;
var found = myformula.match(regex);
var found_regex = new RegExp(found[0],'g');
myformula=myformula.replace(found_regex,"");
formula_feeds.push(found[0].substr(1,found[0].length-1));
}
//console.log("found:"+formula_feeds+"and formula is :"+myformula);
//feed details are id and name
} else {
out += "<div style='width:250px; float:left'><b>"+key+":</b>";
if (processes[process][key].type=="feed" || processes[process][key].type=="newfeed")
out += processlist[z][key].id+":"+processlist[z][key].name;
//if value, should print it
if (processes[process][key].type=="value")
out += processlist[z][key];
out += "</div>";
}

//rework by alexandre CUER
if (processes[process][key].type=="feed" || processes[process][key].type=="formula") {
//base_npoints = processlist[z][key].npoints;
fstart_time.push(processlist[z][key].start_time);
ftime.push(processlist[z][key].time);
finterval.push(processlist[z][key].interval);
}

if (processes[process][key].type=="newfeed") {
out_npoints = processlist[z][key].npoints;
}
}
//console.log(fstart_time);
base_npoints=Math.round((Math.min(...ftime)-Math.max(...fstart_time))/Math.max(...finterval));
out += "</td>";

var points_behind = base_npoints - out_npoints;
Expand Down Expand Up @@ -185,6 +257,10 @@ $("#processlist").on("click",".runprocess",function(){
if (processes[process][key].type=="value") {
params[key] = processlist[z][key];
}

if (processes[process][key].type=="formula") {
params[key] = processlist[z][key].expression;
}
}

$.ajax({
Expand Down
50 changes: 45 additions & 5 deletions postprocess-module/view.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
<?php global $path; ?>

<style>
</style>

<script type="text/javascript" src="<?php echo $path; ?>Modules/feed/feed.js"></script>
<br>
<h2>Post Processor</h2>

<style>
pre {
width:100%;
height:200px;
margin:0px;
padding:0px;
color:#fff;
background-color:#300a24;
overflow: scroll;
overflow-x: hidden;
}
</style>
<table class="table table-hover">
<tr><td colspan=2><h2>Post Processor</h2></td></tr>
<tr>
<td><h3>Logger</h3><p>on file /home/pi/data/postprocess.log</p></td>
<td class="buttons">
<button id="getlog" type="button" class="btn btn-info" data-toggle="button" aria-pressed="false" autocomplete="off"><?php echo _('Auto refresh'); ?></button>
</td>
</tr>
<tr><td colspan=2><pre id="logreply-bound"><div id="logreply"></div></pre></td></tr>
</table>
<p>Rather than process inputs as data arrives in emoncms such as calculating cumulative kWh data from power data with the power to kWh input process, this module can be used to do these kind of processing steps after having recorded base data such as power data for some time. This removes the reliance on setting up everything right in the first instance providing the flexibility to recalculate processed feeds at a later date.</p>

<h3>My processes</h3>
Expand Down Expand Up @@ -38,3 +55,26 @@
</script>

<script type="text/javascript" src="<?php echo $path; ?>Modules/postprocess/view.js"></script>
<script>
var logrunning = false;
var refresher_log;
function refresherStart(func, interval){
clearInterval(refresher_log);
refresher_log = null;
if (interval > 0) refresher_log = setInterval(func, interval);
}
getLog();
function getLog() {
$.ajax({ url: path+"postprocess/getlog", async: true, dataType: "text", success: function(result)
{
$("#logreply").html(result);
$("#logreply-bound").scrollTop = $("#logreply-bound").scrollHeight;
}
});
}
$("#getlog").click(function() {
logrunning = !logrunning;
if (logrunning) { refresherStart(getLog, 500); }
else { refresherStart(getLog, 0); }
});
</script>
Loading