# Python-Skripte schreiben

## Python-Skripte schreiben

{% hint style="warning" %}
Mit der Einführung von BuildingPro Suites Version 12.2 wurden wichtige Änderungen vorgenommen, die es erforderlich machen, Skripte an das neue API-Design anzupassen.
{% endhint %}

## Skriptdefinition

Wenn im BuildingPro-Suites-System ein neues Skript erstellt wird, wird automatisch ein Funktionskopf generiert. Dieser Kopf enthält zwei Parameter:

* **`id`**: Die eindeutige ID des Skripts.
* **`eliona`**: Ein Objekt, über das der Benutzer mit dem BuildingPro-Suites-System interagieren kann.

Der Funktionskopf sieht so aus:

```python
# Sie dürfen Imports nur innerhalb der Funktion hinzufügen
# ändern oder löschen Sie die Funktionsdefinition nicht
def UserFunction(id, eliona):
	# fügen Sie hier Ihren Code ein
```

### Module importieren

Alle erforderlichen Module müssen innerhalb der Funktion importiert werden. Es ist wichtig, dass Module nur innerhalb der Funktion importiert werden und keine globalen Imports verwendet werden.

Beispiel:

```python
def UserFunction(id, eliona):
    import random
    # Weitere Codezeilen folgen
```

***

## Methoden des BuildingPro-Suites-Objekts

Der **`eliona`** Das Objekt bietet eine Reihe von Methoden, mit denen Benutzer mit dem BuildingPro-Suites-System interagieren können. Hier sind die wichtigsten Methoden samt ihren Parametern und Beschreibungen:

<table data-full-width="true"><thead><tr><th width="173">Methode</th><th>Parameter</th><th>Beschreibung</th><th></th></tr></thead><tbody><tr><td><strong>GetHeap</strong></td><td><code>gai: str</code>, <code>subtype: str</code>, <code>attribute: str</code></td><td>Ruft den aktuellen Wert eines Attributs oder die gesamte Daten-JSON eines Assets aus dem Heap ab.</td><td></td></tr><tr><td><strong>SetHeap</strong></td><td><code>gai: str</code>, <code>subtype: str</code>, <code>data: dict</code>, <code>source: str</code></td><td>Sendet Daten an den Rechner, um sie zu verarbeiten und im Heap zu speichern.</td><td></td></tr><tr><td><strong>GetAssetIDByGAI</strong></td><td><code>gai: str</code></td><td>Gibt die numerische Asset-ID für die angegebene GAI zurück.</td><td></td></tr><tr><td><strong>GetAll</strong></td><td>`ids: list[int</td><td>str]<code>,</code> subtype: str`</td><td>Ruft alle Datenpunkte eines bestimmten Subtyps für eine Liste von Assets ab und gibt sie als Wörterbuch zurück (GAI → Daten).</td></tr><tr><td><strong>SQLQuery</strong></td><td><code>query: str</code></td><td>Führt eine beliebige SQL-Abfrage aus und gibt die Ergebnisse als Liste von Tupeln zurück.</td><td></td></tr><tr><td><strong>MakeSource</strong></td><td><code>id: int</code></td><td>Erzeugt einen Quellstring für Heap-Operationen basierend auf der Funktions-ID.</td><td></td></tr><tr><td><strong>OpenFile</strong></td><td><code>name: str</code>, <code>mode: str</code></td><td>Öffnet eine Datei im Arbeitsverzeichnis von BuildingPro Suites (analog zu Python <code>open()</code>).</td><td></td></tr><tr><td><strong>AddAssetTag</strong></td><td><code>gai: str</code>, <code>tag: str</code></td><td>Fügt einem Asset ein Tag hinzu (falls noch nicht vorhanden).</td><td></td></tr><tr><td><strong>RemoveAssetTag</strong></td><td><code>gai: str</code>, <code>tag: str</code></td><td>Entfernt ein Tag von einem Asset (falls vorhanden).</td><td></td></tr><tr><td><strong>GetTrendRecords</strong></td><td><code>asset_id: int</code>, <code>subtype: str</code>, <code>attr: str</code>, <code>begin: datetime</code></td><td>Ruft historische Messwerte als Liste von <code>TrendRecord(ts, value)</code> ab dem angegebenen Zeitpunkt ab.</td><td></td></tr><tr><td><strong>WriteTrendRecords</strong></td><td><code>asset_id: int</code>, <code>subtype: str</code>, <code>attr: str</code>, <code>`recs: TrendRecord</code></td><td>Schreibt einen oder mehrere <code>TrendRecord</code> Datensätze in das System.</td><td></td></tr><tr><td><strong>GetAggregate</strong></td><td><code>agg: Aggregate</code>, <code>asset_id: int</code>, <code>subtype: str</code>, <code>attr: str</code>,<code>raster: str</code>, <code>start: datetime</code>,<code>end: datetime = now()</code></td><td>Berechnet aggregierte Werte (Mittelwert, Summe, laufende Summe) in einem festen Raster über einen Zeitraum.</td><td></td></tr><tr><td><strong>GetLastAggregate</strong></td><td><code>agg: Aggregate</code>, <code>asset_id: int</code>, <code>subtype: str</code>, <code>attr: str</code>, <code>raster: str</code></td><td>Gibt die zuletzt berechnete kumulative Aggregation im ausgewählten Raster zurück (einschl. <code>last_ts</code>).</td><td></td></tr></tbody></table>

***

## Beispielskripte

### GetHeap

**Beschreibung:** Ruft den aktuellen Wert eines Attributs oder die gesamte JSON eines Assets aus dem Heap ab.

**Parameter:**

* `gai: str` (erforderlich) – GAI des Assets, z. B. `"K86_WP01"`
* `subtype: str` (erforderlich) – Datensubtyp, z. B. `"input"`
* `attribute: str` (erforderlich) – Attributname, z. B. `"Aussentemperatur"`

#### Beispielcode:

```python
value = eliona.GetHeap("K86_WP01", "input", "Aussentemperatur")
```

**Beispielausgabe:**

```python
23.5
```

***

### SetHeap

**Beschreibung:** Sendet ein Wörterbuch mit Werten an den Rechner, um diese zu verarbeiten und im Heap zu speichern.

**Parameter:**

* `gai: str` (erforderlich)
* `subtype: str` (erforderlich)
* `data: dict` (erforderlich) – z. B. `{"Aussentemperatur": 23.5}`
* `source: str` (erforderlich) – typischerweise `eliona.MakeSource(id)`

**Codebeispiel:**

```python
data   = {"Aussentemperatur": 23.5}
source = eliona.MakeSource(id)
eliona.SetHeap("K86_WP01", "input", data, source)
```

***

### GetAssetIDByGAI

**Beschreibung:** Gibt die numerische Asset-ID für die angegebene GAI zurück.

**Parameter:**

* `gai: str` (erforderlich)

**Codebeispiel:**

```python
asset_id = eliona.GetAssetIDByGAI("K86_WP01")
```

***

### GetAll

**Beschreibung:** Ruft alle Datenpunkte eines bestimmten Subtyps für eine Liste von Assets ab und gibt sie als Wörterbuch zurück (GAI → Daten).

**Parameter:**

* `ids: list[int|str]` (erforderlich) – z. B. `["K86_WP01", 1073]`
* `subtype: str` (erforderlich)

**Codebeispiel:**

```python
all_data = eliona.GetAll(["K86_WP01"], "input")

