commit a7a5955723173010f24ffd069ae02ccdb92d9a3c Author: Christian Steinle Date: Fri May 3 11:27:58 2024 +0200 Initial commit to aggregate values and show monthly overviews. diff --git a/bootstrap.php b/bootstrap.php new file mode 100644 index 0000000..ca8cf24 --- /dev/null +++ b/bootstrap.php @@ -0,0 +1,12 @@ + $config, + 'remote_db' => $remote_db, + 'local_db' => $local_db +]; \ No newline at end of file diff --git a/config/config.php b/config/config.php new file mode 100644 index 0000000..ed9715a --- /dev/null +++ b/config/config.php @@ -0,0 +1,26 @@ +query($first_date_query); + $first_date = new DateTime($first_date_result->fetch_column(0)); + + $last_date_query = 'SELECT MAX(date) FROM ' . $table . ';'; + $last_date_result = $db->query($last_date_query); + $last_date = new DateTime($last_date_result->fetch_column(0)); + + $first_date->modify('first day of this month'); + $last_date->modify('first day of this month'); + + $dates = []; + + for ($date = $last_date; $date >= $first_date; $date = $date->modify('-1 month')) { + $dates[] = $date->format('Y-m'); + } + + return $dates; +} + +function get_aggregation(mysqli $db, string $table, $date): array +{ + $value_query = 'SELECT date, meter_consumption, power_sensor, grid_feed FROM ' . $table . ' WHERE date LIKE "' . $date . '%" ORDER BY date ASC;'; + $value_result = $db->query($value_query); + + $values = []; + while ($row = $value_result->fetch_assoc()) { + $values['date'][] = $row['date']; + $values['meter_consumption'][] = $row['meter_consumption']; + $values['power_sensor'][] = $row['power_sensor']; + $values['grid_feed'][] = $row['grid_feed']; + $values['min_meter'] = (isset($values['min_meter']) && $values['min_meter'] < $row['meter_consumption']) ? $values['min_meter'] : $row['meter_consumption']; + $values['max_meter'] = (isset($values['max_meter']) && $values['max_meter'] > $row['meter_consumption']) ? $values['max_meter'] : $row['meter_consumption']; + $values['avg_meter'] += $row['meter_consumption']; + $values['min_power'] = (isset($values['min_power']) && $values['min_power'] < $row['power_sensor']) ? $values['min_power'] : $row['power_sensor']; + $values['max_power'] = (isset($values['max_power']) && $values['max_power'] > $row['power_sensor']) ? $values['max_power'] : $row['power_sensor']; + $values['avg_power'] += $row['power_sensor']; + $values['min_feed'] = (isset($values['min_feed']) && $values['min_feed'] < $row['grid_feed']) ? $values['min_feed'] : $row['grid_feed']; + $values['max_feed'] = (isset($values['max_feed']) && $values['max_feed'] > $row['grid_feed']) ? $values['max_feed'] : $row['grid_feed']; + $values['avg_feed'] += $row['grid_feed']; + } + + $values['avg_meter'] /= count($values['meter_consumption']); + $values['avg_power'] /= count($values['power_sensor']); + $values['avg_feed'] /= count($values['grid_feed']); + + return $values; +} + +function get_month_aggregation(mysqli $db, string $table, $date): array +{ + $sum_query = 'SELECT SUM(meter_consumption) / 1000 as meter_consumption, SUM(power_sensor) / 1000 as power_sensor, SUM(grid_feed) / 1000 as grid_feed FROM ' . $table . ' WHERE date LIKE "' . $date . '%";'; + $sum_result = $db->query($sum_query); + + return $sum_result->fetch_assoc(); +} + +function get_year_aggregation(mysqli $db, string $table, $date): array +{ + $year = substr($date, 0, 4); + $sum_query = 'SELECT SUM(meter_consumption) / 1000 as meter_consumption, SUM(power_sensor) / 1000 as power_sensor, SUM(grid_feed) / 1000 as grid_feed FROM ' . $table . ' WHERE date LIKE "' . $year . '%";'; + $sum_result = $db->query($sum_query); + + return $sum_result->fetch_assoc(); +} + +function get_grid_feed_by_month(mysqli $db, string $table_aggregation, string $table_production, $date): array +{ + $year = substr($date, 0, 4); + $feed_query = 'SELECT SUM(grid_feed), YEAR(date) as year, MONTH(date) as month FROM ' . $table_aggregation . ' WHERE date LIKE "' . $year . '%" GROUP BY YEAR(date), MONTH(date);'; + $feed_result = $db->query($feed_query); + + $price_query = 'SELECT YEAR(date) as year, MONTH(date) as month, price FROM ' . $table_production . ' WHERE date LIKE "' . $year . '%";'; + $price_result = $db->query($price_query); + + $price = []; + while ($row = $price_result->fetch_assoc()) { + $price[$row['year'] . '-' . str_pad($row['month'], 2, '0', STR_PAD_LEFT)] = $row['price']; + } + + $grid_feed_by_month = []; + + while ($row = $feed_result->fetch_assoc()) { + $grid_feed_by_month[$row['year'] . '-' . str_pad($row['month'], 2, '0', STR_PAD_LEFT)] = $row['SUM(grid_feed)'] * $price[$row['year'] . '-' . str_pad($row['month'], 2, '0', STR_PAD_LEFT)] / 100000; + } + + return $grid_feed_by_month; +} + +function get_month_production(mysqli $db, string $table, $date): array +{ + $sum_query = 'SELECT eg, og, price FROM ' . $table . ' WHERE date LIKE "' . $date . '%";'; + $sum_result = $db->query($sum_query); + if ($sum_result->num_rows === 0) { + return ['eg' => 0, 'og' => 0, 'price' => 0]; + } + + return $sum_result->fetch_assoc(); +} + +function get_year_production(mysqli $db, string $table, $date): array +{ + $year = substr($date, 0, 4); + $sum_query = 'SELECT SUM(eg) as eg, SUM(eg * price) / 100 as eg_price, SUM(og) as og, SUM(og * price) / 100 as og_price FROM ' . $table . ' WHERE date LIKE "' . $year . '%";'; + $sum_result = $db->query($sum_query); + + return $sum_result->fetch_assoc(); +} \ No newline at end of file diff --git a/jobs/aggregate.php b/jobs/aggregate.php new file mode 100644 index 0000000..b5bc4af --- /dev/null +++ b/jobs/aggregate.php @@ -0,0 +1,64 @@ +query($latest_date_query); +$latest_date = new DateTime($latest_date_result->fetch_column(0)); + +$date_yesterday = new DateTime(); +$date_yesterday->modify('-1 day')->modify('0:00'); +$interval = $date_yesterday->diff($latest_date); + +for ($date_diff = $interval->days; $date_diff > 0; $date_diff--) { + $date = new DateTime(); + $date->modify('-' . $date_diff . ' day'); + $date->modify('0:00'); + + $day_start = $date->getTimestamp() * 1000; + $day_end = ($date->getTimestamp() + $day_seconds) * 1000; + + // electric_meter is the meter reading in Wh. + // The daily consumption ist the last minus the first value of a day + $query_consumption_end = 'SELECT value FROM ' . $remote_table . ' WHERE channel_id = ' . $app['config']['remote']['electric_meter'] . ' AND timestamp < ' . $day_end . ' ORDER BY timestamp DESC LIMIT 1;'; + $query_consumption_start = 'SELECT value FROM ' . $remote_table . ' WHERE channel_id = ' . $app['config']['remote']['electric_meter'] . ' AND timestamp > ' . $day_start . ' ORDER BY timestamp ASC LIMIT 1;'; + + $result = $remote_db->query($query_consumption_end); + $tmp = $result->fetch_assoc(); + $consumption_end = (float)$tmp['value']; + $result = $remote_db->query($query_consumption_start); + $tmp = $result->fetch_assoc(); + $consumption_start = (float)$tmp['value']; + + // power_sensor is the actual consumption in W. + $query_grid_feed = 'SELECT timestamp, value FROM ' . $remote_table . ' WHERE channel_id = ' . $app['config']['remote']['power_sensor'] . ' AND timestamp < ' . $day_end . ' AND timestamp > ' . $day_start . ' ORDER BY timestamp ASC;'; + $result = $remote_db->query($query_grid_feed); + $last = null; + $power_sensor = 0; + while ($query_grid_data = $result->fetch_assoc()) { + if (!is_null($last)) { + $time_diff = $query_grid_data['timestamp'] - $last['timestamp']; + $power_sensor += $last['value'] * $time_diff; + } + $last = $query_grid_data; + } + + $power_sensor /= 3600000; // 3600000 milliseconds per hour + $meter_consumption = $consumption_end - $consumption_start; + $grid_feed = $meter_consumption - $power_sensor; + + if ($grid_feed < 0) { + $grid_feed = 0; + } + + $aggregation_query = 'INSERT INTO ' . $local_table . ' (`date`, `meter_consumption`, `power_sensor`, `grid_feed`, `last_value`) VALUES ("' . $date->format('Y-m-d') . '", ' . $meter_consumption . ', ' . $power_sensor . ', ' . $grid_feed . ', ' . $consumption_end . ');'; + + $local_db->query($aggregation_query); +} diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..5641bc1 --- /dev/null +++ b/public/index.php @@ -0,0 +1,218 @@ +query($check_query); + if ($check_result->num_rows === 0) { + $query = 'INSERT INTO ' . $table_production . ' (date, eg, og, price) VALUES ("' . $_POST['date'] . '-01", ' . $_POST['eg'] . ', ' . $_POST['og'] . ', ' . $_POST['price'] . ');'; + } else { + $query = 'UPDATE ' . $table_production . ' SET eg = "' . $_POST['eg'] . '", og = "' . $_POST['og'] . '", price = "' . $_POST['price'] . '" WHERE date = "' . $_POST['date'] . '-01";'; + } + $local_db->query($query); +} + +$dates = build_date_dropdown($local_db, $table_aggregation); +$chosen_date = (isset($_POST['date'])) ? $_POST['date'] : $dates[0]; +$data = get_aggregation($local_db, $table_aggregation, $chosen_date); +$month_values = get_month_aggregation($local_db, $table_aggregation, $chosen_date); +$year_values = get_year_aggregation($local_db, $table_aggregation, $chosen_date); +$grid_feed_by_month = get_grid_feed_by_month($local_db, $table_aggregation, $table_production, $chosen_date); +$month_production = get_month_production($local_db, $table_production, $chosen_date); +$year_production = get_year_production($local_db, $table_production, $chosen_date); + +$colors = ['#375BEB', '#90EB36', '#EB5F36', '#DAE32D']; + +?> + + + + Consumption values + + + +
+ +
+ +
+ + + + + + + + + +
+ +
+ + + Monat + Jahr + Min + Max + Durchschnitt +
+ +
+ + + KWh + KWh + KWh + KWh + KWh +
+ +
+ + + KWh + KWh + KWh + KWh + KWh +
+ +
+ + + KWh + KWh + KWh + KWh + KWh +
+ +
+ + + KWh + KWh + + + kWh +
+ +
+ + + KWh + KWh + + + kWh +
+ +
+ + + + +
+ +
+ + + 0) ? number_format(100 - $month_values['grid_feed'] * 100 / ($month_production['eg'] + $month_production['og']), 2, ',', '.') : 0; ?> % + % +
+ +
+ +
+ + + + +