diff --git a/examples/Alerts Notebook.ipynb b/examples/Alerts Notebook.ipynb
index 5d920d81..10bae2ba 100644
--- a/examples/Alerts Notebook.ipynb
+++ b/examples/Alerts Notebook.ipynb
@@ -1 +1 @@
-{"cells":[{"cell_type":"markdown","metadata":{"cell_id":"de74932ad03e4b969490663d284bafcd","deepnote_cell_type":"markdown"},"source":"⚠️ **Important:**\nTo view the instructions (if not already displayed), you must **run the next cell**.\n\n▶️ **How to Run the Next Cell?**\n--> Press the **Run** ▶️ button at the top.\n\n---\n\n⚠️ **Wichtig:**\nUm die Anweisungen anzuzeigen (falls nicht bereits angezeigt), müssen Sie **die nächste Zelle ausführen**.\n\n▶️ **Wie führe ich die nächste Zelle aus?**\n--> Drücken Sie die **Run** ▶️-Taste oben.\n","block_group":"8fd9a2c0db19403a80f33c13dea43410"},{"cell_type":"code","metadata":{"source_hash":"baa9d64","is_code_hidden":true,"execution_start":1749641513733,"execution_millis":1,"execution_context_id":"23a9423f-debc-451d-890d-b4b0ec9560ab","deepnote_app_is_code_hidden":true,"deepnote_output_height_limit_disabled":true,"cell_id":"c9ef2462be96452ebff23563edd04c84","deepnote_cell_type":"code"},"source":"%%html\n\n\n\n 🇬🇧 English Instructions (Click to Expand)\n\n
📌 Introduction
\n
This notebook is designed to monitor the status of system components and send email alerts when specific conditions are met. By default, it reports components in error and warning states (see all available warning/error states here), along with any additional user-defined alert states (configured in the component_states_to_alert variable). To customise its execution, you can configure various inputs, including microgrid ID(s), alert states, email settings, and the lookback_duration_minutes parameter. The lookback_duration_minutes parameter defines how far back in time data is fetched for analysis (e.g., setting it to 60 fetches data from the last 60 minutes), ensuring that alerts are both timely and consistent with the analysis interval. Once configured, the notebook can be scheduled for periodic execution, helping you stay informed of critical system changes.
\n\n
🛠️ Instructions
\n
The notebook needs some setup before being executed for the first time.
\n\n
\n
✅ Ensure latest package version: It is recommended to install the latest version of the required packages. View all versions here: frequenz-lib-notebooks, frequenz-client-common, frequenz-reporting-python. When installing, replace the predefined version with the version you want. If you encounter conflicts during installation, ensure you install compatible versions to resolve them.
\n
🛠️ Run the first code cell: Click on the blue triangle when hovering over the cell to install required packages. Then move them to \"requirements.txt\" (for more information about this, see the document \"Instructions: Create a Deepnote project and import a notebook\", section \"5. Install requirements\").
\n
📦 Import necessary libraries: Execute the next two code cells to import libraries and load microgrids.toml. ⏳ Wait for execution to complete.
\n
🎯 Configure inputs: Fill in the required fields in the \"Inputs\" section. See \"Explanation of Input Variables\" for a description of each variable. All inputs are required unless specifically marked as optional.
\n
✉️ Test email settings: Run the \"Test Email Settings\" cell to ensure emails are received.
\n
🚀 Run the notebook: Click the \"Start\" button once inputs are filled.
\n
⏳ Schedule periodic execution: The notebook can then be scheduled for periodic execution using the same frequency defined by the lookback_duration_minutes variable. For more information on how to schedule the notebook to run on periodic intervals, refer to the document \"Instructions: Create a Deepnote project and import a notebook\", section \"Instructions: Schedule regular notebook execution\".\n
\n\n
📊 Explanation of Input Variables
\n\n
Analysis Inputs
\n
\n
🏠 microgrid_id: Select the microgrid(s) to include in the analysis.
\n
🔧 component_types: Choose the component type(s) for analysis. By default, all available types are displayed, but not all may be relevant to the selected microgrid(s).
\n
⏳ lookback_duration_minutes: Set the duration (in minutes) for fetching historical data. For example, enter 60 to retrieve data from the past 60 minutes. Ensure this aligns with your analysis interval.
\n
🚨 component_states_to_alert: Select the component states that should trigger alerts from a predefined list.
\n
\n\n
Email Setup
\n
\n
📡 smtp_server: The address of the SMTP server for sending emails.
\n
🔌 smtp_port: The port for the SMTP server.
\n
👤 smtp_user: The username for the SMTP server.
\n
🔑 smtp_password: The password of the SMTP user.
\n
✉️ sender: The sender's email address.
\n
📩 recipients: The email addresses to send alerts to. Expected value: Comma-separated list of email addresses (e.g., user1@example.com, user2@example.com).
\n
\n \n
Customise Email(Optional)
\n
\n
📨 email_subject: Subject line of the alert email (default: \"Component Error\").
\n
🔗 notebook_url: A link to the Deepnote notebook for reference in the email (default: no value).
\n
📊 rows_to_display: Number of rows of data to include in the email alert (default: 20).
\n
📏 sort_by_severity: Whether to sort alerts by severity in the email alert (default: False).
\n
🧩 group_by_component: Whether to group alerts by component ID in the email alert (default: False).
\n
🚫 filter_no_alerts: Whether to exclude groups with zero errors and warnings in the email alert (default: True).
\n\n
\n\n\n\n 🇩🇪 Deutsche Anleitung (Klicken zum Anzeigen)\n\n
📌 Einleitung
\n
Dieses Notebook ist dazu gedacht, den Status von Systemkomponenten zu überwachen und E-Mail-Benachrichtigungen zu senden, wenn bestimmte Bedingungen erfüllt sind. Standardmäßig meldet es Komponenten im Fehler- (error) und Warnstatus (warning) (Alle verfügbaren Warn-/Fehlerzustände finden Sie hier) sowie zusätzliche, vom Benutzer definierte Warnstatus (konfiguriert in der Variable component_states_to_alert). Um die Ausführung anzupassen, können Sie verschiedene Eingaben konfigurieren, darunter Microgrid-ID(s), Warnstatus, E-Mail-Einstellungen und die Parameter lookback_duration_minutes. Der Parameter lookback_duration_minutes definiert, wie weit in die Vergangenheit Daten für die Analyse abgerufen werden (z. B. werden bei der Einstellung auf 60 Daten der letzten 60 Minuten abgerufen). Dies gewährleistet, dass Benachrichtigungen sowohl zeitnah als auch konsistent mit dem Analyseintervall sind. Nach der Konfiguration kann das Notebook für eine regelmäßige Ausführung geplant werden, sodass Sie über kritische Systemänderungen in Echtzeit informiert bleiben.
\n\n
🛠️ Anleitung
\n
Das Notebook benötigt einige Einstellungen, bevor es zum ersten Mal ausgeführt werden kann.
\n\n
\n
✅ Neueste Paketversion sicherstellen: Es wird empfohlen, die neueste Version des benötigten Pakets zu installieren. Alle Versionen finden Sie hier: frequenz-lib-notebooks, frequenz-client-common, frequenz-reporting-python. Ersetzen Sie bei der Installation die vordefinierte Version durch die gewünschte. Wenn während der Installation Konflikte auftreten, stellen Sie sicher, dass Sie kompatible Versionen installieren, um diese zu beheben.
\n
🛠️ Führen Sie die erste Code-Zelle aus: Klicken Sie auf das blaue Dreieck, um Pakete zu installieren. Danach verschieben Sie sie zu \"requirements.txt\" (weitere Informationen finden Sie im Dokument \"Anleitung: Deepnote Projekt erstellen und Notebook importieren\", Abschnitt \"5. Requirements installieren\").
\n
📦 Importieren Sie die Bibliotheken: Führen Sie die nächsten zwei Code-Zellen aus, um die notwendigen Bibliotheken zu importieren und die Datei microgrids.toml zu laden. ⏳ Warten Sie, bis die Ausführung abgeschlossen ist.
\n
🎯 Konfigurieren Sie die Eingaben: Füllen Sie die erforderlichen Felder unter \"Eingabe\" aus. Details siehe \"Erläuterung der Eingabevariablen\". Alle Eingaben sind erforderlich, es sei denn, sie sind ausdrücklich als optional gekennzeichnet.
\n
✉️ E-Mail-Einstellungen testen: Führen Sie die Zelle \"Testen Sie E-Mail-Einstellungen\" aus, um sicherzustellen, dass E-Mails empfangen werden.
\n
🚀 Notebook ausführen: Klicken Sie auf den \"Start\"-Button, sobald alle Eingaben ausgefüllt sind.
\n
⏳ Planen Sie die regelmäßige Ausführung: Das Notebook kann dann für eine regelmäßige Ausführung geplant werden, wobei die gleiche Frequenz verwendet wird, die durch die Variable lookback_duration_minutes definiert ist. Weitere Informationen dazu, wie das Notebook für regelmäßige Ausführungen geplant werden kann, finden Sie im Dokument \"Anleitung: Deepnote Projekt erstellen und Notebook importieren\", Abschnitt \"Anleitung: Planen Sie die regelmäßige Ausführung eine Notebook\"..\n
\n\n
📊 Erläuterung der Eingabevariablen
\n\n
Analysis Inputs
\n
\n
🏠 microgrid_id: Wählen Sie die Microgrid aus, die in der Analyse berücksichtigt werden sollen.
\n
🔧 component_types: Wähle die Komponententypen für die Analyse aus. Standardmäßig werden alle verfügbaren Typen angezeigt, aber nicht alle sind möglicherweise für die ausgewählten Microgrids relevant.
\n
⏳ lookback_duration_minutes: Lege die Dauer (in Minuten) fest, für die historische Daten abgerufen werden sollen. Zum Beispiel: Gib 60 ein, um Daten der letzten 60 Minuten abzurufen. Stelle sicher, dass dies mit deinem Analyseintervall übereinstimmt.
\n
🚨 component_states_to_alert: Wähle die Komponentenstatus aus, die eine Alarmbenachrichtigung auslösen sollen, aus einer vordefinierten Liste.
\n
\n\n
Email Setup
\n
\n
📡 smtp_server: Die Adresse des SMTP-Servers für das Senden von E-Mails.
\n
🔌 smtp_port: Der Port des SMTP-Servers.
\n
👤 smtp_user: Der Benutzername für den SMTP-Server.
\n
🔑 smtp_password: Das Passwort des SMTP-Benutzers.
\n
✉️ sender: Die E-Mail-Adresse des Absenders.
\n
📩 recipients: Die E-Mail-Adressen der Empfänger. Erwartetes format: Durch Kommas getrennte Liste von E-Mail-Adressen (z. B. user1@example.com, user2@example.com).
\n
\n\n
Customise Email(Optional)
\n
\n
📨 email_subject: Betreffzeile der E-Mail-Benachrichtigung (Standard: \"Component Error\").
\n
🔗 notebook_url: Ein Link zum Deepnote-Notebook als Referenz in der E-Mail (Standard: kein Wert).
\n
📊 rows_to_display: Die Anzahl der Datenzeilen, die in der E-Mail-Benachrichtigung enthalten sein sollen (Standard: 20).
\n
📏 sort_by_severity: Gibt an, ob Warnmeldungen in der E-Mail nach Schweregrad sortiert werden sollen (Standard: False).
\n
🧩 group_by_component: Gibt an, ob Warnmeldungen in der E-Mail nach Komponenten-ID gruppiert werden sollen (Standard: False).
\n
🚫 filter_no_alerts: Gibt an, ob Gruppen ohne Fehler und Warnungen in der E-Mail ausgeschlossen werden sollen (Standard: True).
\n\n
\n\n\n\n","block_group":"ec06701653484ad48b2a8e16fbecf923","execution_count":1,"outputs":[{"data":{"text/plain":"","text/html":"\n\n\n 🇬🇧 English Instructions (Click to Expand)\n\n
📌 Introduction
\n
This notebook is designed to monitor the status of system components and send email alerts when specific conditions are met. By default, it reports components in error and warning states (see all available warning/error states here), along with any additional user-defined alert states (configured in the component_states_to_alert variable). To customise its execution, you can configure various inputs, including microgrid ID(s), alert states, email settings, and the lookback_duration_minutes parameter. The lookback_duration_minutes parameter defines how far back in time data is fetched for analysis (e.g., setting it to 60 fetches data from the last 60 minutes), ensuring that alerts are both timely and consistent with the analysis interval. Once configured, the notebook can be scheduled for periodic execution, helping you stay informed of critical system changes.
\n\n
🛠️ Instructions
\n
The notebook needs some setup before being executed for the first time.
\n\n
\n
✅ Ensure latest package version: It is recommended to install the latest version of the required packages. View all versions here: frequenz-lib-notebooks, frequenz-client-common, frequenz-reporting-python. When installing, replace the predefined version with the version you want. If you encounter conflicts during installation, ensure you install compatible versions to resolve them.
\n
🛠️ Run the first code cell: Click on the blue triangle when hovering over the cell to install required packages. Then move them to \"requirements.txt\" (for more information about this, see the document \"Instructions: Create a Deepnote project and import a notebook\", section \"5. Install requirements\").
\n
📦 Import necessary libraries: Execute the next two code cells to import libraries and load microgrids.toml. ⏳ Wait for execution to complete.
\n
🎯 Configure inputs: Fill in the required fields in the \"Inputs\" section. See \"Explanation of Input Variables\" for a description of each variable. All inputs are required unless specifically marked as optional.
\n
✉️ Test email settings: Run the \"Test Email Settings\" cell to ensure emails are received.
\n
🚀 Run the notebook: Click the \"Start\" button once inputs are filled.
\n
⏳ Schedule periodic execution: The notebook can then be scheduled for periodic execution using the same frequency defined by the lookback_duration_minutes variable. For more information on how to schedule the notebook to run on periodic intervals, refer to the document \"Instructions: Create a Deepnote project and import a notebook\", section \"Instructions: Schedule regular notebook execution\".\n
\n\n
📊 Explanation of Input Variables
\n\n
Analysis Inputs
\n
\n
🏠 microgrid_id: Select the microgrid(s) to include in the analysis.
\n
🔧 component_types: Choose the component type(s) for analysis. By default, all available types are displayed, but not all may be relevant to the selected microgrid(s).
\n
⏳ lookback_duration_minutes: Set the duration (in minutes) for fetching historical data. For example, enter 60 to retrieve data from the past 60 minutes. Ensure this aligns with your analysis interval.
\n
🚨 component_states_to_alert: Select the component states that should trigger alerts from a predefined list.
\n
\n\n
Email Setup
\n
\n
📡 smtp_server: The address of the SMTP server for sending emails.
\n
🔌 smtp_port: The port for the SMTP server.
\n
👤 smtp_user: The username for the SMTP server.
\n
🔑 smtp_password: The password of the SMTP user.
\n
✉️ sender: The sender's email address.
\n
📩 recipients: The email addresses to send alerts to. Expected value: Comma-separated list of email addresses (e.g., user1@example.com, user2@example.com).
\n
\n\n
Customise Email(Optional)
\n
\n
📨 email_subject: Subject line of the alert email (default: \"Component Error\").
\n
🔗 notebook_url: A link to the Deepnote notebook for reference in the email (default: no value).
\n
📊 rows_to_display: Number of rows of data to include in the email alert (default: 20).
\n
📏 sort_by_severity: Whether to sort alerts by severity in the email alert (default: False).
\n
🧩 group_by_component: Whether to group alerts by component ID in the email alert (default: False).
\n
🚫 filter_no_alerts: Whether to exclude groups with zero errors and warnings in the email alert (default: True).
\n\n
\n\n\n\n 🇩🇪 Deutsche Anleitung (Klicken zum Anzeigen)\n\n
📌 Einleitung
\n
Dieses Notebook ist dazu gedacht, den Status von Systemkomponenten zu überwachen und E-Mail-Benachrichtigungen zu senden, wenn bestimmte Bedingungen erfüllt sind. Standardmäßig meldet es Komponenten im Fehler- (error) und Warnstatus (warning) (Alle verfügbaren Warn-/Fehlerzustände finden Sie hier) sowie zusätzliche, vom Benutzer definierte Warnstatus (konfiguriert in der Variable component_states_to_alert). Um die Ausführung anzupassen, können Sie verschiedene Eingaben konfigurieren, darunter Microgrid-ID(s), Warnstatus, E-Mail-Einstellungen und die Parameter lookback_duration_minutes. Der Parameter lookback_duration_minutes definiert, wie weit in die Vergangenheit Daten für die Analyse abgerufen werden (z. B. werden bei der Einstellung auf 60 Daten der letzten 60 Minuten abgerufen). Dies gewährleistet, dass Benachrichtigungen sowohl zeitnah als auch konsistent mit dem Analyseintervall sind. Nach der Konfiguration kann das Notebook für eine regelmäßige Ausführung geplant werden, sodass Sie über kritische Systemänderungen in Echtzeit informiert bleiben.
\n\n
🛠️ Anleitung
\n
Das Notebook benötigt einige Einstellungen, bevor es zum ersten Mal ausgeführt werden kann.
\n\n
\n
✅ Neueste Paketversion sicherstellen: Es wird empfohlen, die neueste Version des benötigten Pakets zu installieren. Alle Versionen finden Sie hier: frequenz-lib-notebooks, frequenz-client-common, frequenz-reporting-python. Ersetzen Sie bei der Installation die vordefinierte Version durch die gewünschte. Wenn während der Installation Konflikte auftreten, stellen Sie sicher, dass Sie kompatible Versionen installieren, um diese zu beheben.
\n
🛠️ Führen Sie die erste Code-Zelle aus: Klicken Sie auf das blaue Dreieck, um Pakete zu installieren. Danach verschieben Sie sie zu \"requirements.txt\" (weitere Informationen finden Sie im Dokument \"Anleitung: Deepnote Projekt erstellen und Notebook importieren\", Abschnitt \"5. Requirements installieren\").
\n
📦 Importieren Sie die Bibliotheken: Führen Sie die nächsten zwei Code-Zellen aus, um die notwendigen Bibliotheken zu importieren und die Datei microgrids.toml zu laden. ⏳ Warten Sie, bis die Ausführung abgeschlossen ist.
\n
🎯 Konfigurieren Sie die Eingaben: Füllen Sie die erforderlichen Felder unter \"Eingabe\" aus. Details siehe \"Erläuterung der Eingabevariablen\". Alle Eingaben sind erforderlich, es sei denn, sie sind ausdrücklich als optional gekennzeichnet.
\n
✉️ E-Mail-Einstellungen testen: Führen Sie die Zelle \"Testen Sie E-Mail-Einstellungen\" aus, um sicherzustellen, dass E-Mails empfangen werden.
\n
🚀 Notebook ausführen: Klicken Sie auf den \"Start\"-Button, sobald alle Eingaben ausgefüllt sind.
\n
⏳ Planen Sie die regelmäßige Ausführung: Das Notebook kann dann für eine regelmäßige Ausführung geplant werden, wobei die gleiche Frequenz verwendet wird, die durch die Variable lookback_duration_minutes definiert ist. Weitere Informationen dazu, wie das Notebook für regelmäßige Ausführungen geplant werden kann, finden Sie im Dokument \"Anleitung: Deepnote Projekt erstellen und Notebook importieren\", Abschnitt \"Anleitung: Planen Sie die regelmäßige Ausführung eine Notebook\"..\n
\n\n
📊 Erläuterung der Eingabevariablen
\n\n
Analysis Inputs
\n
\n
🏠 microgrid_id: Wählen Sie die Microgrid aus, die in der Analyse berücksichtigt werden sollen.
\n
🔧 component_types: Wähle die Komponententypen für die Analyse aus. Standardmäßig werden alle verfügbaren Typen angezeigt, aber nicht alle sind möglicherweise für die ausgewählten Microgrids relevant.
\n
⏳ lookback_duration_minutes: Lege die Dauer (in Minuten) fest, für die historische Daten abgerufen werden sollen. Zum Beispiel: Gib 60 ein, um Daten der letzten 60 Minuten abzurufen. Stelle sicher, dass dies mit deinem Analyseintervall übereinstimmt.
\n
🚨 component_states_to_alert: Wähle die Komponentenstatus aus, die eine Alarmbenachrichtigung auslösen sollen, aus einer vordefinierten Liste.
\n
\n\n
Email Setup
\n
\n
📡 smtp_server: Die Adresse des SMTP-Servers für das Senden von E-Mails.
\n
🔌 smtp_port: Der Port des SMTP-Servers.
\n
👤 smtp_user: Der Benutzername für den SMTP-Server.
\n
🔑 smtp_password: Das Passwort des SMTP-Benutzers.
\n
✉️ sender: Die E-Mail-Adresse des Absenders.
\n
📩 recipients: Die E-Mail-Adressen der Empfänger. Erwartetes format: Durch Kommas getrennte Liste von E-Mail-Adressen (z. B. user1@example.com, user2@example.com).
\n
\n\n
Customise Email(Optional)
\n
\n
📨 email_subject: Betreffzeile der E-Mail-Benachrichtigung (Standard: \"Component Error\").
\n
🔗 notebook_url: Ein Link zum Deepnote-Notebook als Referenz in der E-Mail (Standard: kein Wert).
\n
📊 rows_to_display: Die Anzahl der Datenzeilen, die in der E-Mail-Benachrichtigung enthalten sein sollen (Standard: 20).
\n
📏 sort_by_severity: Gibt an, ob Warnmeldungen in der E-Mail nach Schweregrad sortiert werden sollen (Standard: False).
\n
🧩 group_by_component: Gibt an, ob Warnmeldungen in der E-Mail nach Komponenten-ID gruppiert werden sollen (Standard: False).
\n
🚫 filter_no_alerts: Gibt an, ob Gruppen ohne Fehler und Warnungen in der E-Mail ausgeschlossen werden sollen (Standard: True).
\n\n
\n\n\n\n"},"metadata":{},"output_type":"display_data"}],"outputs_reference":"s3:deepnote-cell-outputs-production/e55cdde1-d17f-42c9-b4e7-f51f36847a91","content_dependencies":null},{"cell_type":"code","metadata":{"cell_id":"e899f0007f7548f7852df2e38a893de8","deepnote_cell_type":"code"},"source":"!pip install --upgrade pip\n!pip install frequenz-lib-notebooks==0.10.1\n!pip install frequenz-client-common==0.3.2\n!pip install frequenz-reporting-python==0.4.0","block_group":"5da73cac7bb044cfb4b51c60d8200be5","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"markdown","metadata":{"formattedRanges":[],"cell_id":"b98534c33f3047f4a9339dd3185539c3","deepnote_cell_type":"text-cell-h1"},"source":"# Imports","block_group":"8caf61c0b4e1499998d48db8285926c7"},{"cell_type":"code","metadata":{"cell_id":"1aad6197cf69480ba8d31b47fb29b7cf","deepnote_cell_type":"code"},"source":"import logging\nimport os\nfrom datetime import UTC, datetime, timedelta\nfrom typing import Any\n\nimport pandas as pd\nfrom frequenz.client.common.metric import Metric\nfrom frequenz.client.common.microgrid.components import (\n ComponentErrorCode,\n ComponentStateCode,\n)\nfrom frequenz.client.reporting import ReportingApiClient\nfrom frequenz.reporting._reporting import fetch_and_extract_state_durations\n\nfrom frequenz.data.microgrid.config import MicrogridConfig\nfrom frequenz.lib.notebooks.alerts.alert_email import (\n AlertEmailConfig,\n ExportOptions,\n compute_time_since,\n generate_alert_email,\n generate_no_alerts_email,\n plot_alerts,\n)\nfrom frequenz.lib.notebooks.notification_service import EmailConfig, EmailNotification\nfrom frequenz.lib.notebooks.notification_utils import (\n format_email_preview,\n send_test_email,\n validate_email_config,\n)\n\nlogging.basicConfig(\n level=logging.WARNING,\n format=\"%(asctime)s %(levelname)s %(name)s: %(message)s\",\n datefmt=\"%H:%M:%S\",\n)\nlogging.getLogger(\"frequenz.lib.notebooks\").setLevel(logging.WARNING)","block_group":"64194d5120ff4d859f56bfad4883aea1","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"markdown","metadata":{"is_collapsed":false,"formattedRanges":[],"deepnote_app_block_visible":false,"cell_id":"f0f721c6c3294dac8f52526c4e42f4f7","deepnote_cell_type":"text-cell-h1"},"source":"# Inputs | Eingabe","block_group":"6382074256294609af0062d64e368da7"},{"cell_type":"code","metadata":{"cell_id":"f794a3e75b0a46248dc3e56696cd3d26","deepnote_cell_type":"code"},"source":"toml_files = [f for f in os.listdir(\"/work\") if f.endswith(\".toml\")]\nif not toml_files:\n raise FileNotFoundError(\"No .toml files found in /work.\")\n\nconfigs: dict[str, \"MicrogridConfig\"] = {}\nfor toml_file in toml_files:\n configs.update(MicrogridConfig.load_configs(toml_file))\navailable_microgrids = sorted(list(int(x) for x in configs.keys()))\navailable_component_types = list(\n set(\n [\n t\n for microgrid_config in configs.values()\n for t in microgrid_config.component_types()\n ]\n )\n)","block_group":"0970747a06e9490fb55c0f3144ee3f30","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"markdown","metadata":{"formattedRanges":[{"type":"marks","marks":{"bold":true},"toCodePoint":15,"fromCodePoint":0}],"cell_id":"8f110a74116e43d197b3145547fdacd6","deepnote_cell_type":"text-cell-p"},"source":"Analysis inputs","block_group":"a48eec0b3ac54c0ab9333f4fe0922578"},{"cell_type":"code","metadata":{"source_hash":"f35a7301","execution_start":1741881819577,"execution_millis":0,"deepnote_input_label":"Select microgrids for analysis","execution_context_id":"46679190-2e76-4c9b-8c11-b15809387adf","deepnote_variable_name":"microgrid_ids","deepnote_variable_value":[],"deepnote_variable_options":[],"deepnote_variable_select_type":"from-variable","deepnote_allow_multiple_values":true,"deepnote_variable_custom_options":["Option 1","Option 2"],"deepnote_variable_selected_variable":"available_microgrids","cell_id":"6db83e7b17274b1aa564ce95fd4cea6a","deepnote_cell_type":"input-select"},"source":"microgrid_ids = []","block_group":"ea00dcba57ee4629a374bff4045d0b2d","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"d0d6ae8e","execution_start":1741881834281,"execution_millis":1,"deepnote_input_label":"Components","execution_context_id":"46679190-2e76-4c9b-8c11-b15809387adf","deepnote_variable_name":"component_types","deepnote_variable_value":[],"deepnote_variable_options":[],"deepnote_variable_select_type":"from-variable","deepnote_allow_multiple_values":true,"deepnote_variable_custom_options":["Option 1","Option 2"],"deepnote_variable_selected_variable":"available_component_types","cell_id":"bb3fcd5a94944f73b5343ef71b085467","deepnote_cell_type":"input-select"},"source":"component_types = []","block_group":"ea00dcba57ee4629a374bff4045d0b2d","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"ad3b922b","execution_start":1738065008238,"execution_millis":1,"deepnote_input_label":"Lookback duration minutes","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"lookback_duration_minutes","deepnote_variable_value":"","cell_id":"7a022b31d3eb4e57afd9c60d6289e41c","deepnote_cell_type":"input-text"},"source":"lookback_duration_minutes = ''","block_group":"9737060fd3c94ef9af2a698f9e123447","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"e26577eb","execution_start":1738064990065,"execution_millis":1,"deepnote_input_label":"Select component states to alert","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"component_states_to_alert","deepnote_variable_value":[],"deepnote_variable_options":["UNKNOWN","SWITCHING_OFF","OFF","STANDBY","ERROR"],"deepnote_variable_select_type":"from-options","deepnote_allow_multiple_values":true,"deepnote_variable_custom_options":["UNKNOWN","SWITCHING_OFF","OFF","STANDBY","ERROR"],"deepnote_variable_selected_variable":"","cell_id":"854d06cdbbdd45c4bd27dd2a2f75df64","deepnote_cell_type":"input-select"},"source":"component_states_to_alert = []","block_group":"9737060fd3c94ef9af2a698f9e123447","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"markdown","metadata":{"formattedRanges":[{"type":"marks","marks":{"bold":true},"toCodePoint":11,"fromCodePoint":0}],"cell_id":"92a99d98870d41e48c1b14aa0e829e57","deepnote_cell_type":"text-cell-p"},"source":"Email setup","block_group":"dec3b5726e2c41bf994f8675c11c23b0"},{"cell_type":"code","metadata":{"source_hash":"8dbeb0a3","execution_start":1738064479096,"execution_millis":0,"deepnote_input_label":"smtp server","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"smtp_server","deepnote_variable_value":"","cell_id":"c4980ebd620242c8a6f73ac0887be6e6","deepnote_cell_type":"input-text"},"source":"smtp_server = ''","block_group":"bac23b391cfd49c28f17b616d8d4fb4e","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"allow_embed":false,"source_hash":"a14f5e1e","execution_start":1738064479144,"execution_millis":0,"deepnote_input_label":"smtp port","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"smtp_port","deepnote_variable_value":"","cell_id":"d0b5151bd2d9446582f269e564571162","deepnote_cell_type":"input-text"},"source":"smtp_port = ''","block_group":"bac23b391cfd49c28f17b616d8d4fb4e","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"allow_embed":false,"source_hash":"f2675e30","execution_start":1738064479192,"execution_millis":0,"deepnote_input_label":"smtp user","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"smtp_user","deepnote_variable_value":"","cell_id":"1340068b451a47ed8b39dc260282edf9","deepnote_cell_type":"input-text"},"source":"smtp_user = ''","block_group":"f095e5c6ff4d4867ba2b82807a9a28f9","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"66e83695","execution_start":1738064479236,"execution_millis":0,"deepnote_input_label":"smtp password","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"smtp_password","deepnote_variable_value":"","cell_id":"843db38536bc47209c7f195aff80690d","deepnote_cell_type":"input-text"},"source":"smtp_password = ''","block_group":"f095e5c6ff4d4867ba2b82807a9a28f9","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"allow_embed":false,"source_hash":"226157e0","execution_start":1738064479284,"execution_millis":0,"deepnote_input_label":"Sender","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"sender","deepnote_variable_value":"","cell_id":"eb463cde3865448e914658f6397454dc","deepnote_cell_type":"input-text"},"source":"sender = ''","block_group":"9a6390e1822b4e6a832e76a486b2ab01","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"d6edc7c","execution_start":1738064479332,"execution_millis":0,"deepnote_input_label":"Recipients","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"recipients","deepnote_variable_value":"","cell_id":"93c6454188e94b8fbc6135bddd239d4a","deepnote_cell_type":"input-textarea"},"source":"recipients = ''","block_group":"9a6390e1822b4e6a832e76a486b2ab01","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"markdown","metadata":{"formattedRanges":[{"type":"marks","marks":{"bold":true},"toCodePoint":26,"fromCodePoint":0}],"cell_id":"749eba71fea84bb2919bb705ec2409b3","deepnote_cell_type":"text-cell-p"},"source":"Customise email (optional)","block_group":"e7126738ff3a4ed5a5167ac9ef52179b"},{"cell_type":"code","metadata":{"allow_embed":false,"source_hash":"e7f819b7","execution_start":1738064479516,"execution_millis":0,"deepnote_input_label":"Email Subject","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"email_subject","deepnote_variable_value":"","cell_id":"20bdeef5986b4170862b59b5dfc5028c","deepnote_cell_type":"input-text"},"source":"email_subject = ''","block_group":"6eb8e4475cb34082b710ea569e45847c","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"de21e876","execution_start":1738064479560,"execution_millis":0,"deepnote_input_label":"Notebook URL","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"notebook_url","deepnote_variable_value":"","cell_id":"595e4d8b9449404286c1a36b95463364","deepnote_cell_type":"input-text"},"source":"notebook_url = ''","block_group":"6eb8e4475cb34082b710ea569e45847c","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"b174d25","execution_start":1738064479608,"execution_millis":0,"deepnote_input_label":"Number of table rows to display","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"rows_to_display","deepnote_variable_value":"","cell_id":"e2641c4756fd4d3a988aee25565deb04","deepnote_cell_type":"input-text"},"source":"rows_to_display = ''","block_group":"6eb8e4475cb34082b710ea569e45847c","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"8e5f5d7a","execution_start":1742564232417,"execution_millis":0,"deepnote_input_label":"Sort by severity","execution_context_id":"a92b83e3-4537-4b08-9ad3-c1951e32355f","deepnote_variable_name":"sort_by_severity","deepnote_variable_value":"False","deepnote_variable_options":["True","False"],"deepnote_variable_select_type":"from-options","deepnote_variable_custom_options":["True","False"],"deepnote_variable_selected_variable":"","cell_id":"f564329f73734d5ca698b2e39a15b4ff","deepnote_cell_type":"input-select"},"source":"sort_by_severity = 'False'","block_group":"e229d61387dd488896d8abf322448bf3","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"d37a2314","execution_start":1742564236322,"execution_millis":2,"deepnote_input_label":"Group by component","execution_context_id":"a92b83e3-4537-4b08-9ad3-c1951e32355f","deepnote_variable_name":"group_by_component","deepnote_variable_value":"False","deepnote_variable_options":["True","False"],"deepnote_variable_select_type":"from-options","deepnote_variable_custom_options":["True","False"],"deepnote_variable_selected_variable":"","cell_id":"df495d27659e40cf911be64773b17635","deepnote_cell_type":"input-select"},"source":"group_by_component = 'False'","block_group":"e229d61387dd488896d8abf322448bf3","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"cb3a4ac3","execution_start":1742564238238,"execution_millis":2,"deepnote_input_label":"Filter no alerts","execution_context_id":"a92b83e3-4537-4b08-9ad3-c1951e32355f","deepnote_variable_name":"filter_no_alerts","deepnote_variable_value":"True","deepnote_variable_options":["True","False"],"deepnote_variable_select_type":"from-options","deepnote_variable_custom_options":["True","False"],"deepnote_variable_selected_variable":"","cell_id":"aca91c9c898f44bbbc79bda47561890c","deepnote_cell_type":"input-select"},"source":"filter_no_alerts = 'True'","block_group":"e229d61387dd488896d8abf322448bf3","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"is_code_hidden":true,"deepnote_app_is_code_hidden":true,"cell_id":"8a10cc71675d4b869cf95b1489ac2a32","deepnote_cell_type":"code"},"source":"default_email_config = {\n \"smtp_server\": smtp_server, # replace with your SMTP server\n \"smtp_port\": smtp_port, # replace with your SMTP port\n \"smtp_user\": smtp_user, # replace with your SMTP user\n \"smtp_password\": smtp_password, # replace with your SMTP password\n \"from_email\": sender, # sender email\n \"recipients\": recipients.replace(\" \", \"\").split(\",\"), # accepts multiple recipients\n \"subject\": email_subject if email_subject else \"Component Error\", # email subject\n \"message\": \"Empty message. Should be replaced automatically.\", # email body\n}\n\n# Bypasses __post_init__ for validation-only use\nconfig = EmailConfig.__new__(EmailConfig)\n\n# Set attributes manually\nfor k, v in default_email_config.items():\n setattr(config, k, v)\n\nerrors = validate_email_config(config, check_connectivity=True)\nif errors:\n try:\n from IPython.display import display\n\n display(errors)\n except ImportError:\n print(\"Validation errors:\", *errors, sep=\"\\n\")\nelse:\n config.subject = \"Test Email - Alert Notebook Notification Service Configuration\"\n success = send_test_email(config, verbose=True)","block_group":"8e72b665afd74f0b9a5013c426006012","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"markdown","metadata":{"source_hash":"b623e53d","execution_start":1738064479652,"execution_millis":0,"execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_button_title":"Start","deepnote_variable_name":"button_1","deepnote_button_behavior":"run","deepnote_button_color_scheme":"blue","cell_id":"cbee6eefa6e44c6384248f13721f3dbe","deepnote_cell_type":"button"},"source":"","block_group":"f6f4e18b54a14b2cb009ff8f9a84041d","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"ddf0cd2d","is_code_hidden":true,"execution_start":1738064479700,"execution_millis":0,"execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_app_is_code_hidden":true,"cell_id":"d726c606bd7d4f6696777b2b445ce1c5","deepnote_cell_type":"code"},"source":"# parse user input and set up some defaults and other parameters\nmicrogrid_components_request = []\nfor microgrid_id, microgrid_config in configs.items():\n if microgrid_id not in microgrid_ids:\n continue\n for t in component_types:\n if t not in microgrid_config.component_types():\n continue\n inverters = microgrid_config.component_type_ids(\n component_type=t, component_category=\"inverter\"\n )\n components = microgrid_config.component_type_ids(\n component_type=t, component_category=\"component\"\n )\n cid_request = []\n cid_request = cid_request + inverters if inverters else cid_request\n cid_request = cid_request + components if components else cid_request\n if cid_request:\n microgrid_components_request += [(int(microgrid_id), cid_request)]\n\n# define the start time, end time, and, resampling period for the data request\nend_time = datetime.now().astimezone(UTC)\nstart_time = end_time - timedelta(minutes=float(lookback_duration_minutes))\nresampling_period_seconds = timedelta(seconds=10)\n\n# convert to boolean\nsort_by_severity = sort_by_severity == \"True\" if sort_by_severity else False\ngroup_by_component = group_by_component == \"True\" if sort_by_severity else False\nfilter_no_alerts = filter_no_alerts == \"True\" if sort_by_severity else True\n\n# set up component states to alert\ncomponent_states_mapping = {\n \"UNKNOWN\": ComponentStateCode.UNKNOWN.value,\n \"SWITCHING_OFF\": ComponentStateCode.SWITCHING_OFF.value,\n \"OFF\": ComponentStateCode.OFF.value,\n \"STANDBY\": ComponentStateCode.STANDBY.value,\n \"ERROR\": ComponentStateCode.ERROR.value,\n}\nstates_to_alert = [\n component_states_mapping[state] for state in component_states_to_alert\n]\n\n# whether to include warnings (errors are included by default)\ninclude_warnings = True\n\n# set up alert conditions (to be) checked\nconditions_checked = [\"All error codes\"]\nconditions_checked += [\"All warning codes\"] if include_warnings else []\nconditions_checked += [f\"ComponentState_{state}\" for state in component_states_to_alert]","block_group":"dca244fdf3e4420ab63598b4b491a1ad","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"code","metadata":{"is_code_hidden":true,"deepnote_app_is_code_hidden":true,"cell_id":"32defd9dd98149cfa8c563b29e13ddfd","deepnote_cell_type":"code"},"source":"# set up the Reporting API client\nclient = ReportingApiClient(\n server_url=os.environ[\"REPORTING_SERVER_URL\"],\n auth_key=os.environ[\"REPORTING_API_KEY\"],\n sign_secret=os.environ[\"REPORTING_API_SECRET\"],\n)\n\n# fetch data and extract state durations and alert records.\nall_states, alert_records = await fetch_and_extract_state_durations(\n client=client,\n microgrid_components=microgrid_components_request,\n metrics=[Metric.AC_ACTIVE_POWER],\n start_time=start_time,\n end_time=end_time,\n resampling_period=resampling_period_seconds,\n alert_states=states_to_alert,\n include_warnings=include_warnings,\n)","block_group":"ccd9b34a27a44fe987ca02a09c984227","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"code","metadata":{"is_code_hidden":true,"deepnote_app_is_code_hidden":true,"cell_id":"8cd76f2320964f9bba590aa9457e0296","deepnote_cell_type":"code"},"source":"STATE_TYPE_TO_ENUM = {\n \"state\": ComponentStateCode,\n \"error\": ComponentErrorCode,\n \"warning\": ComponentErrorCode,\n}\n\n\ndef _convert_state_values_to_enum(\n samples: list[dict[str, Any]],\n) -> list[dict[str, Any]]:\n \"\"\"Convert state_value integers to their corresponding Enum names.\n\n Args:\n samples: List of samples.\n\n Returns:\n New list of samples with state_value converted to Enum names.\n \"\"\"\n converted_samples = []\n for sample in samples:\n enum_cls = STATE_TYPE_TO_ENUM.get(sample.get(\"state_type\"))\n if enum_cls:\n try:\n sample = sample.copy()\n sample[\"state_value\"] = enum_cls(sample[\"state_value\"]).name\n except ValueError:\n print(\n f\"Unknown state value {sample['state_value']} \"\n f\"for component {sample.get('component_id')} \"\n f\"(state_type: {sample['state_type']})\"\n )\n converted_samples.append(sample)\n return converted_samples\n\n\n# Convert state values to their corresponding Enum names for clarity\nall_states = _convert_state_values_to_enum(all_states)\nalert_records = _convert_state_values_to_enum(alert_records)\n\n# create dataframes\nall_states_df = pd.DataFrame(all_states)\nalert_records_df = pd.DataFrame(alert_records)\n\n# add more stats (time since start, time since end)\nif not all_states_df.empty:\n all_states_df[\"time_since_start\"] = all_states_df.apply(\n lambda row: compute_time_since(row, \"start_time\"), axis=1\n )\n all_states_df[\"time_since_end\"] = all_states_df.apply(\n lambda row: compute_time_since(row, \"end_time\"), axis=1\n )\n\nif not alert_records_df.empty:\n alert_records_df[\"time_since_start\"] = alert_records_df.apply(\n lambda row: compute_time_since(row, \"start_time\"), axis=1\n )\n alert_records_df[\"time_since_end\"] = alert_records_df.apply(\n lambda row: compute_time_since(row, \"end_time\"), axis=1\n )","block_group":"373e3bd4ecc24942989ceaf21dd1c28c","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"code","metadata":{"is_code_hidden":true,"deepnote_app_is_code_hidden":true,"cell_id":"5639002ad2d14e2b9c787aee88659ebb","deepnote_cell_type":"code"},"source":"# variables are for display purposes\nsubject = \"Preview\"\nalert_file_name = \"\"\n\n# set up the config for generating alert emails\nalert_email_config = AlertEmailConfig(\n notebook_url=notebook_url,\n displayed_rows=int(rows_to_display) if rows_to_display else 20,\n sort_by_severity=sort_by_severity,\n group_by_component=group_by_component,\n filter_no_alerts=filter_no_alerts,\n)\n\nemail_config = EmailConfig.from_dict(default_email_config)\n\nif not alert_records_df.empty: # send an alert email\n email_config.subject += f\" - {len(alert_records_df)} alerts detected\"\n subject = email_config.subject\n\n # generate HTML email body with alert details\n html_body = generate_alert_email(\n alert_records=alert_records_df,\n config=alert_email_config,\n checks=conditions_checked,\n )\n email_config.message = html_body\n\n # optionally add attachments (a list of files)\n email_config.attachments = None\n timestamp = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n alert_file_name = f\"alert_details_{timestamp}.csv\"\n alert_records_df.to_csv(alert_file_name, index=False)\n email_config.attachments = [alert_file_name]\n\n # create a visualisation of the alert records\n img_path = plot_alerts(\n records=alert_records_df,\n plot_type=\"all\",\n export_options=ExportOptions(\n format=\"png\",\n show=True,\n ),\n )\n email_config.attachments += img_path if img_path else []\n\n # send email\n email_notification = EmailNotification(config=email_config)\n email_notification.send()\nelse: # send a no alerts email\n email_config.subject = \"No Alerts Found\"\n email_config.message = generate_no_alerts_email(\n checks=conditions_checked, notebook_url=notebook_url\n )\n email_notification = EmailNotification(config=email_config)\n email_notification.send()","block_group":"5189ff94420e43f68c11cc9da4c215f6","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"code","metadata":{"is_code_hidden":true,"deepnote_app_is_code_hidden":true,"cell_id":"c66fe42dc5314d8dba7424cf89fd6b79","deepnote_cell_type":"code"},"source":"# example email preview\nfrom IPython.display import HTML\n\n\nHTML(\n format_email_preview(\n subject=subject if subject else email_config.subject,\n body_html=(\n generate_alert_email(\n alert_records=alert_records_df,\n config=alert_email_config,\n checks=conditions_checked,\n )\n if not alert_records_df.empty\n else generate_alert_email(\n alert_records=all_states_df,\n config=alert_email_config,\n checks=conditions_checked,\n )\n ),\n attachments=[alert_file_name] if alert_file_name else [],\n )\n)","block_group":"57312325101141c59ace3ff13c15f456","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"markdown","source":"\n \nCreated in Deepnote","metadata":{"created_in_deepnote_cell":true,"deepnote_cell_type":"markdown"}}],"nbformat":4,"nbformat_minor":0,"metadata":{"deepnote_notebook_id":"aa595208e5fa4768ba86950627ad2af3"}}
\ No newline at end of file
+{"cells":[{"cell_type":"markdown","metadata":{"cell_id":"44a83ab824ad4712be9a1ce41c89fd10","deepnote_cell_type":"markdown"},"source":"⚠️ **Important:**\nTo view the instructions (if not already displayed), you must **run the next cell**.\n\n▶️ **How to Run the Next Cell?**\n--> Press the **Run** ▶️ button at the top.\n\n---\n\n⚠️ **Wichtig:**\nUm die Anweisungen anzuzeigen (falls nicht bereits angezeigt), müssen Sie **die nächste Zelle ausführen**.\n\n▶️ **Wie führe ich die nächste Zelle aus?**\n--> Drücken Sie die **Run** ▶️-Taste oben.\n","block_group":"66974a26fdde4b4dbb6303308ab06ba4"},{"cell_type":"code","metadata":{"source_hash":"baa9d64","is_code_hidden":true,"execution_start":1749641513733,"execution_millis":1,"execution_context_id":"23a9423f-debc-451d-890d-b4b0ec9560ab","deepnote_app_is_code_hidden":true,"deepnote_output_height_limit_disabled":true,"cell_id":"f76238429c0c4ca68666ac33d89c6bbb","deepnote_cell_type":"code"},"source":"%%html\n\n\n\n 🇬🇧 English Instructions (Click to Expand)\n\n
📌 Introduction
\n
\n This notebook monitors the status of microgrid components and sends email alerts when specific conditions are met. It is designed to help users stay informed about critical system changes.\n
\n\n
\n By default, the notebook sends alerts for components in error and warning states, along with any additional states you define in the component_states_to_alert input variable.\n
\n\n
\n The list of possible error and warning codes is defined in a class called ComponentErrorCode. The available component states that can be used in alerts are defined in ComponentStateCode.\n
Open the link and press Ctrl+F (or Cmd+F on Mac) or look for the search box directly.
\n
Type ComponentErrorCode or ComponentStateCode to jump to the definitions.
\n
\n
\n\n
\n To customise this notebook's execution, you can configure various inputs such as microgrid IDs, email settings, and the lookback_duration_minutes parameter. This parameter defines how far back in time data is fetched for analysis (e.g., setting it to 60 fetches data from the last 60 minutes). Once configured, the notebook can be scheduled for periodic execution.\n
\n\n
🛠️ Instructions
\n
The notebook needs some setup before being executed for the first time.
\n\n
\n
✅ Ensure latest package version: It is recommended to install the latest version of the required package. View all versions here: frequenz-lib-notebooks. When installing, replace the predefined version with the version you want.
\n
🛠️ Run the first code cell: Click on the blue triangle when hovering over the cell to install required packages. Then move them to \"requirements.txt\" (for more information about this, see the document \"Instructions: Create a Deepnote project and import a notebook\", section \"5. Install requirements\").
\n
📦 Import necessary libraries: Execute the next two code cells to import libraries and load microgrids.toml. ⏳ Wait for execution to complete.
\n
🎯 Configure inputs: Fill in the required fields in the \"Inputs\" section. See \"Explanation of Input Variables\" for a description of each variable. All inputs are required unless specifically marked as optional.
\n
✉️ Test email settings: Run the \"Test Email Settings\" cell to ensure emails are received.
\n
🚀 Run the notebook: Click the \"Start\" button once inputs are filled.
\n
⏳ Schedule periodic execution: The notebook can then be scheduled for periodic execution using the same frequency defined by the lookback_duration_minutes variable. For more information on how to schedule the notebook to run on periodic intervals, refer to the document \"Instructions: Create a Deepnote project and import a notebook\", section \"Instructions: Schedule regular notebook execution\".\n
\n\n
📊 Explanation of Input Variables
\n\n
Analysis Inputs
\n
\n
🏠 microgrid_id: Select the microgrid(s) to include in the analysis.
\n
🔧 component_types: Choose the component type(s) for analysis. By default, all available types are displayed, but not all may be relevant to the selected microgrid(s).
\n
⏳ lookback_duration_minutes: Set the duration (in minutes) for fetching historical data. For example, enter 60 to retrieve data from the past 60 minutes. Ensure this aligns with your analysis interval.
\n
🚨 component_states_to_alert: Select the component states that should trigger alerts from a predefined list.
\n
\n\n
Email Setup
\n
\n
📡 smtp_server: The address of the SMTP server for sending emails.
\n
🔌 smtp_port: The port for the SMTP server.
\n
👤 smtp_user: The username for the SMTP server.
\n
🔑 smtp_password: The password of the SMTP user.
\n
✉️ sender: The sender's email address.
\n
📩 recipients: The email addresses to send alerts to. Expected value: Comma-separated list of email addresses (e.g., user1@example.com, user2@example.com).
\n
\n \n
Customise Email(Optional)
\n
\n
📨 email_subject: Subject line of the alert email (default: \"Component Error\").
\n
🔗 notebook_url: A link to the Deepnote notebook for reference in the email (default: no value).
\n
📊 rows_to_display: Number of rows of data to include in the email alert (default: 20).
\n
📏 sort_by_severity: Whether to sort alerts by severity in the email alert (default: False).
\n
🧩 group_by_component: Whether to group alerts by component ID in the email alert (default: False).
\n
🚫 filter_no_alerts: Whether to exclude groups with zero errors and warnings in the email alert (default: True).
\n\n
\n\n\n\n 🇩🇪 Deutsche Anleitung (Klicken zum Anzeigen)\n\n
📌 Einleitung
\n
\n Dieses Notebook überwacht den Status von Microgrid-Komponenten und sendet E-Mail-Benachrichtigungen, wenn bestimmte Bedingungen erfüllt sind. Es soll Benutzer dabei unterstützen, über kritische Systemänderungen informiert zu bleiben.\n
\n\n
\n Standardmäßig sendet das Notebook Benachrichtigungen für Komponenten im error- und warning-Status sowie für zusätzliche Zustände, die Sie in der Eingabevariable component_states_to_alert definieren.\n
\n\n
\n Die Liste der möglichen Fehler- und Warncodes ist in der Klasse ComponentErrorCode definiert. Die verfügbaren Komponentenstatus, die für Benachrichtigungen verwendet werden können, sind in ComponentStateCode definiert.\n
Öffnen Sie den Link und drücken Sie Strg+F (oder Befehl+F auf dem Mac), oder verwenden Sie direkt das Suchfeld.
\n
Geben Sie ComponentErrorCode oder ComponentStateCode ein, um direkt zu den Definitionen zu springen.
\n
\n \n\n
\n Um die Ausführung dieses Notebooks anzupassen, können Sie verschiedene Eingaben konfigurieren, z. B. Microgrid-IDs, E-Mail-Einstellungen und den Parameter lookback_duration_minutes. Dieser Parameter definiert, wie weit in der Vergangenheit Daten für die Analyse abgerufen werden (z. B. ruft der Wert 60 Daten der letzten 60 Minuten ab). Nach der Konfiguration kann das Notebook für eine regelmäßige Ausführung geplant werden.\n
\n\n
🛠️ Anleitung
\n
Das Notebook benötigt einige Einstellungen, bevor es zum ersten Mal ausgeführt werden kann.
\n\n
\n
✅ Neueste Paketversion sicherstellen: Es wird empfohlen, die neueste Version des benötigten Pakets zu installieren. Alle Versionen finden Sie hier: frequenz-lib-notebooks. Ersetzen Sie bei der Installation die vordefinierte Version durch die gewünschte.
\n
🛠️ Führen Sie die erste Code-Zelle aus: Klicken Sie auf das blaue Dreieck, um Pakete zu installieren. Danach verschieben Sie sie zu \"requirements.txt\" (weitere Informationen finden Sie im Dokument \"Anleitung: Deepnote Projekt erstellen und Notebook importieren\", Abschnitt \"5. Requirements installieren\").
\n
📦 Importieren Sie die Bibliotheken: Führen Sie die nächsten zwei Code-Zellen aus, um die notwendigen Bibliotheken zu importieren und die Datei microgrids.toml zu laden. ⏳ Warten Sie, bis die Ausführung abgeschlossen ist.
\n
🎯 Konfigurieren Sie die Eingaben: Füllen Sie die erforderlichen Felder unter \"Eingabe\" aus. Details siehe \"Erläuterung der Eingabevariablen\". Alle Eingaben sind erforderlich, es sei denn, sie sind ausdrücklich als optional gekennzeichnet.
\n
✉️ E-Mail-Einstellungen testen: Führen Sie die Zelle \"Testen Sie E-Mail-Einstellungen\" aus, um sicherzustellen, dass E-Mails empfangen werden.
\n
🚀 Notebook ausführen: Klicken Sie auf den \"Start\"-Button, sobald alle Eingaben ausgefüllt sind.
\n
⏳ Planen Sie die regelmäßige Ausführung: Das Notebook kann dann für eine regelmäßige Ausführung geplant werden, wobei die gleiche Frequenz verwendet wird, die durch die Variable lookback_duration_minutes definiert ist. Weitere Informationen dazu, wie das Notebook für regelmäßige Ausführungen geplant werden kann, finden Sie im Dokument \"Anleitung: Deepnote Projekt erstellen und Notebook importieren\", Abschnitt \"Anleitung: Planen Sie die regelmäßige Ausführung eine Notebook\"..\n
\n\n
📊 Erläuterung der Eingabevariablen
\n\n
Analysis Inputs
\n
\n
🏠 microgrid_id: Wählen Sie die Microgrid aus, die in der Analyse berücksichtigt werden sollen.
\n
🔧 component_types: Wähle die Komponententypen für die Analyse aus. Standardmäßig werden alle verfügbaren Typen angezeigt, aber nicht alle sind möglicherweise für die ausgewählten Microgrids relevant.
\n
⏳ lookback_duration_minutes: Lege die Dauer (in Minuten) fest, für die historische Daten abgerufen werden sollen. Zum Beispiel: Gib 60 ein, um Daten der letzten 60 Minuten abzurufen. Stelle sicher, dass dies mit deinem Analyseintervall übereinstimmt.
\n
🚨 component_states_to_alert: Wähle die Komponentenstatus aus, die eine Alarmbenachrichtigung auslösen sollen, aus einer vordefinierten Liste.
\n
\n\n
Email Setup
\n
\n
📡 smtp_server: Die Adresse des SMTP-Servers für das Senden von E-Mails.
\n
🔌 smtp_port: Der Port des SMTP-Servers.
\n
👤 smtp_user: Der Benutzername für den SMTP-Server.
\n
🔑 smtp_password: Das Passwort des SMTP-Benutzers.
\n
✉️ sender: Die E-Mail-Adresse des Absenders.
\n
📩 recipients: Die E-Mail-Adressen der Empfänger. Erwartetes format: Durch Kommas getrennte Liste von E-Mail-Adressen (z. B. user1@example.com, user2@example.com).
\n
\n\n
Customise Email(Optional)
\n
\n
📨 email_subject: Betreffzeile der E-Mail-Benachrichtigung (Standard: \"Component Error\").
\n
🔗 notebook_url: Ein Link zum Deepnote-Notebook als Referenz in der E-Mail (Standard: kein Wert).
\n
📊 rows_to_display: Die Anzahl der Datenzeilen, die in der E-Mail-Benachrichtigung enthalten sein sollen (Standard: 20).
\n
📏 sort_by_severity: Gibt an, ob Warnmeldungen in der E-Mail nach Schweregrad sortiert werden sollen (Standard: False).
\n
🧩 group_by_component: Gibt an, ob Warnmeldungen in der E-Mail nach Komponenten-ID gruppiert werden sollen (Standard: False).
\n
🚫 filter_no_alerts: Gibt an, ob Gruppen ohne Fehler und Warnungen in der E-Mail ausgeschlossen werden sollen (Standard: True).
\n\n
\n\n\n\n","block_group":"381ecdd54829453f9900e39966a80ebd","execution_count":1,"outputs":[{"data":{"text/html":"\n\n\n 🇬🇧 English Instructions (Click to Expand)\n\n
📌 Introduction
\n
\n This notebook monitors the status of microgrid components and sends email alerts when specific conditions are met. It is designed to help users stay informed about critical system changes.\n
\n\n
\n By default, the notebook sends alerts for components in error and warning states, along with any additional states you define in the component_states_to_alert input variable.\n
\n\n
\n The list of possible error and warning codes is defined in a class called ComponentErrorCode. The available component states that can be used in alerts are defined in ComponentStateCode.\n
Open the link and press Ctrl+F (or Cmd+F on Mac) or look for the search box directly.
\n
Type ComponentErrorCode or ComponentStateCode to jump to the definitions.
\n
\n \n\n
\n To customise this notebook's execution, you can configure various inputs such as microgrid IDs, email settings, and the lookback_duration_minutes parameter. This parameter defines how far back in time data is fetched for analysis (e.g., setting it to 60 fetches data from the last 60 minutes). Once configured, the notebook can be scheduled for periodic execution.\n
\n\n
🛠️ Instructions
\n
The notebook needs some setup before being executed for the first time.
\n\n
\n
✅ Ensure latest package version: It is recommended to install the latest version of the required package. View all versions here: frequenz-lib-notebooks. When installing, replace the predefined version with the version you want.
\n
🛠️ Run the first code cell: Click on the blue triangle when hovering over the cell to install required packages. Then move them to \"requirements.txt\" (for more information about this, see the document \"Instructions: Create a Deepnote project and import a notebook\", section \"5. Install requirements\").
\n
📦 Import necessary libraries: Execute the next two code cells to import libraries and load microgrids.toml. ⏳ Wait for execution to complete.
\n
🎯 Configure inputs: Fill in the required fields in the \"Inputs\" section. See \"Explanation of Input Variables\" for a description of each variable. All inputs are required unless specifically marked as optional.
\n
✉️ Test email settings: Run the \"Test Email Settings\" cell to ensure emails are received.
\n
🚀 Run the notebook: Click the \"Start\" button once inputs are filled.
\n
⏳ Schedule periodic execution: The notebook can then be scheduled for periodic execution using the same frequency defined by the lookback_duration_minutes variable. For more information on how to schedule the notebook to run on periodic intervals, refer to the document \"Instructions: Create a Deepnote project and import a notebook\", section \"Instructions: Schedule regular notebook execution\".\n
\n\n
📊 Explanation of Input Variables
\n\n
Analysis Inputs
\n
\n
🏠 microgrid_id: Select the microgrid(s) to include in the analysis.
\n
🔧 component_types: Choose the component type(s) for analysis. By default, all available types are displayed, but not all may be relevant to the selected microgrid(s).
\n
⏳ lookback_duration_minutes: Set the duration (in minutes) for fetching historical data. For example, enter 60 to retrieve data from the past 60 minutes. Ensure this aligns with your analysis interval.
\n
🚨 component_states_to_alert: Select the component states that should trigger alerts from a predefined list.
\n
\n\n
Email Setup
\n
\n
📡 smtp_server: The address of the SMTP server for sending emails.
\n
🔌 smtp_port: The port for the SMTP server.
\n
👤 smtp_user: The username for the SMTP server.
\n
🔑 smtp_password: The password of the SMTP user.
\n
✉️ sender: The sender's email address.
\n
📩 recipients: The email addresses to send alerts to. Expected value: Comma-separated list of email addresses (e.g., user1@example.com, user2@example.com).
\n
\n \n
Customise Email(Optional)
\n
\n
📨 email_subject: Subject line of the alert email (default: \"Component Error\").
\n
🔗 notebook_url: A link to the Deepnote notebook for reference in the email (default: no value).
\n
📊 rows_to_display: Number of rows of data to include in the email alert (default: 20).
\n
📏 sort_by_severity: Whether to sort alerts by severity in the email alert (default: False).
\n
🧩 group_by_component: Whether to group alerts by component ID in the email alert (default: False).
\n
🚫 filter_no_alerts: Whether to exclude groups with zero errors and warnings in the email alert (default: True).
\n\n
\n\n\n\n 🇩🇪 Deutsche Anleitung (Klicken zum Anzeigen)\n\n
📌 Einleitung
\n
\n Dieses Notebook überwacht den Status von Microgrid-Komponenten und sendet E-Mail-Benachrichtigungen, wenn bestimmte Bedingungen erfüllt sind. Es soll Benutzer dabei unterstützen, über kritische Systemänderungen informiert zu bleiben.\n
\n\n
\n Standardmäßig sendet das Notebook Benachrichtigungen für Komponenten im error- und warning-Status sowie für zusätzliche Zustände, die Sie in der Eingabevariable component_states_to_alert definieren.\n
\n\n
\n Die Liste der möglichen Fehler- und Warncodes ist in der Klasse ComponentErrorCode definiert. Die verfügbaren Komponentenstatus, die für Benachrichtigungen verwendet werden können, sind in ComponentStateCode definiert.\n
Öffnen Sie den Link und drücken Sie Strg+F (oder Befehl+F auf dem Mac), oder verwenden Sie direkt das Suchfeld.
\n
Geben Sie ComponentErrorCode oder ComponentStateCode ein, um direkt zu den Definitionen zu springen.
\n
\n \n\n
\n Um die Ausführung dieses Notebooks anzupassen, können Sie verschiedene Eingaben konfigurieren, z. B. Microgrid-IDs, E-Mail-Einstellungen und den Parameter lookback_duration_minutes. Dieser Parameter definiert, wie weit in der Vergangenheit Daten für die Analyse abgerufen werden (z. B. ruft der Wert 60 Daten der letzten 60 Minuten ab). Nach der Konfiguration kann das Notebook für eine regelmäßige Ausführung geplant werden.\n
\n\n
🛠️ Anleitung
\n
Das Notebook benötigt einige Einstellungen, bevor es zum ersten Mal ausgeführt werden kann.
\n\n
\n
✅ Neueste Paketversion sicherstellen: Es wird empfohlen, die neueste Version des benötigten Pakets zu installieren. Alle Versionen finden Sie hier: frequenz-lib-notebooks. Ersetzen Sie bei der Installation die vordefinierte Version durch die gewünschte.
\n
🛠️ Führen Sie die erste Code-Zelle aus: Klicken Sie auf das blaue Dreieck, um Pakete zu installieren. Danach verschieben Sie sie zu \"requirements.txt\" (weitere Informationen finden Sie im Dokument \"Anleitung: Deepnote Projekt erstellen und Notebook importieren\", Abschnitt \"5. Requirements installieren\").
\n
📦 Importieren Sie die Bibliotheken: Führen Sie die nächsten zwei Code-Zellen aus, um die notwendigen Bibliotheken zu importieren und die Datei microgrids.toml zu laden. ⏳ Warten Sie, bis die Ausführung abgeschlossen ist.
\n
🎯 Konfigurieren Sie die Eingaben: Füllen Sie die erforderlichen Felder unter \"Eingabe\" aus. Details siehe \"Erläuterung der Eingabevariablen\". Alle Eingaben sind erforderlich, es sei denn, sie sind ausdrücklich als optional gekennzeichnet.
\n
✉️ E-Mail-Einstellungen testen: Führen Sie die Zelle \"Testen Sie E-Mail-Einstellungen\" aus, um sicherzustellen, dass E-Mails empfangen werden.
\n
🚀 Notebook ausführen: Klicken Sie auf den \"Start\"-Button, sobald alle Eingaben ausgefüllt sind.
\n
⏳ Planen Sie die regelmäßige Ausführung: Das Notebook kann dann für eine regelmäßige Ausführung geplant werden, wobei die gleiche Frequenz verwendet wird, die durch die Variable lookback_duration_minutes definiert ist. Weitere Informationen dazu, wie das Notebook für regelmäßige Ausführungen geplant werden kann, finden Sie im Dokument \"Anleitung: Deepnote Projekt erstellen und Notebook importieren\", Abschnitt \"Anleitung: Planen Sie die regelmäßige Ausführung eine Notebook\"..\n
\n\n
📊 Erläuterung der Eingabevariablen
\n\n
Analysis Inputs
\n
\n
🏠 microgrid_id: Wählen Sie die Microgrid aus, die in der Analyse berücksichtigt werden sollen.
\n
🔧 component_types: Wähle die Komponententypen für die Analyse aus. Standardmäßig werden alle verfügbaren Typen angezeigt, aber nicht alle sind möglicherweise für die ausgewählten Microgrids relevant.
\n
⏳ lookback_duration_minutes: Lege die Dauer (in Minuten) fest, für die historische Daten abgerufen werden sollen. Zum Beispiel: Gib 60 ein, um Daten der letzten 60 Minuten abzurufen. Stelle sicher, dass dies mit deinem Analyseintervall übereinstimmt.
\n
🚨 component_states_to_alert: Wähle die Komponentenstatus aus, die eine Alarmbenachrichtigung auslösen sollen, aus einer vordefinierten Liste.
\n
\n\n
Email Setup
\n
\n
📡 smtp_server: Die Adresse des SMTP-Servers für das Senden von E-Mails.
\n
🔌 smtp_port: Der Port des SMTP-Servers.
\n
👤 smtp_user: Der Benutzername für den SMTP-Server.
\n
🔑 smtp_password: Das Passwort des SMTP-Benutzers.
\n
✉️ sender: Die E-Mail-Adresse des Absenders.
\n
📩 recipients: Die E-Mail-Adressen der Empfänger. Erwartetes format: Durch Kommas getrennte Liste von E-Mail-Adressen (z. B. user1@example.com, user2@example.com).
\n
\n\n
Customise Email(Optional)
\n
\n
📨 email_subject: Betreffzeile der E-Mail-Benachrichtigung (Standard: \"Component Error\").
\n
🔗 notebook_url: Ein Link zum Deepnote-Notebook als Referenz in der E-Mail (Standard: kein Wert).
\n
📊 rows_to_display: Die Anzahl der Datenzeilen, die in der E-Mail-Benachrichtigung enthalten sein sollen (Standard: 20).
\n
📏 sort_by_severity: Gibt an, ob Warnmeldungen in der E-Mail nach Schweregrad sortiert werden sollen (Standard: False).
\n
🧩 group_by_component: Gibt an, ob Warnmeldungen in der E-Mail nach Komponenten-ID gruppiert werden sollen (Standard: False).
\n
🚫 filter_no_alerts: Gibt an, ob Gruppen ohne Fehler und Warnungen in der E-Mail ausgeschlossen werden sollen (Standard: True).
\n\n
\n\n\n\n","text/plain":""},"metadata":{},"output_type":"display_data"}],"outputs_reference":"s3:deepnote-cell-outputs-production/e6b0d844-c6e5-47dc-b2ab-602020018a33","content_dependencies":null},{"cell_type":"code","metadata":{"source_hash":"1ad047d2","execution_start":1753286893572,"execution_millis":27659,"execution_context_id":"2063558d-e7bb-4056-b69d-8319406519da","cell_id":"ea03fbd7dee947e3b1e19416be2f9867","deepnote_cell_type":"code"},"source":"!pip install --upgrade pip\n!pip install frequenz-lib-notebooks==0.11.0","block_group":"f6c5c041456e4349ae0153364c6e0ddb","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"markdown","metadata":{"formattedRanges":[],"cell_id":"a68f6caab73b40e1b66c395c70dae313","deepnote_cell_type":"text-cell-h1"},"source":"# Imports","block_group":"fb1e56b649dc43738dfc63c71fb5e3a4"},{"cell_type":"code","metadata":{"source_hash":"57209c25","execution_start":1753286921282,"execution_millis":1685,"execution_context_id":"2063558d-e7bb-4056-b69d-8319406519da","cell_id":"7be4b0d270ce4346b9a25c6f7e9aa2ca","deepnote_cell_type":"code"},"source":"import logging\nimport os\nfrom datetime import UTC, datetime, timedelta\n\nimport pandas as pd\nfrom frequenz.client.common.metric import Metric\nfrom frequenz.client.common.microgrid.components import ComponentStateCode\nfrom frequenz.client.reporting import ReportingApiClient\n\nfrom frequenz.data.microgrid.config import MicrogridConfig\nfrom frequenz.lib.notebooks.alerts.alert_email import (\n AlertEmailConfig,\n ExportOptions,\n compute_time_since,\n generate_alert_email,\n generate_no_alerts_email,\n plot_alerts,\n)\nfrom frequenz.lib.notebooks.notification_service import EmailConfig, EmailNotification\nfrom frequenz.lib.notebooks.notification_utils import (\n format_email_preview,\n send_test_email,\n validate_email_config,\n)\nfrom frequenz.lib.notebooks.reporting.state_analysis import (\n fetch_and_extract_state_durations,\n)\n\nlogging.basicConfig(\n level=logging.WARNING,\n format=\"%(asctime)s %(levelname)s %(name)s: %(message)s\",\n datefmt=\"%H:%M:%S\",\n)\nlogging.getLogger(\"frequenz.lib.notebooks\").setLevel(logging.WARNING)","block_group":"08a18831aff54456ac12b44e7b607525","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"markdown","metadata":{"is_collapsed":false,"formattedRanges":[],"deepnote_app_block_visible":false,"cell_id":"200bfbbd9506490886a89d4220052885","deepnote_cell_type":"text-cell-h1"},"source":"# Inputs | Eingabe","block_group":"36af0cd8a43d48898576658340433474"},{"cell_type":"code","metadata":{"source_hash":"8599b5a9","execution_start":1753286957142,"execution_millis":1553,"execution_context_id":"2063558d-e7bb-4056-b69d-8319406519da","cell_id":"f749a9ad3ea040819fe87632cfdf5d30","deepnote_cell_type":"code"},"source":"configs: dict[str, \"MicrogridConfig\"] = MicrogridConfig.load_configs(\n microgrid_config_dir=\"/work\"\n)\navailable_microgrids = sorted(list(int(x) for x in configs.keys()))\n\nassets = {\"battery\", \"pv\", \"ev\"}\navailable_component_types = sorted(\n {t for config in configs.values() for t in config.component_types() if t in assets}\n)\n\navailable_component_states = [state.name for state in ComponentStateCode]","block_group":"517d6989c89f4d6791bf29088f3ec88d","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"markdown","metadata":{"formattedRanges":[{"type":"marks","marks":{"bold":true},"toCodePoint":15,"fromCodePoint":0}],"cell_id":"4b1c3104ecb54e108613b21c94fcc198","deepnote_cell_type":"text-cell-p"},"source":"Analysis inputs","block_group":"89862b5aeaf14ce6a0dff0e8d44863a4"},{"cell_type":"code","metadata":{"source_hash":"f35a7301","execution_start":1753287003015,"execution_millis":2,"deepnote_input_label":"Select microgrids for analysis","execution_context_id":"2063558d-e7bb-4056-b69d-8319406519da","deepnote_variable_name":"microgrid_ids","deepnote_variable_value":[],"deepnote_variable_options":["11","14","15","42","59","65","113","205"],"deepnote_variable_select_type":"from-variable","deepnote_allow_multiple_values":true,"deepnote_variable_custom_options":["Option 1","Option 2"],"deepnote_variable_selected_variable":"available_microgrids","cell_id":"06f1f37abdef4c638cb567f4e6419abc","deepnote_cell_type":"input-select"},"source":"microgrid_ids = []","block_group":"46476438671140888b9e5946fd38416e","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"d0d6ae8e","execution_start":1753287004286,"execution_millis":1,"deepnote_input_label":"Components","execution_context_id":"2063558d-e7bb-4056-b69d-8319406519da","deepnote_variable_name":"component_types","deepnote_variable_value":[],"deepnote_variable_options":["battery","ev","pv"],"deepnote_variable_select_type":"from-variable","deepnote_allow_multiple_values":true,"deepnote_variable_custom_options":["Option 1","Option 2"],"deepnote_variable_selected_variable":"available_component_types","cell_id":"5531a5ffa6974b88a2b267026e66fffc","deepnote_cell_type":"input-select"},"source":"component_types = []","block_group":"46476438671140888b9e5946fd38416e","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"ad3b922b","execution_start":1738065008238,"execution_millis":1,"deepnote_input_label":"Lookback duration minutes","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"lookback_duration_minutes","deepnote_variable_value":"","cell_id":"f6a691b2b6ee48c5a026badfc40aee71","deepnote_cell_type":"input-text"},"source":"lookback_duration_minutes = ''","block_group":"b006953108bb4306a5c594c1d9f8b351","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"e26577eb","execution_start":1753287025792,"execution_millis":0,"deepnote_input_label":"Select component states to alert","execution_context_id":"2063558d-e7bb-4056-b69d-8319406519da","deepnote_variable_name":"component_states_to_alert","deepnote_variable_value":[],"deepnote_variable_options":["UNSPECIFIED","UNKNOWN","SWITCHING_OFF","OFF","SWITCHING_ON","STANDBY","READY","CHARGING","DISCHARGING","ERROR","EV_CHARGING_CABLE_UNPLUGGED","EV_CHARGING_CABLE_PLUGGED_AT_STATION","EV_CHARGING_CABLE_PLUGGED_AT_EV","EV_CHARGING_CABLE_LOCKED_AT_STATION","EV_CHARGING_CABLE_LOCKED_AT_EV","RELAY_OPEN","RELAY_CLOSED","PRECHARGER_OPEN","PRECHARGER_PRECHARGING","PRECHARGER_CLOSED"],"deepnote_variable_select_type":"from-variable","deepnote_allow_multiple_values":true,"deepnote_variable_default_value":"","deepnote_variable_custom_options":[],"deepnote_variable_selected_variable":"available_component_states","cell_id":"81ca4cbf83454eaea05de483a00f47ef","deepnote_cell_type":"input-select"},"source":"component_states_to_alert = []","block_group":"b006953108bb4306a5c594c1d9f8b351","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"markdown","metadata":{"formattedRanges":[{"type":"marks","marks":{"bold":true},"toCodePoint":11,"fromCodePoint":0}],"cell_id":"d9d8e3df8234443fb7182d14f0a1c031","deepnote_cell_type":"text-cell-p"},"source":"Email setup","block_group":"27a59548ca2a4512b314d17c6e12b53c"},{"cell_type":"code","metadata":{"source_hash":"8dbeb0a3","execution_start":1738064479096,"execution_millis":0,"deepnote_input_label":"smtp server","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"smtp_server","deepnote_variable_value":"","cell_id":"41f50f0a7a9b4b3780d394ac473a5785","deepnote_cell_type":"input-text"},"source":"smtp_server = ''","block_group":"f65d1a80d5584bf28bfc5b1ea5a4d8ba","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"allow_embed":false,"source_hash":"a14f5e1e","execution_start":1738064479144,"execution_millis":0,"deepnote_input_label":"smtp port","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"smtp_port","deepnote_variable_value":"","cell_id":"1bcc2a0a4f024c3cb1e4cd451093884a","deepnote_cell_type":"input-text"},"source":"smtp_port = ''","block_group":"f65d1a80d5584bf28bfc5b1ea5a4d8ba","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"allow_embed":false,"source_hash":"f2675e30","execution_start":1738064479192,"execution_millis":0,"deepnote_input_label":"smtp user","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"smtp_user","deepnote_variable_value":"","cell_id":"0de50ede86af445ca95ec6fc3440b4ec","deepnote_cell_type":"input-text"},"source":"smtp_user = ''","block_group":"cbe89192e74a4ff4a191b58c3088affb","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"66e83695","execution_start":1738064479236,"execution_millis":0,"deepnote_input_label":"smtp password","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"smtp_password","deepnote_variable_value":"","cell_id":"92b1980eba78423ab3f4185007dcd391","deepnote_cell_type":"input-text"},"source":"smtp_password = ''","block_group":"cbe89192e74a4ff4a191b58c3088affb","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"allow_embed":false,"source_hash":"226157e0","execution_start":1738064479284,"execution_millis":0,"deepnote_input_label":"Sender","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"sender","deepnote_variable_value":"","cell_id":"7d2c6dfa0fac470380f19d5c1fd3d1a8","deepnote_cell_type":"input-text"},"source":"sender = ''","block_group":"f897e80d049d44da90ee34d48c20fecc","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"d6edc7c","execution_start":1738064479332,"execution_millis":0,"deepnote_input_label":"Recipients","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"recipients","deepnote_variable_value":"","cell_id":"6c320126e4a04eb0a6aa6468a2feccf8","deepnote_cell_type":"input-textarea"},"source":"recipients = ''","block_group":"f897e80d049d44da90ee34d48c20fecc","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"markdown","metadata":{"formattedRanges":[{"type":"marks","marks":{"bold":true},"toCodePoint":26,"fromCodePoint":0}],"cell_id":"bcc6086919d148dfb0c8d8086fd9de8a","deepnote_cell_type":"text-cell-p"},"source":"Customise email (optional)","block_group":"880da173d214444face40ba7d13dacbb"},{"cell_type":"code","metadata":{"allow_embed":false,"source_hash":"e7f819b7","execution_start":1738064479516,"execution_millis":0,"deepnote_input_label":"Email Subject","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"email_subject","deepnote_variable_value":"","cell_id":"e3533f80826b4c76bde979abd40dab35","deepnote_cell_type":"input-text"},"source":"email_subject = ''","block_group":"4a75b673b3dc459f9b0e31a5df440e36","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"de21e876","execution_start":1738064479560,"execution_millis":0,"deepnote_input_label":"Notebook URL","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"notebook_url","deepnote_variable_value":"","cell_id":"ef481a6823e9463a9aa4ff19e8f6492a","deepnote_cell_type":"input-text"},"source":"notebook_url = ''","block_group":"4a75b673b3dc459f9b0e31a5df440e36","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"b174d25","execution_start":1738064479608,"execution_millis":0,"deepnote_input_label":"Number of table rows to display","execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_variable_name":"rows_to_display","deepnote_variable_value":"","cell_id":"b1fcd3c2a6d74c478aecc440d426e4c5","deepnote_cell_type":"input-text"},"source":"rows_to_display = ''","block_group":"4a75b673b3dc459f9b0e31a5df440e36","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"8e5f5d7a","execution_start":1742564232417,"execution_millis":0,"deepnote_input_label":"Sort by severity","execution_context_id":"a92b83e3-4537-4b08-9ad3-c1951e32355f","deepnote_variable_name":"sort_by_severity","deepnote_variable_value":"False","deepnote_variable_options":["True","False"],"deepnote_variable_select_type":"from-options","deepnote_variable_custom_options":["True","False"],"deepnote_variable_selected_variable":"","cell_id":"df48330da6c14ecc81f7388edb14cf9d","deepnote_cell_type":"input-select"},"source":"sort_by_severity = 'False'","block_group":"ef5ca73223ba4fcea183fa874abf7641","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"d37a2314","execution_start":1742564236322,"execution_millis":2,"deepnote_input_label":"Group by component","execution_context_id":"a92b83e3-4537-4b08-9ad3-c1951e32355f","deepnote_variable_name":"group_by_component","deepnote_variable_value":"False","deepnote_variable_options":["True","False"],"deepnote_variable_select_type":"from-options","deepnote_variable_custom_options":["True","False"],"deepnote_variable_selected_variable":"","cell_id":"136454b9e9fc403ca6d41796f59b8837","deepnote_cell_type":"input-select"},"source":"group_by_component = 'False'","block_group":"ef5ca73223ba4fcea183fa874abf7641","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"cb3a4ac3","execution_start":1742564238238,"execution_millis":2,"deepnote_input_label":"Filter no alerts","execution_context_id":"a92b83e3-4537-4b08-9ad3-c1951e32355f","deepnote_variable_name":"filter_no_alerts","deepnote_variable_value":"True","deepnote_variable_options":["True","False"],"deepnote_variable_select_type":"from-options","deepnote_variable_custom_options":["True","False"],"deepnote_variable_selected_variable":"","cell_id":"2d8f6dc195594e40b00239b6b6b0213a","deepnote_cell_type":"input-select"},"source":"filter_no_alerts = 'True'","block_group":"ef5ca73223ba4fcea183fa874abf7641","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"is_code_hidden":true,"deepnote_app_is_code_hidden":true,"cell_id":"9796b11ff00d4471b62ea02b6c4e32c3","deepnote_cell_type":"code"},"source":"default_email_config = {\n \"smtp_server\": smtp_server, # replace with your SMTP server\n \"smtp_port\": smtp_port, # replace with your SMTP port\n \"smtp_user\": smtp_user, # replace with your SMTP user\n \"smtp_password\": smtp_password, # replace with your SMTP password\n \"from_email\": sender, # sender email\n \"recipients\": recipients.replace(\" \", \"\").split(\",\"), # accepts multiple recipients\n \"subject\": email_subject if email_subject else \"Component Error\", # email subject\n \"message\": \"Empty message. Should be replaced automatically.\", # email body\n}\n\n# Bypasses __post_init__ for validation-only use\nconfig = EmailConfig.__new__(EmailConfig)\n\n# Set attributes manually\nfor k, v in default_email_config.items():\n setattr(config, k, v)\n\nerrors = validate_email_config(config, check_connectivity=True)\nif errors:\n try:\n from IPython.display import display\n\n display(errors)\n except ImportError:\n print(\"Validation errors:\", *errors, sep=\"\\n\")\nelse:\n config.subject = \"Test Email - Alert Notebook Notification Service Configuration\"\n success = send_test_email(config)","block_group":"7ed3b8674a2346689435e813177b17c4","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"markdown","metadata":{"source_hash":"b623e53d","execution_start":1738064479652,"execution_millis":0,"execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_button_title":"Start","deepnote_variable_name":"button_1","deepnote_button_behavior":"run","deepnote_button_color_scheme":"blue","cell_id":"fa5bb613e20e4914bb8434bd0397d87d","deepnote_cell_type":"button"},"source":"","block_group":"47fabb926e27457096f4af64f4134f0c","execution_count":null,"outputs":[],"outputs_reference":null},{"cell_type":"code","metadata":{"source_hash":"ddf0cd2d","is_code_hidden":true,"execution_start":1738064479700,"execution_millis":0,"execution_context_id":"0613a2d8-ce03-427c-8fdd-429e64b27765","deepnote_app_is_code_hidden":true,"cell_id":"5c970ee5776c47d396fd06f069b4ec3d","deepnote_cell_type":"code"},"source":"# parse user input and set up some defaults and other parameters\nmicrogrid_components_request = []\nmetrics_to_request = [Metric.AC_ACTIVE_POWER]\nfor microgrid_id, microgrid_config in configs.items():\n if microgrid_id not in microgrid_ids:\n continue\n for ctype in component_types:\n if ctype not in microgrid_config.component_types():\n continue\n inverters = microgrid_config.component_type_ids(\n component_type=ctype, component_category=\"inverter\"\n )\n components = microgrid_config.component_type_ids(\n component_type=ctype, component_category=\"component\"\n )\n if ctype == \"battery\":\n metrics_to_request.append(Metric.DC_POWER)\n logging.info(\n \"Microgrid %s: Found %s inverters (%s) and %s components (%s) of type `%s`\",\n microgrid_id,\n len(inverters) if inverters else 0,\n inverters,\n len(components) if components else 0,\n components,\n ctype,\n )\n cid_request = []\n cid_request = cid_request + inverters if inverters else cid_request\n cid_request = cid_request + components if components else cid_request\n if cid_request:\n microgrid_components_request += [(int(microgrid_id), cid_request)]\n logging.info(\"Microgrid request: %s\", microgrid_components_request)\n else:\n logging.warning(\"No components found for microgrid %s\", microgrid_id)\n\n# define the start time, end time, and, resampling period for the data request\nend_time = datetime.now().astimezone(UTC)\nstart_time = end_time - timedelta(minutes=float(lookback_duration_minutes))\nresampling_period_seconds = timedelta(seconds=1)\n\n# convert to boolean\nsort_by_severity = sort_by_severity == \"True\" if sort_by_severity else False\ngroup_by_component = group_by_component == \"True\" if sort_by_severity else False\nfilter_no_alerts = filter_no_alerts == \"True\" if sort_by_severity else True\n\n# whether to include warnings (errors are included by default)\ninclude_warnings = True\n\n# set up alert conditions (to be) checked\nconditions_checked = [\"All error codes\"]\nconditions_checked += [\"All warning codes\"] if include_warnings else []\nconditions_checked += [f\"ComponentState_{state}\" for state in component_states_to_alert]","block_group":"6671b1d2a800462da78d35479b372224","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"code","metadata":{"is_code_hidden":true,"deepnote_app_is_code_hidden":true,"cell_id":"70180c41c1a34c95bf0e95748d6658da","deepnote_cell_type":"code"},"source":"# set up the Reporting API client\nclient = ReportingApiClient(\n server_url=os.environ[\"REPORTING_SERVER_URL\"],\n auth_key=os.environ[\"REPORTING_API_KEY\"],\n sign_secret=os.environ[\"REPORTING_API_SECRET\"],\n)\n\n# fetch data and extract state durations and alert records.\nall_states, alert_records = await fetch_and_extract_state_durations(\n client=client,\n microgrid_components=microgrid_components_request,\n metrics=metrics_to_request,\n start_time=start_time,\n end_time=end_time,\n resampling_period=resampling_period_seconds,\n alert_states=[ComponentStateCode[name] for name in component_states_to_alert],\n include_warnings=include_warnings,\n)","block_group":"c6d6e8eef9d2463ca77c4981b32f8aa6","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"code","metadata":{"is_code_hidden":true,"deepnote_app_is_code_hidden":true,"cell_id":"56ba3ecf108640aa9310d1ad6ae838a8","deepnote_cell_type":"code"},"source":"# create dataframes\nall_states_df = pd.DataFrame(all_states)\nalert_records_df = pd.DataFrame(alert_records)\n\n# add more stats (time since start, time since end)\nif not all_states_df.empty:\n all_states_df[\"time_since_start\"] = all_states_df.apply(\n lambda row: compute_time_since(row, \"start_time\"), axis=1\n )\n all_states_df[\"time_since_end\"] = all_states_df.apply(\n lambda row: compute_time_since(row, \"end_time\"), axis=1\n )\n\nif not alert_records_df.empty:\n alert_records_df[\"time_since_start\"] = alert_records_df.apply(\n lambda row: compute_time_since(row, \"start_time\"), axis=1\n )\n alert_records_df[\"time_since_end\"] = alert_records_df.apply(\n lambda row: compute_time_since(row, \"end_time\"), axis=1\n )","block_group":"a86a7dbe295f4c1b9f008d20e68ed4ed","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"code","metadata":{"is_code_hidden":true,"deepnote_app_is_code_hidden":true,"cell_id":"0bf956410a0140588d438baf43f65468","deepnote_cell_type":"code"},"source":"# variables are for display purposes\nsubject = \"Preview\"\nalert_file_name = \"\"\n\n# set up the config for generating alert emails\nalert_email_config = AlertEmailConfig(\n notebook_url=notebook_url,\n displayed_rows=int(rows_to_display) if rows_to_display else 20,\n sort_by_severity=sort_by_severity,\n group_by_component=group_by_component,\n filter_no_alerts=filter_no_alerts,\n)\n\nemail_config = EmailConfig.from_dict(default_email_config)\n\nif not alert_records_df.empty: # send an alert email\n email_config.subject += f\" - {len(alert_records_df)} alerts detected\"\n subject = email_config.subject\n\n # generate HTML email body with alert details\n html_body = generate_alert_email(\n alert_records=alert_records_df,\n config=alert_email_config,\n checks=conditions_checked,\n )\n email_config.message = html_body\n\n # optionally add attachments (a list of files)\n email_config.attachments = None\n timestamp = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n alert_file_name = f\"alert_details_{timestamp}.csv\"\n alert_records_df.to_csv(alert_file_name, index=False)\n email_config.attachments = [alert_file_name]\n\n # create a visualisation of the alert records\n img_path = plot_alerts(\n records=alert_records_df,\n plot_type=\"all\",\n export_options=ExportOptions(\n # format=\"png\",\n show=True,\n ),\n )\n email_config.attachments += img_path if img_path else []\n\n # send email\n email_notification = EmailNotification(config=email_config)\n email_notification.send()\nelse: # send a no alerts email\n email_config.subject = \"No Alerts Found\"\n email_config.message = generate_no_alerts_email(\n checks=conditions_checked, notebook_url=notebook_url\n )\n email_notification = EmailNotification(config=email_config)\n email_notification.send()","block_group":"871c9d22834849729178590942f1e77b","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"code","metadata":{"is_code_hidden":true,"deepnote_app_is_code_hidden":true,"cell_id":"2d03e69b7aaa41c0bef990a340ee2961","deepnote_cell_type":"code"},"source":"# example email preview\nfrom IPython.display import HTML\n\nHTML(\n format_email_preview(\n subject=subject if subject else email_config.subject,\n body_html=(\n generate_alert_email(\n alert_records=alert_records_df,\n config=alert_email_config,\n checks=conditions_checked,\n )\n if not alert_records_df.empty\n else generate_alert_email(\n alert_records=all_states_df,\n config=alert_email_config,\n checks=conditions_checked,\n )\n ),\n attachments=[alert_file_name] if alert_file_name else [],\n )\n)","block_group":"18a1b3a126274c0ba2545362b0f3e16b","execution_count":null,"outputs":[],"outputs_reference":null,"content_dependencies":null},{"cell_type":"markdown","source":"\n \nCreated in Deepnote","metadata":{"created_in_deepnote_cell":true,"deepnote_cell_type":"markdown"}}],"nbformat":4,"nbformat_minor":0,"metadata":{"deepnote_notebook_id":"283a24f3463f4fd5a94fe70612559b50"}}
\ No newline at end of file