{"id":1460,"date":"2023-12-09T19:24:36","date_gmt":"2023-12-09T18:24:36","guid":{"rendered":"https:\/\/caipirinha.spdns.org\/wp\/?p=1460"},"modified":"2024-08-02T19:30:16","modified_gmt":"2024-08-02T17:30:16","slug":"grafana-visualizations-part-1","status":"publish","type":"post","link":"https:\/\/caipirinha.spdns.org\/wp\/?p=1460","title":{"rendered":"Grafana Visualizations (Part 1)"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Executive Summary<\/h2>\n\n\n\n<p>In this article, we do first steps into visualizations in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> of data stored in a <a href=\"https:\/\/mariadb.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">MariaDB<\/a> database and draw conclusions from the visualizations. In this case, we look at meaningful data from <strong>solar power generation<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Preconditions<\/h2>\n\n\n\n<p>In order to use the approach described here, you should:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2026 have access to a Linux machine or account<\/li>\n\n\n\n<li>\u2026 have a&nbsp;<a href=\"https:\/\/www.mysql.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">MySQL<\/a>&nbsp;or&nbsp;<a href=\"https:\/\/mariadb.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">MariaDB<\/a>&nbsp;database server installed, configured, up and running<\/li>\n\n\n\n<li>\u2026 have a&nbsp;populated <a href=\"https:\/\/www.mysql.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">MySQL<\/a>&nbsp;or&nbsp;<a href=\"https:\/\/mariadb.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">MariaDB<\/a>&nbsp;database like in our example to which you have access<\/li>\n\n\n\n<li>\u2026 have the package&nbsp;<a href=\"https:\/\/grafana.com\/grafana\/download\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> [<a href=\"https:\/\/grafana.com\/grafana\/download\" target=\"_blank\" rel=\"noreferrer noopener\">2<\/a>] installed, configured, up and running<\/li>\n\n\n\n<li>\u2026 have some basic knowledge of how to operate in a Linux environment and some basic understanding of shell scripts<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Description and Usage<\/h2>\n\n\n\n<p>The base for the following visualizations is a fully populated database of the following structure:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Datenbank f\u00fcr Analysen der Solaranlage\n# V1.1; 2023-12-10, Gabriel R\u00fceck &lt;gabriel@rueeck.de&gt;, &lt;gabriel@caipirinha.spdns.org&gt;\n# Delete existing databases\nREVOKE ALL ON solaranlage.* FROM 'gabriel';\nDROP DATABASE solaranlage;\n\n# Create a new database\nCREATE DATABASE solaranlage DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\nGRANT ALL ON solaranlage.* TO 'gabriel';\nUSE solaranlage;\nSET default_storage_engine=Aria;\n\nCREATE TABLE anlage          (uid            INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,\\\n                              zeitstempel    TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\\\n                              leistung       INT UNSIGNED DEFAULT NULL,\\\n                              energie        INT UNSIGNED DEFAULT NULL);<\/code><\/pre>\n\n\n\n<p>[<a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=1450\" target=\"_blank\" rel=\"noreferrer noopener\">1<\/a>] explains how such a database can be filled with real-world data using smart home devices whose data is then stored in the database. For now, we assume that the database already is fully populated and contains large amount of data of the type:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MariaDB &#91;solaranlage]&gt; SELECT * FROM anlage LIMIT 20;\n+-----+---------------------+----------+---------+\n| uid | zeitstempel         | leistung | energie |\n+-----+---------------------+----------+---------+\n|   1 | 2023-05-02 05:00:08 |        0 | 5086300 |\n|   2 | 2023-05-02 05:15:07 |        0 | 5086300 |\n|   3 | 2023-05-02 05:30:07 |        0 | 5086300 |\n|   4 | 2023-05-02 05:45:07 |        0 | 5086300 |\n|   5 | 2023-05-02 06:00:07 |        0 | 5086300 |\n|   6 | 2023-05-02 06:15:07 |    12660 | 5086301 |\n|   7 | 2023-05-02 06:30:07 |    39830 | 5086307 |\n|   8 | 2023-05-02 06:45:08 |    44270 | 5086318 |\n|   9 | 2023-05-02 07:00:07 |    78170 | 5086333 |\n|  10 | 2023-05-02 07:15:07 |   187030 | 5086367 |\n|  11 | 2023-05-02 07:30:07 |   312630 | 5086424 |\n|  12 | 2023-05-02 07:45:08 |   665900 | 5086556 |\n|  13 | 2023-05-02 08:00:07 |   729560 | 5086733 |\n|  14 | 2023-05-02 08:15:08 |   573700 | 5086889 |\n|  15 | 2023-05-02 08:30:07 |   288030 | 5086985 |\n|  16 | 2023-05-02 08:45:07 |   444170 | 5087065 |\n|  17 | 2023-05-02 09:00:08 |   655880 | 5087217 |\n|  18 | 2023-05-02 09:15:07 |   974600 | 5087476 |\n|  19 | 2023-05-02 09:30:08 |  1219150 | 5087839 |\n|  20 | 2023-05-02 09:45:07 |   772690 | 5088024 |\n+-----+---------------------+----------+---------+\n20 rows in set (0,000 sec)\n<\/code><\/pre>\n\n\n\n<p>whereby the values in column <strong>leistung<\/strong> represent the current power generation in <em>mW<\/em> and the values in energy represent the accumulated <strong>energy<\/strong> in <em>Wh<\/em>.<\/p>\n\n\n\n<p>Now we shall visualize the data of the solar power generation in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a>. <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> is powerful and mighty visualization tool with which you can create state-of-the-art dashboards and professional visualizations. I must really laude the team behind <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> for making such a powerful tool free for personal and other usage (for details to their licenses und usage models, see <a href=\"https:\/\/grafana.com\/licensing\/\" target=\"_blank\" rel=\"noreferrer noopener\">Licensing | Grafana Labs<\/a>).<\/p>\n\n\n\n<p>Before you can use data from a MySQL database in Grafana, you have to set up MySQL as a data source in <strong>Connections<\/strong>. Remember that MySQL is one of many possible data sources for <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> and so, you have to walk through the jungle of offered data sources and find the MySQL connection and set up your data source accordingly. On my server, both <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> and <a href=\"https:\/\/mariadb.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">MariaDB<\/a> run on the same machine, so there is no need for encryption, etc. My setup simply looks like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"773\" height=\"826\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-7.png\" alt=\"\" class=\"wp-image-1468\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-7.png 773w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-7-281x300.png 281w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-7-768x821.png 768w\" sizes=\"auto, (max-width: 773px) 100vw, 773px\" \/><figcaption class=\"wp-element-caption\">MySQL connection setup in Grafana (local database)<\/figcaption><\/figure>\n\n\n\n<p>One step where I always stumble again is that in the entry mask for the connection setup, <em>localhost:3306<\/em> is proposed in grey color as Host, but unless you type that in, too, <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> will actually not use <em>localhost:3306<\/em>. So be sure to physically type that in.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Average Power per Month and Hour of the Day (I)<\/h3>\n\n\n\n<p>For this, we use the built-in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> visualization <strong><a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/visualizations\/table\/\" target=\"_blank\" rel=\"noreferrer noopener\">Table<\/a><\/strong>. We select the according database, and our MySQL query is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT MONTHNAME(zeitstempel) AS Monat, HOUR(zeitstempel) AS Stunde, ROUND(AVG(leistung)\/1000) AS Leistung\nFROM anlage\nGROUP BY Monat, Stunde\nORDER BY FIELD (Monat,'January','February','March','April','May','June','July','August','September','October','November','December'), Stunde ASC;<\/code><\/pre>\n\n\n\n<p>This query delivers us an ordered list of power values grouped and ordered by (the correct sequence of) month, and subsequently by the hour of the day as shown below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"486\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-5-1024x486.png\" alt=\"\" class=\"wp-image-1466\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-5-1024x486.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-5-300x142.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-5-768x364.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-5.png 1223w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Output of the MySQL query for the 2-dimensional table (view in the <a href=\"https:\/\/www.mysql.com\/products\/workbench\/\" target=\"_blank\" rel=\"noreferrer noopener\">MySQL Workbench<\/a>)<\/figcaption><\/figure>\n\n\n\n<p>However, this is not enough to get the table view we want in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> as the power values are still one-dimensional (only one value per line). We need to transpose the table with respect to the months, and therefore, we must select the built-in transformation <strong>Grouping to Matrix<\/strong> for this visualization and enter our column names according to the image below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"190\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-6-1024x190.png\" alt=\"\" class=\"wp-image-1467\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-6-1024x190.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-6-300x56.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-6-768x143.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-6.png 1361w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Required transformation for data in order to get a 2-dimensional table<\/figcaption><\/figure>\n\n\n\n<p>Now, in order to get a beautiful visualization, we need to adjust some of the <a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/configure-panel-options\/\" target=\"_blank\" rel=\"noreferrer noopener\">panel options<\/a>, and those are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Cell options \u2192 Cell type<\/strong>: Set to <strong>Colored background<\/strong><\/li>\n\n\n\n<li><strong>Standard options \u2192 Color scheme<\/strong>: Set to <strong>Green-Yellow-Red (by value)<\/strong><\/li>\n<\/ul>\n\n\n\n<p>and we need to define some <strong>Overrides<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Override 1 \u2192 Fields with name<\/strong>: Select <strong>Stunde\\Monat<\/strong><\/li>\n\n\n\n<li><strong>Override 1 \u2192 Cell options \u2192 Cell type<\/strong>: Set to <strong>Auto<\/strong><\/li>\n\n\n\n<li><strong>Override 2 \u2192 Fields with type<\/strong>: Select <strong>Number<\/strong><\/li>\n\n\n\n<li><strong>Override 2 \u2192 Standard options \u2192 Unit<\/strong>: Select <strong>Watt (W)<\/strong><\/li>\n<\/ul>\n\n\n\n<p>Then, ideally, you should see something like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"556\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Tabelle-P-1024x556.png\" alt=\"\" class=\"wp-image-1464\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Tabelle-P-1024x556.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Tabelle-P-300x163.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Tabelle-P-768x417.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Tabelle-P.png 1406w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Colored table of average power per month and hour of the day<\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Average Power per Month and Hour of the Day (II)<\/h3>\n\n\n\n<p>This visualization is similar to the one of the previous chapter. However, we slightly modify the MySQL query to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT MONTHNAME(zeitstempel) AS Monat, HOUR(zeitstempel) AS Stunde, ROUND(GREATEST((AVG(leistung)-STDDEV(leistung))\/1000,0.0)) AS '\u00d8-1\u03c3'\nFROM anlage\nGROUP BY Monat, Stunde\nORDER BY FIELD (Monat,'January','February','March','April','May','June','July','August','September','October','November','December'), Stunde ASC;<\/code><\/pre>\n\n\n\n<p>Doing so, we assume that there is some reasonable <a href=\"https:\/\/en.wikipedia.org\/wiki\/Normal_distribution\" target=\"_blank\" rel=\"noreferrer noopener\">normal distribution<\/a> in the timeframe of one month among the values in the same hourly time interval which, strictly speaking, is not true. Further below, we will look into this assumption. Using this unproven assumption, if we subtract 1\u03c3 from the average power value and use the resulting value or zero (whichever is higher), then we come to a value where we can say: &#8220;Probably (84%), in this month and in this hour, we generate at least <em>x<\/em> watts of power.&#8221; So if someone was looking, for example, for an answer to the question on &#8220;When would be the best hour to start the washing machine and ideally use my solar energy for it?&#8221;, then, in June, this would be somewhen between 10:00&#8230;12:00, but in September, it might be 11:00&#8230;13:00, a detail which we might not have uncovered in the visualization of the previous chapter. Of course, you might argue that common sense (&#8220;Look out of the window and turn on the washing machine when the sun is shining.&#8221;) makes most sense, and that is true in our example. However, for automated systems that must run daily, such information might be valuable.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"549\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Tabelle-P-\u03c3-1024x549.png\" alt=\"\" class=\"wp-image-1471\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Tabelle-P-\u03c3-1024x549.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Tabelle-P-\u03c3-300x161.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Tabelle-P-\u03c3-768x412.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Tabelle-P-\u03c3.png 1405w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Colored table of (average power &#8211; 1\u03c3) per month and hour of the day<\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Heatmap of the Hourly and Daily Power Generation<\/h3>\n\n\n\n<p>For this, we use the plug-in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> visualization <strong><a href=\"https:\/\/grafana.com\/grafana\/plugins\/marcusolsson-hourly-heatmap-panel\/\" target=\"_blank\" rel=\"noreferrer noopener\">Hourly heatmap<\/a><\/strong>. We select the according database, and our MySQL query is very simple:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT UNIX_TIMESTAMP(zeitstempel) AS time, ROUND(leistung\/1000) AS power FROM anlage;<\/code><\/pre>\n\n\n\n<p>This time, there is also no need for any transformation, but again, we should adjust some <a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/configure-panel-options\/\" target=\"_blank\" rel=\"noreferrer noopener\">panel options<\/a> in order to beautify our graph, and these are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Hourly heatmap \u2192 From<\/strong>: Set to <strong>05:00<\/strong><\/li>\n\n\n\n<li><strong>Hourly heatmap \u2192 To<\/strong>: Set to <strong>23:00<\/strong><\/li>\n\n\n\n<li><strong>Hourly heatmap \u2192 Group by<\/strong>: Select <strong>60 minutes<\/strong><\/li>\n\n\n\n<li><strong>Hourly heatmap \u2192 Calculation<\/strong>: Select <strong>Mean<\/strong><\/li>\n\n\n\n<li><strong>Hourly heatmap \u2192 Color palette<\/strong>: Select <strong>Spectral<\/strong><\/li>\n\n\n\n<li><strong>Hourly heatmap \u2192 Invert color palette<\/strong>: (enabled)<\/li>\n\n\n\n<li><strong>Legend \u2192 Gradient quality<\/strong>: Select <strong>Low<\/strong> (it already computes long enough in <strong>Low<\/strong> mode)<\/li>\n\n\n\n<li><strong>Standard options \u2192 Unit<\/strong>: Select <strong>Watt (W)<\/strong><\/li>\n<\/ul>\n\n\n\n<p>Then, ideally, after some seconds, you should see something like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"102\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Heatmap-1024x102.png\" alt=\"\" class=\"wp-image-1465\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Heatmap-1024x102.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Heatmap-300x30.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Heatmap-768x76.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Heatmap-1536x152.png 1536w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Heatmap-2048x203.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Heatmap<\/figcaption><\/figure>\n\n\n\n<p>This visualization is time-consuming. Keep in mind that if you have large amounts of data, it might take several seconds until the graph build up. The <strong>Hourly Heatmap<\/strong> is also more detailed than the previous visualizations, and we can point with the mouse pointer on a certain rectangle and get to know the average power on this day and in this hour (if the database has at least one power value per hour). It even shows fluctuations occurring in one day only which might go unnoticed in the previous visualizations. We can realize, for example, that the lower average power which was generated in July this year was not because the sky is greyer in July than in other months, but that there were a few 2&#8230;3 days periods with clouded sky where the electricity generation dropped while other days were just perfectly sunny as in June or August. We can also see how the daylight hours dramatically decrease when we reach November.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Daily Energy Generation, split into Time Ranges<\/h3>\n\n\n\n<p>The next graph shall visualize the daily energy generation of the solar system over the time, and we split the day into 4 time ranges (morning, lunch, afternoon, evening). The 4 time ranges are not equally large, so you have to pay close attention to the description of the time range. Of course, you can easily change the MySQL query and adapt the time ranges to your own needs. We use the built-in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> visualization <a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/visualizations\/time-series\/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Time Series<\/strong><\/a>. We select the according database, and our MySQL query uses the timestamp and the energy values of the dataset. We also use the uid as we calculate the differences in the (ever increasing) energy value between two consecutive value sets in the dataset.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT DATE(past.zeitstempel) AS time,\n       CASE\n         WHEN (HOUR(past.zeitstempel)&lt;11) THEN '05:00-11:00'\n         WHEN (HOUR(past.zeitstempel)&gt;=11) AND (HOUR(past.zeitstempel)&lt;14) THEN '11:00-14:00'\n         WHEN (HOUR(past.zeitstempel)&gt;=14) AND (HOUR(past.zeitstempel)&lt;17) THEN '14:00-17:00'\n         WHEN (HOUR(past.zeitstempel)&gt;=17) THEN '17:00-22:00'\n       END AS metric,\n       SUM(IF(present.energie&gt;=past.energie,IF((present.energie-past.energie&lt;4000),(present.energie-past.energie),NULL),NULL)) AS value\nFROM anlage AS present INNER JOIN anlage AS past ON present.uid=past.uid+1\nGROUP BY time,metric;<\/code><\/pre>\n\n\n\n<p>In order to better understand the MySQL query, here are some explanations:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>We determine the time ranges in the form of a <strong>CASE<\/strong> statement in which we determine our time ranges and what shall be the textual output for a certain time range.<\/li>\n\n\n\n<li>We sum up the differences between consecutive energy values in the database over the respective time ranges. This is the task of the <strong>SUM<\/strong> operator.<\/li>\n\n\n\n<li>There might be missing energy values in the dataset, maybe because of network outages or (temporary) issues in the MySQL socket. The <strong>IF<\/strong> clauses inside the <strong>SUM<\/strong> operator help us to determine if the result of (present.energie-past.energie) would be negative (in case that present.energie is NULL) or if we have an unrealistic value (\u22654000) because past.energie is NULL. Such values will be skipped in the calculation.<\/li>\n\n\n\n<li>We consult the same tables (anlage) two times, one time named as present and one time named as past whereby past the dataset immediately before present is.<\/li>\n\n\n\n<li>Keep in mind that as time we use the value of <strong>past.zeitstempel<\/strong> so that we include the last value that still fits into the time range (although for the calculation of the energy difference, <strong>present.zeitstempe<\/strong>l would already be the next hour value, e.g.: (past.zeitstempel=16:45 and present.zeitstempel=17:00).<\/li>\n<\/ul>\n\n\n\n<p>We furthermore should adjust some <a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/configure-panel-options\/\" target=\"_blank\" rel=\"noreferrer noopener\">panel options<\/a> in order to beautify our graph, and these are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Graph styles \u2192 Fill opacity<\/strong>: Set to <strong>45%<\/strong><\/li>\n\n\n\n<li><strong>Graph styles \u2192 Stack Series<\/strong>: Select <strong>Normal<\/strong><\/li>\n\n\n\n<li><strong>Standard options \u2192 Unit<\/strong>: Select <strong>Watt-hour (Wh)<\/strong><\/li>\n\n\n\n<li><strong>Standard options \u2192 Min<\/strong>: Set to <strong>0<\/strong><\/li>\n\n\n\n<li><strong>Standard options \u2192 Decimals<\/strong>: Set to <strong>0<\/strong><\/li>\n\n\n\n<li><strong>Standard options \u2192 Color scheme<\/strong>: Select to <strong>Classic<\/strong> <strong>palette<\/strong><\/li>\n<\/ul>\n\n\n\n<p>On the left side, just above the code window, we have to switch from <strong>Table<\/strong> to <strong>Time Series<\/strong>:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"397\" height=\"128\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/grafik.png\" alt=\"Switch to the correct format for the graph.\" class=\"wp-image-1561\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/grafik.png 397w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/grafik-300x97.png 300w\" sizes=\"auto, (max-width: 397px) 100vw, 397px\" \/><figcaption class=\"wp-element-caption\">Do not forget to switch to the correct format.<\/figcaption><\/figure>\n\n\n\n<p>The graph should now look like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"210\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Stromerzeugung-nach-Zeitbereichen-1024x210.png\" alt=\"\" class=\"wp-image-1491\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Stromerzeugung-nach-Zeitbereichen-1024x210.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Stromerzeugung-nach-Zeitbereichen-300x62.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Stromerzeugung-nach-Zeitbereichen-768x158.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Stromerzeugung-nach-Zeitbereichen-1536x315.png 1536w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Stromerzeugung-nach-Zeitbereichen.png 1887w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Solar Energy according to Time Ranges<\/figcaption><\/figure>\n\n\n\n<p>There is one interesting characteristic of the built-in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> visualization <a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/visualizations\/time-series\/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Time Series<\/strong><\/a> which we make use of. If we edit the graph and select the Table view, we will see that <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> automatically has created a matrix from the results of our MySQL query.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"324\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-9-1024x324.png\" alt=\"\" class=\"wp-image-1492\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-9-1024x324.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-9-300x95.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-9-768x243.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/image-9.png 1406w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Matrix for the stacked Time Series<\/figcaption><\/figure>\n\n\n\n<p>This is astonishing because the MySQL query does not create the matrix itself, but rather delivers an output like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MariaDB &#91;solaranlage]&gt; SELECT DATE(past.zeitstempel) AS time,\n    -&gt;        CASE\n    -&gt;          WHEN (HOUR(past.zeitstempel)&lt;11) THEN '05:00-11:00'\n    -&gt;          WHEN (HOUR(past.zeitstempel)&gt;=11) AND (HOUR(past.zeitstempel)&lt;14) THEN '11:00-14:00'\n    -&gt;          WHEN (HOUR(past.zeitstempel)&gt;=14) AND (HOUR(past.zeitstempel)&lt;17) THEN '14:00-17:00'\n    -&gt;          WHEN (HOUR(past.zeitstempel)&gt;=17) THEN '17:00-22:00'\n    -&gt;        END AS metric,\n    -&gt;        SUM(IF(present.energie&gt;=past.energie,IF((present.energie-past.energie&lt;4000),(present.energie-past.energie),NULL),NULL)) AS value\n    -&gt; FROM anlage AS present INNER JOIN anlage AS past ON present.uid=past.uid+1\n    -&gt; GROUP BY time,metric\n    -&gt; LIMIT 15;\n+------------+-------------+-------+\n| time       | metric      | value |\n+------------+-------------+-------+\n| 2023-05-02 | 05:00-11:00 |  3588 |\n| 2023-05-02 | 11:00-14:00 |  4428 |\n| 2023-05-02 | 14:00-17:00 |  2524 |\n| 2023-05-02 | 17:00-22:00 |   375 |\n| 2023-05-03 | 05:00-11:00 |  4260 |\n| 2023-05-03 | 11:00-14:00 |  6047 |\n| 2023-05-03 | 14:00-17:00 |  2648 |\n| 2023-05-03 | 17:00-22:00 |   369 |\n| 2023-05-04 | 05:00-11:00 |  6326 |\n| 2023-05-04 | 11:00-14:00 |  5867 |\n| 2023-05-04 | 14:00-17:00 |  2568 |\n| 2023-05-04 | 17:00-22:00 |   477 |\n| 2023-05-05 | 05:00-11:00 |  3113 |\n| 2023-05-05 | 11:00-14:00 |  3496 |\n| 2023-05-05 | 14:00-17:00 |  1657 |\n+------------+-------------+-------+\n15 rows in set (0,197 sec)\n<\/code><\/pre>\n\n\n\n<p>I found out that this only works if metric is <strong>not<\/strong> a numerical value. For numerical values, the matrix would not be auto generated, the graph would not work like this. Maybe, an additional transformation in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> might then be necessary.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Detailed Examinations of the Dataset<\/h3>\n\n\n\n<p>Let us look closer to subsets of the dataset and visualize them, in order to get a better understanding of how the solar power generation behaves in reality at selected times.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Power Distribution between 12:00 and 13:00 (4 values per day)<\/h4>\n\n\n\n<p>For this, we use the built-in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> visualization <strong><a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/visualizations\/heatmap\/\" target=\"_blank\" rel=\"noreferrer noopener\">Heatmap<\/a><\/strong>. We select the according database, and our MySQL query is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT zeitstempel AS time, ROUND(leistung\/1000) AS 'Power' FROM anlage\nWHERE (HOUR(zeitstempel)=12);<\/code><\/pre>\n\n\n\n<p>Keep in mind that in my dataset, I register 4 samples per hour in the database. This is defined by the frequency of how often the script described in [<a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=1450\" target=\"_blank\" rel=\"noreferrer noopener\">1<\/a>] is executed, and this itself is defined in <a href=\"https:\/\/man7.org\/linux\/man-pages\/man5\/crontab.5.html\" target=\"_blank\" rel=\"noreferrer noopener\">crontab<\/a>. You can also have the script be executed every minute, and hence you will register 60 samples per hour in the database which will be more precise but put higher load on your server and on the evaluation of the data in MySQL queries. So, in my case,  in the time frame [12:00-13:00], we consider 4 power values, and we filter for these power values simply by looking at timestamps with the value &#8220;12&#8221; as the hour part. The Heatmap will give the distribution of these 4 power values per day. We must furthermore adjust some <a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/configure-panel-options\/\" target=\"_blank\" rel=\"noreferrer noopener\">panel options<\/a>, and these are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Heatmap \u2192 X Bucket<\/strong>: Select <strong>Size<\/strong> and set to <strong>24h<\/strong><\/li>\n\n\n\n<li><strong>Heatmap \u2192 Y Bucket<\/strong>: Select <strong>Size<\/strong> and set to <strong>Auto<\/strong><\/li>\n\n\n\n<li><strong>Heatmap \u2192 Y Bucket Scale<\/strong>: Select <strong>Linear<\/strong><\/li>\n\n\n\n<li><strong>Y Axis \u2192 Unit<\/strong>: Select <strong>Watt (W)<\/strong><\/li>\n\n\n\n<li><strong>Y Axis \u2192 Decimals<\/strong>: Set to <strong>1<\/strong><\/li>\n\n\n\n<li><strong>Y Axis \u2192 Min value<\/strong>: Set to <strong>0<\/strong><\/li>\n\n\n\n<li><strong>Colors \u2192 Mode<\/strong>: Select <strong>Scheme<\/strong><\/li>\n\n\n\n<li><strong>Colors \u2192 Scheme<\/strong>: Select <strong>Oranges<\/strong><\/li>\n\n\n\n<li><strong>Colors \u2192 Steps<\/strong>: Set to <strong>64<\/strong><\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"85\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-4-values-per-day-1024x85.png\" alt=\"\" class=\"wp-image-1479\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-4-values-per-day-1024x85.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-4-values-per-day-300x25.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-4-values-per-day-768x64.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-4-values-per-day-1536x128.png 1536w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-4-values-per-day-2048x170.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Power Distribution between 12:00 and 13:00 (4 values per day)<\/figcaption><\/figure>\n\n\n\n<p>With this Heatmap, we can immediately understand an important detail, and that is: If someone had the assumption that between [12:00-13:00], we generate a lot of power every day in summer, this would clearly be very wrong. In fact, we can recognize that the power generation varies from low to high values on many days. The reason is that even in summer, there are many cloudy days in the location where this solar power generator is located. This might not be true for a different location, and if we had data from Southern Europe (Portugal, Spain, Italy), this might look very different.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Average Power [12:00-13:00]<\/h4>\n\n\n\n<p>Now, we shall look at the average power generation between [12:00-13:00] over the year, using the 4 power values that we have register in this time interval every day. For this, we use the built-in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> visualization <a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/visualizations\/time-series\/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Time Series<\/strong><\/a>. We select the according database, and we use two MySQL queries (<strong>A<\/strong> and <strong>B)<\/strong>. Both curves will then be visualized in the diagram with different colors. Our query <strong>A<\/strong> calculates the average value per day in the time interval [12:00-13:00] and is displayed in green color:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT zeitstempel AS time, ROUND(AVG(leistung)\/1000) AS 'Power &#91;12:00-13:00]' FROM anlage\nWHERE (HOUR(zeitstempel)=12)\nGROUP BY DATE(zeitstempel);<\/code><\/pre>\n\n\n\n<p>Our query <strong>B<\/strong> takes a <strong>7d average<\/strong> of the average values per day, it therefore is kind of a <em>trend line<\/em> of the curve we have generated with query <strong>A<\/strong> and is displayed in yellow color:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT zeitstempel AS time, (SELECT ROUND(AVG(leistung)\/1000) FROM anlage WHERE (HOUR(zeitstempel)=12) AND zeitstempel&lt;=time AND zeitstempel&gt;DATE_ADD(time,INTERVAL-7 DAY)) AS 'Power &#91;12:00-13:00; 7d average]' FROM anlage\nWHERE (DATE(zeitstempel)&gt;='2023-05-09')\nGROUP BY DATE(zeitstempel);<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"93\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Power-1200-1300-1024x93.png\" alt=\"\" class=\"wp-image-1480\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Power-1200-1300-1024x93.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Power-1200-1300-300x27.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Power-1200-1300-768x70.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Power-1200-1300-1536x139.png 1536w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Power-1200-1300-2048x186.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Average Power [12:00-13:00]<\/figcaption><\/figure>\n\n\n\n<p>This graph visualizes the same finding as the previous heatmap. In my opinion, it even shows in a more dramatic way that the average power between [12:00-13:00] even during summer can vary dramatically, and that we simply cannot assume that there is a certain minimum power &#8220;guaranteed&#8221; in a certain time frame during summer. We also see that in winter, the power generation is minimal, and there is no chance that the solar power generator can contribute to the electricity demand of the home in any meaningful way.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Average Power [12:00-13:00] (calculated as difference of energy values)<\/h4>\n\n\n\n<p>One might argue that 4 sampling values per hour are not enough, maybe we were just unlucky and there were clouds in the sky exactly when we were sampling the data. Let us therefore repeat the graph from above, not by using the average of the 4 samples per hour but let us divide the increase of the overall generated energy in the time frame [12:00-13:00] as the base for the power calculation. Again, we will do two queries (<strong>A<\/strong> and <strong>B<\/strong>) whereby query <strong>A<\/strong> is the value on the daily basis:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT present.zeitstempel AS time, (present.energie-past.energie) AS 'Power &#91;12:00-13:00]'\nFROM anlage AS present INNER JOIN anlage AS past ON present.uid=past.uid+4\nWHERE (TIME_FORMAT(present.zeitstempel,'%H:%i')='13:00');<\/code><\/pre>\n\n\n\n<p>and where query <strong>B<\/strong> shows the <strong>7d average<\/strong> of the daily values:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT zeitstempel AS time, (SELECT AVG(present.energie-past.energie) FROM anlage AS present INNER JOIN anlage AS past ON present.uid=past.uid+4 WHERE (TIME_FORMAT(present.zeitstempel,'%H:%i')='13:00') AND present.zeitstempel&lt;=time AND present.zeitstempel&gt;DATE_ADD(time,INTERVAL-7 DAY)) AS 'Power &#91;12:00-13:00; 7d average]' FROM anlage\nWHERE (DATE(zeitstempel)&gt;='2023-05-09')\nGROUP BY DATE(zeitstempel);<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"91\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Power-1200-1300-calculated-as-difference-of-energy-values-1024x91.png\" alt=\"\" class=\"wp-image-1481\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Power-1200-1300-calculated-as-difference-of-energy-values-1024x91.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Power-1200-1300-calculated-as-difference-of-energy-values-300x27.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Power-1200-1300-calculated-as-difference-of-energy-values-768x68.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Power-1200-1300-calculated-as-difference-of-energy-values-1536x137.png 1536w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Power-1200-1300-calculated-as-difference-of-energy-values-2048x182.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Average Power [12:00-13:00] (calculated as difference of energy values)<\/figcaption><\/figure>\n\n\n\n<p>While we can identify some differences in the green curve between this graph and the previous one, the yellow curve is almost identical. In general, the calculation via the energy values is the more precise one; 4 sample values simply do not seem to suffice as we can see in the differences of the green curves.<\/p>\n\n\n\n<p>The overall conclusion of this curve is the same as in the previous one, however: There are many days where the average power generation between [12:00-13:00] stays well below the expected (larger) values.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Average Hourly Power Generation [June]<\/h4>\n\n\n\n<p>The following visualization, again using the built-in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> visualization <a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/visualizations\/time-series\/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Time Series<\/strong><\/a>, shows how the average value of power generated per hour in the month of June varies if we look at the first half and the second half of June. This visualization uses three queries. Query <strong>A<\/strong> shows the average power generation of the <strong>whole month<\/strong> of June:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT zeitstempel AS time, ROUND(AVG(leistung)\/1000) AS 'Power &#91;June 2023]' FROM anlage\nWHERE (zeitstempel&gt;'2023-06-01') AND (zeitstempel&lt;'2023-07-01')\nGROUP BY HOUR(zeitstempel);<\/code><\/pre>\n\n\n\n<p>Query <strong>B<\/strong> looks at the average power generation of the <strong>first half<\/strong> of June:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT zeitstempel AS time, ROUND(AVG(leistung)\/1000) AS 'Power &#91;June 2023; first half]' FROM anlage\nWHERE (zeitstempel&gt;'2023-06-01') AND (zeitstempel&lt;'2023-06-16')\nGROUP BY HOUR(zeitstempel);<\/code><\/pre>\n\n\n\n<p>Query <strong>C<\/strong> looks at the average power generation of the <strong>second half<\/strong> of June<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT DATE_ADD(zeitstempel, INTERVAL -15 DAY) AS time, ROUND(AVG(leistung)\/1000) AS 'Power &#91;June 2023; second half]' FROM anlage\nWHERE (zeitstempel&gt;'2023-06-16') AND (zeitstempel&lt;'2023-07-01')\nGROUP BY HOUR(zeitstempel);<\/code><\/pre>\n\n\n\n<p>As time period for the visualization, we select <strong>2023-06-01 00:00:00 to 2023-06-01 23:59:59<\/strong>. You might wonder why we only select one day for the visualization when we examine a whole month. But as we calculate the average value over the full month (indicated in the WHERE clause of the MySQL query), we will receive only data for one day:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MariaDB &#91;solaranlage]&gt; SELECT zeitstempel AS time, ROUND(AVG(leistung)\/1000) AS 'Power &#91;June 2023]' FROM anlage\n    -&gt; WHERE (zeitstempel&gt;'2023-06-01') AND (zeitstempel&lt;'2023-07-01')\n    -&gt; GROUP BY HOUR(zeitstempel);\n+---------------------+-------------------+\n| time                | Power &#91;June 2023] |\n+---------------------+-------------------+\n| 2023-06-01 05:00:07 |                 9 |\n| 2023-06-01 06:00:08 |               220 |\n| 2023-06-01 07:00:07 |               827 |\n| 2023-06-01 08:00:07 |              1346 |\n| 2023-06-01 09:00:07 |              1530 |\n| 2023-06-01 10:00:07 |              1711 |\n| 2023-06-01 11:00:07 |              1814 |\n| 2023-06-01 12:00:08 |              1689 |\n| 2023-06-01 13:00:07 |              1512 |\n| 2023-06-01 14:00:08 |              1215 |\n| 2023-06-01 15:00:07 |               853 |\n| 2023-06-01 16:00:07 |               458 |\n| 2023-06-01 17:00:07 |               264 |\n| 2023-06-01 18:00:07 |               192 |\n| 2023-06-01 19:00:07 |               133 |\n| 2023-06-01 20:00:07 |                59 |\n| 2023-06-01 21:00:07 |                 9 |\n| 2023-06-01 22:00:07 |                 0 |\n+---------------------+-------------------+\n18 rows in set (0,035 sec)\n\n<\/code><\/pre>\n\n\n\n<p>This also explains the sequence <em>DATE_ADD(zeitstempel, INTERVAL -15 DAY)<\/em> in query C. That sequence simply &#8220;brings back&#8221; the result curves from the day 2023-06-16 to the day 2023-06-01 and thus into our selected time period.<\/p>\n\n\n\n<p>We also need to adjust some <a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/configure-panel-options\/\" target=\"_blank\" rel=\"noreferrer noopener\">panel options<\/a>, and these are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Standard options \u2192 Unit<\/strong>: Select <strong>Watt (W)<\/strong><\/li>\n\n\n\n<li><strong><strong>Standard options <\/strong>\u2192 Min<\/strong>: Set to <strong>0<\/strong><\/li>\n\n\n\n<li><strong><strong>Standard options <\/strong> \u2192 Max<\/strong>: Set to <strong>2500<\/strong><\/li>\n\n\n\n<li><strong><strong><strong>Standard options <\/strong> <\/strong>\u2192 Decimals<\/strong>: Set to <strong>1<\/strong><\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"440\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Hourly-Power-Generation-June-1-1024x440.png\" alt=\"\" class=\"wp-image-1486\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Hourly-Power-Generation-June-1-1024x440.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Hourly-Power-Generation-June-1-300x129.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Hourly-Power-Generation-June-1-768x330.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Hourly-Power-Generation-June-1-1536x660.png 1536w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Average-Hourly-Power-Generation-June-1.png 1892w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Average Hourly Power Generation [June]<\/figcaption><\/figure>\n\n\n\n<p>The green curve displays the average data over the whole month of June whereas the yellow curve represents the first half, and the blue curve represents the second half. We can see that this year (2023), the second half of June was much worse than the first half of June, in terms of power generation. Only in the time window [16:00-18:00], all three curves show the same values.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Power Distribution between 12:00 and 13:00 [June 2023]<\/h4>\n\n\n\n<p>Let us go back to the assumption we used for the second visualization on this article where we assumed a normal distribution of power values for a reasonably small timeframe (one hour over one month). Is this actually a true or maybe a wrong assumption? In order to get a better feeling, we use the built-in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> visualization <a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/visualizations\/histogram\/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Histogram<\/strong><\/a> and look how the power value samples (4 per hour) distribute in the month of June, in the first half of June (where we had a sunny sky), and in the second half of June (where we had a partially cloudy sky).<\/p>\n\n\n\n<p>For the following three histograms, we use the <a href=\"https:\/\/grafana.com\/docs\/grafana\/latest\/panels-visualizations\/configure-panel-options\/\" target=\"_blank\" rel=\"noreferrer noopener\">panel options<\/a>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Histogram \u2192 Bucket size<\/strong>: Set to <strong>50<\/strong><\/li>\n\n\n\n<li><strong><strong>Histogram <\/strong>\u2192 Bucket offset <\/strong>: Set to <strong>0<\/strong><\/li>\n\n\n\n<li><strong>Standard options \u2192 Unit<\/strong>: Select <strong>Watt (W)<\/strong><\/li>\n\n\n\n<li><strong><strong>Standard options <\/strong>\u2192 Min<\/strong>: Set to <strong>0<\/strong><\/li>\n\n\n\n<li><strong><strong>Standard options <\/strong> \u2192 Max<\/strong>: Set to <strong>2500<\/strong><\/li>\n\n\n\n<li><strong><strong><strong>Standard options <\/strong> <\/strong>\u2192 Color scheme<\/strong>: Select <strong>Single color<\/strong><\/li>\n<\/ul>\n\n\n\n<p>The first histogram shows the distribution of power samples (<strong>120<\/strong> in total) over the <strong>whole month<\/strong> of June:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT zeitstempel, ROUND(leistung\/1000) AS 'Power 12:00-13:00 &#91;June 2023]' FROM anlage\nWHERE (zeitstempel&gt;'2023-06-01') AND (zeitstempel&lt;'2023-07-01')\n  AND (HOUR(zeitstempel)=12);<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"405\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-1024x405.png\" alt=\"\" class=\"wp-image-1483\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-1024x405.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-300x119.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-768x304.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-1536x607.png 1536w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June.png 1885w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Power Distribution between 12:00 and 13:00 [June 2023]<\/figcaption><\/figure>\n\n\n\n<p>The second histogram shows the distribution of power samples (<strong>60<\/strong> in total) over the <strong>first half<\/strong> of June:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT zeitstempel, ROUND(leistung\/1000) AS 'Power 12:00-13:00 &#91;June 2023; first half]' FROM anlage\nWHERE (zeitstempel&gt;'2023-06-01') AND (zeitstempel&lt;'2023-06-16')\n  AND (HOUR(zeitstempel)=12);<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"442\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-first-half-1024x442.png\" alt=\"\" class=\"wp-image-1484\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-first-half-1024x442.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-first-half-300x129.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-first-half-768x331.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-first-half-1536x663.png 1536w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-first-half.png 1896w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Power Distribution between 12:00 and 13:00 [June 2023; first half]<\/figcaption><\/figure>\n\n\n\n<p>The third histogram shows the distribution of power samples (<strong>60<\/strong> in total) over the <strong>second half<\/strong> of June:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT zeitstempel, ROUND(leistung\/1000) AS 'Power 12:00-13:00 &#91;June 2023; second half]' FROM anlage\nWHERE (zeitstempel&gt;'2023-06-16') AND (zeitstempel&lt;'2023-07-01')\n  AND (HOUR(zeitstempel)=12);<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"444\" src=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-second-half-1024x444.png\" alt=\"\" class=\"wp-image-1485\" srcset=\"https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-second-half-1024x444.png 1024w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-second-half-300x130.png 300w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-second-half-768x333.png 768w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-second-half-1536x667.png 1536w, https:\/\/caipirinha.spdns.org\/wp\/wp-content\/uploads\/Power-Distribution-between-1200-and-1300-June-second-half.png 1892w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Power Distribution between 12:00 and 13:00 [June 2023; second half]<\/figcaption><\/figure>\n\n\n\n<p>From all curves, we can see that the distribution that we see is by no means a normal distribution. It certainly has a region where we have a bell-shaped density of power values, but during periods with cloudy skies, we can also have many values in the range below the bell-shaped values of the solar generator. Therefore, the assumption of a normal distribution does not hold true in reality.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Visualizations<\/h3>\n\n\n\n<p><a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> allows us to create advanced visualizations from MySQL data with little effort. The point with some less used visualizations in <a href=\"https:\/\/grafana.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> however, is that there is little documentation available, or to say it in a different way: Sometimes the documentation is sufficient if you already know how it works, but insufficient if you do not yet know how it works. I hope that at least with this article, I could contribute to enlarge knowledge.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Solar Power Generation<\/h3>\n\n\n\n<p>The data used in this example shows a solar power generation unit in Germany, facing the East. From the visualized data, we can draw several conclusions:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Peak power of the installed solar power system is shortly before lunch time and decreases already significantly after 14:00.<\/li>\n\n\n\n<li>While power generation looks good until even October, from November on, the yield is poor.<\/li>\n\n\n\n<li>While the generated electricity in the winter months might still help to decrease the electricity bill, it becomes clear that if you were to use a heat pump for the heating of your home, you cannot count on solar power generation to support you in a meaningful way until you have some 50 kW+ peak solar capacity on a large roof.<\/li>\n\n\n\n<li>As the solar power generation peaks shortly before noon, it might make sense to combine units that face to the East and units that face to the West. This observation is in-line with recent proposals that claim that units facing South are not much better than a combination of units facing East and West (e.g., [<a href=\"https:\/\/solarenergie.de\/photovoltaikanlage\/aufbau-photovoltaikanlage\/standort-und-ausrichtung\/ost-west-anlage#:~:text=Das%20hat%20einen%20entscheidenden%20Vorteil,der%20Stromerzeugung%20%C3%BCber%20den%20Tag.\" target=\"_blank\" rel=\"noreferrer noopener\">3<\/a>]).<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Outlook<\/h2>\n\n\n\n<p>The visualizations given here are only an easy beginning. We might want to use more serious statistical analysis to answer questions like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Can we infer from a bad start in the morning (little power) that the rest of the day will stay like this?<\/li>\n\n\n\n<li>How probable is it that we have 3+ cloudy days (with little electricity) in a row, and that translates to: If it rained today, should I wait for 1&#8230;3 more days before I turn on the washing machine?<\/li>\n\n\n\n<li>Does it make economic sense to invest in a battery storage in order to capture excess electricity in summer days? How large should this battery be?<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Files<\/h2>\n\n\n\n<p>The following dataset was used for the graphs:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/caipirinha.spdns.org\/~gabriel\/Blog\/solaranlage.sql.gz\">https:\/\/caipirinha.spdns.org\/~gabriel\/Blog\/solaranlage.sql.gz<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Sources<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[<a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=1450\" target=\"_blank\" rel=\"noreferrer noopener\">1<\/a>] = <a href=\"https:\/\/caipirinha.spdns.org\/wp\/?p=1450\" target=\"_blank\" rel=\"noreferrer noopener\">Smarthome: AVM-Steckdosen per Skript auslesen \u2013 Gabriel R\u00fceck (caipirinha.spdns.org)<\/a><\/li>\n\n\n\n<li>[<a href=\"https:\/\/grafana.com\/grafana\/download\" target=\"_blank\" rel=\"noreferrer noopener\">2<\/a>] = <a href=\"https:\/\/grafana.com\/grafana\/download\" target=\"_blank\" rel=\"noreferrer noopener\">Download Grafana | Grafana Labs<\/a><\/li>\n\n\n\n<li>[<a href=\"https:\/\/solarenergie.de\/photovoltaikanlage\/aufbau-photovoltaikanlage\/standort-und-ausrichtung\/ost-west-anlage#:~:text=Das%20hat%20einen%20entscheidenden%20Vorteil,der%20Stromerzeugung%20%C3%BCber%20den%20Tag.\" target=\"_blank\" rel=\"noreferrer noopener\">3<\/a>] = <a href=\"https:\/\/solarenergie.de\/photovoltaikanlage\/aufbau-photovoltaikanlage\/standort-und-ausrichtung\/ost-west-anlage#:~:text=Das%20hat%20einen%20entscheidenden%20Vorteil,der%20Stromerzeugung%20%C3%BCber%20den%20Tag.\" target=\"_blank\" rel=\"noreferrer noopener\">Ost-West-Ausrichtung von Photovoltaikanlagen (solarenergie.de)<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Disclaimer<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Program codes and examples are for demonstration purposes only.<\/li>\n\n\n\n<li>Program codes are not recommended be used in production environments without further enhancements in terms of speed, failure-tolerance or cyber-security.<\/li>\n\n\n\n<li>While program codes have been tested, they might still contain errors.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this article, we do first steps into visualizations in Grafana of data stored in a MariaDB database and draw conclusions from the visualizations. In this case, we look at meaningful data from solar power generation.<\/p>\n","protected":false},"author":1,"featured_media":1465,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[108,35,107],"tags":[],"class_list":["post-1460","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-energy-transition","category-it","category-statistics"],"_links":{"self":[{"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/posts\/1460","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1460"}],"version-history":[{"count":10,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/posts\/1460\/revisions"}],"predecessor-version":[{"id":1562,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/posts\/1460\/revisions\/1562"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=\/wp\/v2\/media\/1465"}],"wp:attachment":[{"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1460"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1460"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/caipirinha.spdns.org\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1460"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}