added min/max/avg/consumption calculations to MeterInterpreter

improved performance
This commit is contained in:
Steffen Vogel 2011-02-25 20:08:08 +01:00
parent b2b6f357a9
commit 9445fb8ca0
10 changed files with 72 additions and 63 deletions

View file

@ -78,7 +78,7 @@ class AggregatorInterpreter {
* @todo to be implemented
* @return array of values
*/
public function getValues($tuples = NULL, $groupBy = NULL) {
public function processData($tuples = NULL, $groupBy = NULL) {
}

View file

@ -43,6 +43,8 @@ abstract class Interpreter {
protected $from;
protected $to;
protected $rows;
/**
* Constructor
@ -72,7 +74,7 @@ abstract class Interpreter {
* @param string|integer $groupBy
* @return Volkszaehler\DataIterator
*/
protected function getData($tuples = NULL, $groupBy = NULL) {
protected function getData($count = NULL, $groupBy = NULL) {
// prepare sql
$sql['from'] = ' FROM data';
$sql['where'] = ' WHERE channel_id = ?' . self::buildDateTimeFilterSQL($this->from, $this->to);
@ -90,17 +92,17 @@ abstract class Interpreter {
}
// get total row count for grouping
$rowCount = $this->conn->fetchColumn($sql['rowCount'], array($this->channel->getId()), 0);
$this->rows = $this->conn->fetchColumn($sql['rowCount'], array($this->channel->getId()), 0);
// query for data
$stmt = $this->conn->executeQuery('SELECT ' . $sql['fields'] . $sql['from'] . $sql['where'] . $sql['groupBy'] . $sql['orderBy'], array($this->channel->getId()));
// return iterators
if ($sql['groupBy'] || is_null($tuples) || $rowCount < $tuples) {
return new Iterator\DataIterator($stmt, $rowCount);
if ($sql['groupBy'] || is_null($count) || $this->rows < $count) {
return new Iterator\DataIterator($stmt, $this->rows);
}
else {
return new Iterator\DataAggregationIterator($stmt, $rowCount, $tuples);
return new Iterator\DataAggregationIterator($stmt, $this->rows, $count);
}
}

View file

@ -64,8 +64,8 @@ class DataAggregationIterator implements \Iterator, \Countable {
$current[2] += $tuple[2];
}
$this->current = $current;
$this->key++;
return $this->current = $current;
}
public function rewind() {
@ -75,7 +75,7 @@ class DataAggregationIterator implements \Iterator, \Countable {
for ($i = 0; $i < $skip; $i++) {
$this->iterator->next();
}
$this->next();
return $this->next();
}
public function valid() {
@ -91,4 +91,4 @@ class DataAggregationIterator implements \Iterator, \Countable {
public function current() { return $this->current; }
}
?>
?>

View file

@ -24,7 +24,6 @@
namespace Volkszaehler\Interpreter\Iterator;
use Volkszaehler\Util;
use Doctrine\DBAL;
/**
@ -32,7 +31,7 @@ use Doctrine\DBAL;
* @package default
*/
class DataIterator implements \Iterator, \Countable {
protected $current;
protected $current; // the current data
protected $key; // key
protected $stmt; // PDOStatement
protected $size; // total readings in PDOStatement
@ -45,7 +44,6 @@ class DataIterator implements \Iterator, \Countable {
*/
public function __construct(\PDOStatement $stmt, $size) {
$this->size = $size;
$this->stmt = $stmt;
$this->stmt->setFetchMode(\PDO::FETCH_NUM);
}
@ -62,7 +60,7 @@ class DataIterator implements \Iterator, \Countable {
*/
public function next() {
$this->key++;
$this->current = $this->stmt->fetch();
return $this->current = $this->stmt->fetch();
}
/**
@ -87,13 +85,16 @@ class DataIterator implements \Iterator, \Countable {
*/
public function rewind() {
$this->key = 0;
$this->current = $this->stmt->fetch();
return $this->current = $this->stmt->fetch();
}
/**
* Get total num of rows
* @return integer
*/
public function count() { return $this->size; }
public function count() {
return $this->size;
}
}
?>
?>

View file

@ -35,50 +35,43 @@ use Volkszaehler\Util;
class MeterInterpreter extends Interpreter {
protected $min = NULL;
protected $max = NULL;
protected $consumption = NULL;
protected $resolution;
/**
* Calculates the consumption for interval speciefied by $from and $to
*
* @todo improfve workaround
* Calculates the consumption
* @return float total consumption
*/
public function getConsumption() {
$sql = 'SELECT COUNT(*) FROM `data` WHERE `channel_id` = ?' . parent::buildDateTimeFilterSQL($this->from, $this->to);
return $this->conn->fetchColumn($sql, array($this->channel->getId()), 0) / $this->channel->getProperty('resolution'); // return KWh
if (is_null($this->consumption)) throw new \Excpetion('Data has to be processed first!');
return $this->consumption / $this->resolution;
}
/**
* Get minimum
* @return array (0 => timestamp, 1 => value)
* @todo reimplement according to new env
*/
public function getMin() {
/*$data = $this->getData();
$min = current($data);
foreach ($data as $reading) {
if ($reading['value '] < $min['value']) {
$min = $reading;
}
}
return $min;*/
if (is_null($this->min)) throw new \Excpetion('Data has to be processed first!');
return $this->min;
}
/**
* Get maximum
* @return array (0 => timestamp, 1 => value)
* @todo reimplement according to new env
*/
public function getMax() {
/*$data = $this->getData();
$max = current($data);
foreach ($data as $reading) {
if ($reading['value '] > $max['value']) {
$max = $reading;
}
}
return $max;*/
if (is_null($this->max)) throw new \Excpetion('Data has to be processed first!');
return $this->max;
}
/**
* Get Average
* @return float
*/
public function getAverage() {
@ -92,21 +85,37 @@ class MeterInterpreter extends Interpreter {
* @todo untested
* @return array with timestamp, values, and pulse count
*/
public function getValues($tuples, $groupBy, $callback) {
$pulses = parent::getData($tuples, $groupBy);
public function processData($count, $groupBy, $callback) {
$this->resolution = $this->channel->getProperty('resolution');
$this->consumption = 0;
$pulses = parent::getData($count, $groupBy);
$values = array();
foreach ($pulses as $pulse) {
if (isset($last)) {
$values[] = $callback($this->raw2differential($last, $pulse));
$last = $pulse;
$tuples = array();
$last = $pulses->rewind();
$next = $pulses->next();
$next = $pulses->current();
while ($pulses->valid()) {
Util\Debug::log('after valid()', $last, $next);
$tuple = $callback($this->raw2differential($last, $next));
if (is_null($this->max) || $tuple[1] > $this->max[1]) {
$this->max = $tuple;
}
else {
$last = $pulse;
if (is_null($this->min) || $tuple[1] < $this->min[1]) {
$this->min = $tuple;
}
$this->consumption += $tuple[2];
$tuples[] = $tuple;
$last = $next;
$next = $pulses->next();
}
return $values;
return $tuples;
}
/**
@ -120,8 +129,8 @@ class MeterInterpreter extends Interpreter {
return array(
($next[0] - $delta / 2), // timestamp
$next[1] * (3600000 / (($this->channel->getProperty('resolution') / 1000) * $delta)), // value
$next[2]
$next[1] * (3600000 / (($this->resolution / 1000) * $delta)), // value
$next[2] // num of pulses
);
}
}

View file

@ -34,10 +34,9 @@ use Volkszaehler\Util;
class SensorInterpreter extends Interpreter {
/**
* @todo untested
* @param string|integer $groupBy
*/
public function getValues($tuples, $groupBy, $callback) {
public function processData($tuples, $groupBy, $callback) {
$data = parent::getData($tuples, $groupBy);
$values = array();

View file

@ -117,7 +117,7 @@ class CSV extends View {
protected function addData(Interpreter\Interpreter $interpreter) {
//$this->response->setHeader('Content-Disposition', 'attachment; filename="' . strtolower($interpreter->getEntity()->getProperty('title')) . '.csv"'); // TODO add time?
$tuples = $interpreter->getValues(
$tuples = $interpreter->processData(
$this->request->getParameter('tuples'),
$this->request->getParameter('group'),
function($tuple) {

View file

@ -213,7 +213,7 @@ class JSON extends View {
protected function addData($interpreter) {
$this->json['data']['uuid'] = $interpreter->getEntity()->getUuid();
$data = $interpreter->getValues(
$data = $interpreter->processData(
$this->request->getParameter('tuples'),
$this->request->getParameter('group'),
function($tuple) {

View file

@ -112,9 +112,7 @@ class JpGraph extends View {
$this->graph->xaxis->SetLabelAngle(45);
$this->graph->xaxis->SetLabelFormatCallback(function($label) { return date('j.n.y G:i', $label); });
if (function_exists('imageantialias')) {
$this->graph->img->SetAntiAliasing();
}
$this->graph->img->SetAntiAliasing(function_exists('imageantialias'));
}
/**
@ -144,7 +142,7 @@ class JpGraph extends View {
* @param $data
*/
public function addData(Interpreter\InterpreterInterface $interpreter){
$data = $interpreter->getValues($this->width/4);
$data = $interpreter->processData($this->width/4);
if (count($data) > 0) {
$count = count($this->channels);

View file

@ -205,7 +205,7 @@ class XML extends View {
$xmlData = $this->xmlDoc->createElement('data');
$xmlTuples = $this->xmlDoc->createElement('tuples');
$data = $interpreter->getValues(
$data = $interpreter->processData(
$this->request->getParameter('tuples'),
$this->request->getParameter('group'),
function($tuple) use ($xmlDoc, $xmlTuples) {