# Write Python scripts

{% hint style="warning" %}
With the introduction of Eliona Version 12.2, important changes were made that require scripts to be adapted in order to use the new API design.
{% endhint %}

## Script definition

When a new script is created in the Eliona system, a function header is generated automatically. This header contains two parameters:

* **`id`**: The unique ID of the script.
* **`eliona`**: An object through which the user can interact with the Eliona system.

The function header looks as follows:

```python
# you may add imports only inside the function
# don't change or delete the function definition
def UserFunction(id, eliona):
	# add your code here
```

### Importing modules

All necessary modules must be imported within the function. It is important that modules are imported only within the function and that no global imports are used.

Example:

```python
def UserFunction(id, eliona):
    import random
    # More lines of code follow
```

***

## Methods of the Eliona object

The **`eliona`**-object provides a range of methods that enable users to interact with the Eliona system. Here are the most important methods together with their parameters and descriptions:

<table data-full-width="true"><thead><tr><th width="173">Method</th><th>Parameters</th><th>Description</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>Retrieves the current value of an attribute or the entire data JSON of an asset from the heap.</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>Sends data to the Calculator to process it and store it in the heap.</td></tr><tr><td><strong>GetAssetIDByGAI</strong></td><td><code>gai: str</code></td><td>Returns the numeric asset ID for the specified GAI.</td></tr><tr><td><strong>GetAll</strong></td><td><code>ids: list[intstr], subtype: str</code></td><td>Retrieves all data for a list of assets identified by their IDs and a subtype.</td></tr><tr><td><strong>SQLQuery</strong></td><td><code>query: str</code></td><td>Executes any SQL query and returns the results as a list of tuples.</td></tr><tr><td><strong>MakeSource</strong></td><td><code>id: int</code></td><td>Creates a source string for heap operations based on the function ID.</td></tr><tr><td><strong>OpenFile</strong></td><td><code>name: str</code>, <code>mode: str</code></td><td>Opens a file in the Eliona working directory (analogous to Python’s <code>open()</code>).</td></tr><tr><td><strong>AddAssetTag</strong></td><td><code>gai: str</code>, <code>tag: str</code></td><td>Adds a tag to an asset (if not already present).</td></tr><tr><td><strong>RemoveAssetTag</strong></td><td><code>gai: str</code>, <code>tag: str</code></td><td>Removes a tag from an asset (if present).</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>Retrieves historical measured values as a list of <code>TrendRecord(ts, value)</code> from the specified time onward.</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>Writes one or more <code>TrendRecord</code>-records into the system.</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>Calculates aggregated values (Avg, Sum, Cusum) in a fixed raster over a period of time.</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>Returns the most recent cumulative aggregate in the selected raster (incl. <code>last_ts</code>).</td></tr></tbody></table>

***

## Example scripts

### GetHeap

**Description:**\
Retrieves the current value of an attribute or the entire JSON of an asset from the heap.

**Parameters:**

* `gai: str` (required) – GAI of the asset, e.g. `"K86_WP01"`
* `subtype: str` (required) – data subtype, e.g. `"input"`
* `attribute: str` (required) – attribute name, e.g. `"Aussentemperatur"`

**Code example:**

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

**Example output:**

```
23.5
```

***

### SetHeap

**Description:**\
Sends a dictionary of values to the Calculator to process them and store them in the heap.

**Parameters:**

* `gai: str` (required)
* `subtype: str` (required)
* `data: dict` (required) – e.g. `{"Aussentemperatur": 23.5}`
* `source: str` (required) – typically `eliona.MakeSource(id)`

**Code example:**

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

***

### GetAssetIDByGAI

**Description:**\
Returns the numeric asset ID for the specified GAI.

**Parameters:**

* `gai: str` (required)

**Code example:**

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

***

### GetAll

**Description:**\
Retrieves all data points of a specific subtype for a list of assets and returns them as a dictionary (GAI → data).

**Parameters:**

* `ids: list[int|str]` (required) – e.g. `["K86_WP01", 1073]`
* `subtype: str` (required)

**Code example:**

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

***

### SQLQuery

**Description:**\
Executes any SQL query and returns the results as a list of tuples.

**Parameters:**

* `query: str` (required)

**Code example:**

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

**Example output:**

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

***

### MakeSource

**Description:**\
Creates a source string (e.g. `"ssr:123"`) for heap operations based on the function ID.

**Parameters:**

* `id: int` (required)

**Code example:**

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

***

### OpenFile

**Description:**\
Opens a file in the Eliona working directory (analogous to Python’s `open()`).

**Parameters:**

* `name: str` (required) – file name, e.g. `"log.txt"`
* `mode: str` (required) – e.g. `"w"`, `"r"`

**Code example:**

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

***

### AddAssetTag

**Description:**\
Adds a tag to an asset if it has not already been assigned.

**Parameters:**

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

**Code example:**

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

***

### RemoveAssetTag

**Description:**\
Removes a tag from an asset, if present.

**Parameters:**

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

**Code example:**

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

***

### GetTrendRecords

**Description:**\
Loads a list of historical measured values (`TrendRecord(ts, value)`) from the specified start time.

**Parameters:**

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

**Code example:**

```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

**Description:**\
Writes one or more `TrendRecord`-records into the system.

**Parameters:**

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

**Code example:**

```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

**Description:**\
Calculates aggregated values (average, sum, cumulative sum) in a fixed raster over a period of time.

**Parameters:**

* `agg: Aggregate` (required) – e.g. `eliona_types.Aggregate.Avg`
* `asset_id: int` (required)
* `subtype: str` (required)
* `attr: str` (required)
* `raster: str` (required) – ISO 8601 duration, e.g. `"PT1H"` for hourly
* `start: datetime` (required)
* `end: datetime` (optional, default: `now()`)

**Code example:**

```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
)
```

**Example output structure:**

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

***

### GetLastAggregate

**Description:**\
Returns the most recent cumulative aggregate in the selected raster (including `last_ts`).

**Parameters:**

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

**Code example:**

```python
import eliona_types

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

**Example output structure:**

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

***

### Simple script for manipulating data

This example shows how a script generates a random value and writes it to the heap of an asset:

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

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

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

**Description:**

* The script imports the module `random`.
* A dictionary `data` is created, containing a key `power_val` to which a random value between 10 and 100 is assigned.
* The generated value is written to the asset heap with the method `SetHeap` in the heap of the asset `TestInactIn` written.

***

### Retrieve and modify data

In this example, the value of an attribute is retrieved from one asset, modified, and stored in another asset:

```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))
```

**Description:**

* The script imports the module `datetime`.
* The current value of the attribute `power_val` is retrieved from the heap of the asset `TestInactIn` is retrieved.
* This value is tripled and written as `energy_val` to the same asset.

***

### Advanced functions and SQL queries

With the method `SQLQuery` any SQL queries can be executed directly from the script:

```python
def UserFunction(id, eliona):
    result = eliona.SQLQuery("SELECT * FROM public.asset WHERE gai = 'TestInactIn';")
    # Further processing of the result
```

**Description:**

* The SQL query retrieves all information about the asset with the GAI `TestInactIn` .
* The result can then be processed further.