```

***

### SQLQuery

**Beschreibung:** Führt eine beliebige SQL-Abfrage aus und gibt die Ergebnisse als Liste von Tupeln zurück.

**Parameter:**

* `query: str` (erforderlich)

**Codebeispiel:**

```python
res = eliona.SQLQuery(
    "SELECT data->>'Aussentemperatur' "
    "FROM public.heap "
    "WHERE gai='K86_WP01' AND subtype='input' "
    "ORDER BY timestamp DESC LIMIT 1;"
)
```

**Beispielausgabe:**

```python
[('23.5',)]
```

***

### MakeSource

**Beschreibung:** Erzeugt einen Quellstring (z. B. `"ssr:123"`) für Heap-Operationen basierend auf der Funktions-ID.

**Parameter:**

* `id: int` (erforderlich)

**Codebeispiel:**

```python
src = eliona.MakeSource(id)
```

***

### OpenFile

**Beschreibung:** Öffnet eine Datei im Arbeitsverzeichnis von BuildingPro Suites (analog zu Python `open()`).

**Parameter:**

* `name: str` (erforderlich) – Dateiname, z. B. `"log.txt"`
* `mode: str` (erforderlich) – z. B. `"w"`, `"r"`

**Codebeispiel:**

```python
f = eliona.OpenFile("aussentemp_log.txt", "w")
f.write("Temperatur: 23.5\n")
f.close()
```

***

### AddAssetTag

**Beschreibung:** Fügt einem Asset ein Tag hinzu, wenn es noch nicht zugewiesen ist.

**Parameter:**

* `gai: str` (erforderlich)
* `tag: str` (erforderlich)

**Codebeispiel:**

```python
eliona.AddAssetTag("K86_WP01", "has-aussentemp")

```

***

### RemoveAssetTag

**Beschreibung:** Entfernt ein Tag von einem Asset, falls vorhanden.

**Parameter:**

* `gai: str` (erforderlich)
* `tag: str` (erforderlich)

**Codebeispiel:**

```python
eliona.RemoveAssetTag("K86_WP01", "has-aussentemp")
```

***

### GetTrendRecords

**Beschreibung:** Lädt eine Liste historischer Messwerte (`TrendRecord(ts, value)`) ab dem angegebenen Startzeitpunkt.

**Parameter:**

* `asset_id: int` (erforderlich)
* `subtype: str` (erforderlich)
* `attr: str` (erforderlich)
* `begin: datetime` (erforderlich)

**Codebeispiel:**

```python
from datetime import datetime, timedelta

aid   = eliona.GetAssetIDByGAI("K86_WP01")
begin = datetime.now() - timedelta(hours=1)
records = eliona.GetTrendRecords(aid, "input", "Aussentemperatur", begin)
```

***

### WriteTrendRecords

**Beschreibung:** Schreibt einen oder mehrere `TrendRecord` Datensätze in das System.

**Parameter:**

* `asset_id: int` (erforderlich)
* `subtype: str` (erforderlich)
* `attr: str` (erforderlich)
* `recs: TrendRecord | list[TrendRecord]` (erforderlich)

**Codebeispiel:**

```python
from datetime import datetime, timedelta
import eliona_types

aid = eliona.GetAssetIDByGAI("K86_WP01")
now = datetime.now()
r1  = eliona_types.TrendRecord(now, 18.7)
r2  = eliona_types.TrendRecord(now + timedelta(minutes=30), 19.2)
eliona.WriteTrendRecords(aid, "input", "Aussentemperatur", [r1, r2])

```

***

### GetAggregate

**Beschreibung:** Berechnet aggregierte Werte (Durchschnitt, Summe, kumulierte Summe) in einem festen Raster über einen Zeitraum.

**Parameter:**

* `agg: Aggregate` (erforderlich) – z. B. `eliona_types.Aggregate.Avg`
* `asset_id: int` (erforderlich)
* `subtype: str` (erforderlich)
* `attr: str` (erforderlich)
* `raster: str` (erforderlich) – ISO 8601-Dauer, z. B. `"PT1H"` für stündlich
* `start: datetime` (erforderlich)
* `end: datetime` (optional, Standard: `now()`)
* `recs: TrendRecord | list[TrendRecord]` (erforderlich)

**Codebeispiel:**

```python
from datetime import datetime, timedelta
import eliona_types

aid   = eliona.GetAssetIDByGAI("K86_WP01")
end   = datetime.now()
start = end - timedelta(days=1)
aggs  = eliona.GetAggregate(
    eliona_types.Aggregate.Avg,
    aid, "input", "Aussentemperatur",
    "PT1H", start, end
)
```

**Beispielausgabestruktur:**

```python
[
  TrendAggregate(ts=<datetime>, cnt=<int>, avg=<float>,
                 sum=<float>, first=<float>,
                 min=<float>, max=<float>, last=<float>),
  ...
]
```

***

### GetLastAggregate

**Beschreibung:** Gibt die zuletzt berechnete kumulative Aggregation im ausgewählten Raster zurück (einschließlich `last_ts`).

**Parameter:**

* `agg: Aggregate` (erforderlich)
* `asset_id: int` (erforderlich)
* `subtype: str` (erforderlich)
* `attr: str` (erforderlich)
* `raster: str` (erforderlich)

**Codebeispiel:**

```python
import eliona_types

aid  = eliona.GetAssetIDByGAI("K86_WP01")
last = eliona.GetLastAggregate(
    eliona_types.Aggregate.Cusum,
    aid, "input", "Aussentemperatur", "P1D"
)
```

**Beispielausgabestruktur:**

```python
RunningAggregate(
  ts=<datetime>, cnt=<int>, avg=<float>,
  sum=<float>, first=<float>,
  min=<float>, max=<float>, last=<float>,
  last_ts=<datetime>
)
```

***

### Einfaches Skript zur Datenmanipulation

Dieses Beispiel zeigt, wie ein Skript einen Zufallswert erzeugt und in den Heap eines Assets schreibt:

```python
def UserFunction(id, eliona):
    import random

    data = {
        "power_val": random.randint(10, 100)
    }

    eliona.SetHeap("TestInactIn", "input", data, eliona.MakeSource(id))
```

**Beschreibung:**

* Das Skript importiert das `random` Modul.
* Ein Wörterbuch `data` wird erstellt, das einen Schlüssel `power_val`enthält, dem ein Zufallswert zwischen 10 und 100 zugewiesen wird.
* Der erzeugte Wert wird in den Heap des `TestInactIn` Assets geschrieben unter Verwendung des `SetHeap` Methode.

***

## Daten abrufen und ändern

In diesem Beispiel wird der Wert eines Attributs von einem Asset abgerufen, geändert und in einem anderen Asset gespeichert:

```python
def UserFunction(id, eliona):
    from datetime import datetime

    heap = eliona.GetHeap("TestInactIn", "input")

    data = {
        "energy_val": heap["power_val"] * 3
    }

    eliona.SetHeap("TestInactIn", "input", data, eliona.MakeSource(id))
```

**Beschreibung:**

* Das Skript importiert das `datetime` Modul.
* Der aktuelle Wert des `power_val` Attributs wird aus dem Heap des `TestInactIn` Assets abgerufen.
* Dieser Wert wird verdreifacht und als `energy_val`.

***

## Erweiterte Funktionen und SQL-Abfragen

Mit der `SQLQuery` Methode können beliebige SQL-Abfragen direkt aus dem Skript ausgeführt werden:

```python
def UserFunction(id, eliona):
    result = eliona.SQLQuery("SELECT * FROM public.asset WHERE gai = 'TestInactIn';")
    # Weitere Verarbeitung des Ergebnisses
```

**Beschreibung:**

* Die SQL-Abfrage ruft alle Informationen über das Asset mit der GAI ab `TestInactIn`.
* Das Ergebnis kann anschließend weiterverarbeitet werden.
