---
title: "SpotLogic – battery optimisation over the spot market (HTTP API)"
description: "SpotLogic cloud API over HTTPS: reads the spot-market battery command, target charge and plan age; uploads battery telemetry. Forecast series required."
url: "https://taphome.com/en/compatibility/spotlogic-energy-optimizer-http/"
language: en
lastmod: 2026-11-10
generator: hugo
ai:
  topics: ["http","cloud-api","data-service","energy-management","battery-storage","spot-prices","photovoltaic"]
  questions: ["How to integrate SpotLogic with TapHome?","What does the SpotLogic TapHome template read and upload?","How to connect TapHome to the SpotLogic API over HTTPS?","Where do I get the SpotLogic PLC ID and access token?","Why does the SpotLogic command stay at No plan?","Why does SpotLogic reject the telemetry with HTTP 422?","Which forecast and price series does SpotLogic need from TapHome?","Does the SpotLogic template control the inverter directly?"]
---

# SpotLogic – battery optimisation over the spot market (HTTP API)

Communication: Packet Parser → HTTP

## Integration guide

SpotLogic is a cloud service that computes a charge and discharge plan for a photovoltaic battery over the spot electricity market. It is a calculation service, not a data source: the control unit sends battery telemetry together with the PV generation forecast, the house consumption forecast and the import and export prices, and SpotLogic answers with the command for the current time slot. This template connects TapHome to the SpotLogic API over HTTPS (`spotlogic.cz`, port 443) with a Packet Parser HTTP module. It **reads** the command and **uploads** the telemetry; it does not control the inverter — the command is connected to the inverter with the installer's own smart rules.

There is nothing to wire. Setting up the service means activating SpotLogic for the site, collecting the battery and grid parameters, giving the control unit outgoing internet access and preparing the forecast and price series.

> [!WARNING]
> SpotLogic needs forecast and price series in every telemetry upload (PV generation and house consumption for today and tomorrow, import and export prices). This template cannot fill them on its own — see [Forecast and price series](https://taphome.com/en/compatibility/spotlogic-energy-optimizer-http/#forecast-and-price-series). Until they are filled, SpotLogic rejects the telemetry with HTTP 422, does not compute a plan, and the command stays at **No plan**.

## Configuration

### 1. Activate SpotLogic and keep the credentials

SpotLogic sends the **PLC ID** and the **access token** by e-mail when the device is activated. The token is secret, bound to exactly one PLC ID and valid for the subscription period. Both travel only in the query string of each request (`?plc_id=…&token=…`), as the SpotLogic contract requires — never in the request body.

> [!WARNING]
> Keep the token out of shared documents and public repositories. A wrong PLC ID and token pair, an invalid token or an expired subscription all end with HTTP 401, and SpotLogic deliberately does not say which of the three it was.

### 2. Collect the battery and grid parameters

SpotLogic plans only with the numbers it receives in the telemetry. Before the import, look them up in the inverter and battery documentation and in the grid connection contract:

| Value | Where it comes from | Unit |
|---|---|---|
| Battery capacity | battery data sheet; must be greater than 0 | kWh |
| Battery max power | one value for charging and discharging | kW |
| Max grid import power | size of the main breaker; `0` means the site never imports | kW |
| Max grid export power | export limit of the grid connection; `0` means the site never exports | kW |
| Hard battery floor | lowest state of charge allowed by the inverter manufacturer, default 10 | % |
| Battery reserve | reserve the plan never sells to the grid from (for example for unpredictable consumption), default 10 | % |

The **current state of charge** of the battery must also be available in TapHome, typically from the inverter's own integration, so that a smart rule can write it into this template (see Uploading telemetry below).

### 3. Network and clock of the control unit

- The control unit needs outgoing internet access over HTTPS to `spotlogic.cz` on port 443. SpotLogic does not connect back to the control unit — the forecast and price series travel in the body of the telemetry upload, so no inbound port has to be opened.
- The telemetry carries the time of sending from the control unit clock, and SpotLogic builds the plan window from it. A few minutes of drift is harmless; hours of drift move the whole plan to the wrong slots. Keep the control unit clock correct.
- The time zone (IANA name, for example `Europe/Prague`) decides where "today" ends and "tomorrow" begins. Enter the zone of the site.

### 4. Import parameters

The template is imported into the Packet Parser interface of the TapHome app, and the following parameters are filled in at import:

| Parameter | Meaning | Unit |
|---|---|---|
| PLC ID, access token | from the activation e-mail | — |
| Time zone | IANA name, default `Europe/Prague`; day boundaries of the plan come from it | — |
| Battery capacity | must be greater than 0 | kWh |
| Battery max power | one value for charging and discharging | kW |
| Max grid import / export power | `0` means the site never imports / never exports | kW |
| Max state of charge | recorded by SpotLogic only, the current planner does not enforce it | % |
| Hard battery floor | floor from the inverter manufacturer, default 10 | % |

Numbers are written with a decimal point (a comma is converted). The PLC ID and the token are stored in the module variables `PlcId` and `Token`. All values stay editable afterwards as module variables.

### 5. Checking the credentials

The interactive API documentation of SpotLogic (on `spotlogic.cz` under `/docs`) has an **Authorize** dialog for the PLC ID and the token, and its TapHome telemetry example is complete: with valid credentials SpotLogic accepts it with HTTP 202. Update its time of sending (`TimeStampUnix`) to the current time first. Accepted example data are buffered for a plan like real telemetry, so this check belongs before the command is connected to the inverter.

> [!TIP]
> An HTTP 422 answer about an incomplete forecast horizon also proves that the PLC ID and the token are correct — a wrong token gives HTTP 401.

## Device capabilities

### Reading the command (every 20 s)

The module polls `GET /api/v1/dispatch` every 20 seconds and the devices parse the answer:

- **SpotLogic command** — command for the slot in progress (`action_id`):

| Value | TapHome value | SpotLogic name | Meaning |
|---|---|---|---|
| 0 | No plan | `no_plan` | No usable plan — keep the inverter in its own safe mode |
| 1 | Self-use | `self_use` | Self-consumption: charge from PV surplus, discharge to cover the house |
| 2 | Force charge | `force_charge` | Charge the battery at maximum power |
| 3 | Force discharge to grid | `force_discharge` | Discharge the battery to the grid at maximum power |
| 4 | Self-use, no discharging | `self_use_ChargeOnly` | Self-consumption, charging allowed, discharging forbidden |
| 5 | Self-use, no charging | `self_use_DischargeOnly` | Self-consumption, discharging allowed, charging forbidden |
| 6 | Stop PV (reserved) | `stopPV` | Reserved — not issued by the current planner |
| 7 | Grid charge without PV (reserved) | `ChargeMaxNoPV` | Reserved — not issued by the current planner |

  Service attributes show the command name and when the command ends (local time).
- **SpotLogic target state of charge** — state of charge (%) the plan expects at the end of the slot. Stop forced charging or discharging when the battery reaches it; with self-use do not charge above it. SpotLogic adds that with `self_use_DischargeOnly` the battery should not be discharged below it. The value is a result of the plan, not a setpoint that has to be forced, and it may temporarily be lower than the battery reserve after the house consumed the reserve.
- **SpotLogic next command** — the command of the following slot, with its start time as a service attribute.
- **SpotLogic plan age** — age of the served plan in seconds. It can drive a fallback smart rule: when it grows well above the recompute interval, the plan is not being recomputed.

The answer HTTP 404 `no_plan` is **not an error**: the command is 0 and the device shows an information message. SpotLogic asks to switch to the inverter's own safe mode in that state and never to repeat the last known command from memory. HTTP 401 (wrong PLC ID or token, expired subscription) sets an error on the devices and on the module; SpotLogic asks not to repeat such calls, so fix the credentials.

### Uploading telemetry (about every 2 minutes)

The module sends `POST /api/v1/optimize` with `PLCtype: "taphome"` at most every 2 minutes. It sends the time of sending, the time zone, the battery and grid parameters and two values from devices:

- **Battery state of charge (input)** — write the current state of charge 0–100 % from the inverter with a smart rule (when the inverter template gives 0–1, multiply by 100). It is rounded to a whole percent, because SpotLogic rejects fractional values. Until it has a value, nothing is sent and the module shows a warning.
- **Battery reserve for SpotLogic** — the `SOCmin` reserve, default 10 %: the level the plan never sells to the grid from.

The module service attributes show the result of the last upload, the recompute interval reported by SpotLogic (default 900 s), when the plan was computed, the plan run and the API version. A rejected upload (HTTP 422) is a module error with the message SpotLogic returned. The upload answer never contains the plan — SpotLogic computes it in the background and the module picks it up with the next command reading.

### Forecast and price series

SpotLogic expects six series in the body, each as pairs `[unix_ts, value]`:

| Module variable | Content | Contract |
|---|---|---|
| `PvForecastTod`, `PvForecastTom` | PV generation today / tomorrow, kWh per hour | hourly, without gaps, from the current hour to the end of tomorrow |
| `LoadForecastTod`, `LoadForecastTom` | house consumption today / tomorrow, kWh per hour | the same |
| `PriceImp`, `PriceExp` | import / export price, CZK/kWh | constant cadence (hourly or 15 minutes), today is enough, negative prices allowed |

The variables hold the series as JSON text, for example `[[1788645600,0.0],[1788649200,0.42]]`, and are inserted into the body unchanged; the default `[]` is an empty series. The integration itself works; what it needs is the data. TapHome cannot yet share one JSON text between scripts, and a smart rule script cannot send HTTP requests. The six series — about 500 values together — therefore have to be collected from other scripts (for example a forecast or spot-price template) and handed over to this module through hundreds of helper devices, or built in the module read script itself. The integration becomes really practical once TapHome adds a text variable shared between scripts — see the idea [Text variable and HTTP from smart rule scripts](https://taphome.com/en/ideas/script-data-http/). Until then, fill the six variables and the template works as is. The script explains this in a comment at its top and at the place where the series are inserted.

Where the data come from is up to the installer; SpotLogic names these typical sources:

- **PV generation** — a PV forecast service fed with the location, orientation and tilt of the panels and the installed power, or the inverter manufacturer's cloud.
- **House consumption** — the site's own history: hourly consumption averaged by hour of day and type of day (working day, weekend, holiday) is enough to start with.
- **Prices** — the spot price recalculated by the supply contract (import, for example spot plus a margin) and by the contract for selling surplus energy (export).

A day with a daylight-saving change has 23 or 25 hours, so a complete PV or consumption series has 47, 48 or 49 values. Samples older than one hour before the current hour are cropped, as are samples beyond the end of tomorrow; a series that ends before the end of tomorrow is rejected.

## Troubleshooting

| Symptom | Cause and solution |
|---|---|
| Command stays at **No plan** | No plan has been computed yet, or the telemetry is rejected. Check the module error and the service attribute Last telemetry upload. A plan older than 60 minutes is not served either. After the first accepted upload the plan can take a while — at least one recompute interval. |
| Module error HTTP 422 | The telemetry violates the SpotLogic data contract; the message says which part. Most often the forecast or price series are missing or do not cover the period up to the end of tomorrow. |
| Error HTTP 401 | PLC ID and token do not match or the subscription expired. Correct the module variables `PlcId` and `Token`. |
| Warning "Telemetry not sent" | The state of charge has not been written yet, or a battery or grid parameter is empty. |
| Plan age keeps growing | New telemetry is not reaching SpotLogic or its data sources fail; the last valid plan stays in force until it is 60 minutes old. |
| Error HTTP 500 or 502 | Server error or failing data source on the SpotLogic side; the last valid plan stays in force. SpotLogic recommends repeating both with growing delays; the module simply repeats both requests on the next poll. |
| Plan steers the wrong hours | The control unit clock or the time zone is wrong — the plan window is built from the time of sending and the declared zone. |

## Available devices 6

These devices appear in TapHome after import.

SpotLogic Module

Service Attributes

|                         |
|-------------------------|
| Last telemetry upload   |
| Plan recompute interval |
| Plan computed at        |
| Plan run                |
| API version             |

Custom Variables

|                                  |
|----------------------------------|
| `PlcId` (string)                 |
| `Token` (string)                 |
| `TimeZone` (string)              |
| `BatCapacity` (string)           |
| `BatPmax` (string)               |
| `GridImportPmax` (string)        |
| `GridExportPmax` (string)        |
| `SocMax` (string)                |
| `SocHardMin` (string)            |
| `SocNow` (numeric) = -1          |
| `SocMin` (numeric) = 10          |
| `PvForecastTod` (string) = \[]   |
| `PvForecastTom` (string) = \[]   |
| `LoadForecastTod` (string) = \[] |
| `LoadForecastTom` (string) = \[] |
| `PriceImp` (string) = \[]        |
| `PriceExp` (string) = \[]        |
| `DispatchJson` (string)          |
| `DispatchCode` (numeric)         |
| `OptimizeJson` (string)          |
| `OptimizeCode` (numeric)         |
| `OptimizeAt` (string)            |
| `LastOptimizeUnix` (numeric)     |

Read (module)

```taphome
# =============================================================================
#  STATUS: WORKING, BUT THE DATA MUST BE BROUGHT IN BY HAND
# =============================================================================
#  The integration itself works - dispatch reading, action_id -> inverter mode
#  mapping, next command, plan diagnostics and error reporting are finished.
#  What it needs is the data: six series (PV forecast, load forecast, import and
#  export spot price; ~500 values, hourly or 15-minute, horizon now -> end of
#  tomorrow) as JSON text [[unix_ts, value], ...] in the module variables
#  PvForecastTod ... PriceExp (see below).
#  Until TapHome ships a shared variable between scripts, those series must be
#  collected from other scripts and handed over through hundreds of helper
#  devices - that is why the integration is only really practical once that
#  feature lands.
#  Tracking: https://taphome.com/cs/ideas/script-data-http/  (TapHome idea FR-003)
#  In the meantime: fill the six variables below and the template works as is.
# =============================================================================

# 1) GET /api/v1/dispatch - the command for the slot in progress (module poll ~20 s).
#    plc_id and token travel ONLY in the query string (SpotLogic contract).
VAR r := SENDHTTPREQUEST("/api/v1/dispatch?plc_id=" + PlcId + "&token=" + Token);
DispatchCode := r.StatusCode;
DispatchJson := r.Content;
IF r.StatusCode = 401
    ADDERROR(1, "SpotLogic rejected the PLC ID or the token (HTTP 401) - check the module variables PlcId and Token; the subscription may have expired. Not retried by SpotLogic rules, fix the credentials.");
ELSEIF r.StatusCode != 200 AND r.StatusCode != 404
    VAR dmsg := PARSEJSON(r.Content, "$.message", true);
    ADDERROR(2, "SpotLogic dispatch failed: HTTP " + r.StatusCode + IF(ISNULL(dmsg), "", " " + dmsg));
END

# 2) POST /api/v1/optimize - telemetry, at most every ~2 min (SpotLogic asks for no more often).
datetime now := NOW();
VAR nowUnix := now.UNIXTIME;
IF nowUnix - LastOptimizeUnix >= 115
    LastOptimizeUnix := nowUnix;
    VAR cap := TODOUBLE(REPLACE(BatCapacity, ",", "."));
    VAR bp := TODOUBLE(REPLACE(BatPmax, ",", "."));
    VAR gi := TODOUBLE(REPLACE(GridImportPmax, ",", "."));
    VAR ge := TODOUBLE(REPLACE(GridExportPmax, ",", "."));
    VAR smax := TODOUBLE(SocMax);
    VAR shard := TODOUBLE(SocHardMin);
    IF SocNow < 0 OR SocNow > 100
        OptimizeCode := -1;
    ELSEIF ISNAN(cap) OR ISNAN(bp) OR ISNAN(gi) OR ISNAN(ge) OR ISNAN(smax) OR ISNAN(shard) OR LENGTH(PlcId) = 0 OR LENGTH(Token) = 0
        OptimizeCode := -2;
    ELSE
        # Forecast and price series: module variables PvForecastTod, PvForecastTom,
        # LoadForecastTod, LoadForecastTom, PriceImp, PriceExp hold JSON text
        # [[unix_ts, value], ...]. The template does NOT fill them - see the banner
        # at the top of this script. Until they are filled, SpotLogic answers 422.
        VAR body := "{\"PLCtype\":\"taphome\"";
        body := body + ",\"TimeZone\":\"" + TimeZone + "\"";
        body := body + ",\"TimeStampUnix\":" + TOSTRING(nowUnix, "F0");
        body := body + ",\"BatCapacity\":" + TOSTRING(cap, "F2");
        body := body + ",\"BatPmax\":" + TOSTRING(bp, "F2");
        body := body + ",\"GridImportPmax\":" + TOSTRING(gi, "F2");
        body := body + ",\"GridExportPmax\":" + TOSTRING(ge, "F2");
        body := body + ",\"SOCnow\":" + TOSTRING(SocNow, "F0");
        body := body + ",\"SOCmin\":" + TOSTRING(SocMin, "F0");
        body := body + ",\"SOCmax\":" + TOSTRING(smax, "F0");
        body := body + ",\"SOChardmin\":" + TOSTRING(shard, "F0");
        body := body + ",\"PvForecastTod\":" + PvForecastTod;
        body := body + ",\"PvForecastTom\":" + PvForecastTom;
        body := body + ",\"LoadForecastTod\":" + LoadForecastTod;
        body := body + ",\"LoadForecastTom\":" + LoadForecastTom;
        body := body + ",\"PriceImp\":" + PriceImp;
        body := body + ",\"PriceExp\":" + PriceExp + "}";
        VAR o := SENDHTTPREQUEST("/api/v1/optimize?plc_id=" + PlcId + "&token=" + Token, "POST", body, "Content-Type: application/json");
        OptimizeCode := o.StatusCode;
        OptimizeJson := o.Content;
        OptimizeAt := TOSTRING(now, "yyyy-MM-dd HH:mm:ss");
    END
END

# The outcome of the last telemetry upload is reported on every run, not only on the upload run.
VAR omsg := "";
IF LENGTH(OptimizeJson) > 0
    omsg := PARSEJSON(OptimizeJson, "$.message", true);
    IF ISNULL(omsg)
        omsg := "";
    END
END
IF OptimizeCode = -1
    ADDWARNING(3, "Telemetry not sent: the device Battery state of charge (input) has no value 0-100 yet - write it from the inverter with a smart rule.");
ELSEIF OptimizeCode = -2
    ADDWARNING(7, "Telemetry not sent: fill the module variables PlcId, Token, BatCapacity, BatPmax, GridImportPmax, GridExportPmax, SocMax and SocHardMin (numbers with a decimal point).");
ELSEIF OptimizeCode = 401
    ADDERROR(4, "SpotLogic rejected the telemetry: PLC ID or token invalid (HTTP 401).");
ELSEIF OptimizeCode = 422
    ADDERROR(5, "SpotLogic rejected the telemetry (HTTP 422): " + omsg + " - the forecast and price series (module variables PvForecastTod ... PriceExp) must be filled, see the template description.");
ELSEIF OptimizeCode != 0 AND OptimizeCode != 202
    ADDERROR(6, "SpotLogic telemetry upload failed: HTTP " + OptimizeCode + " " + omsg);
END
```

Service Attributes

Last telemetry upload

```taphome
IF(OptimizeCode = 0, "not sent yet", IF(OptimizeCode < 0, "waiting for inputs", "HTTP " + OptimizeCode + " at " + OptimizeAt))
```

Plan recompute interval

```taphome
VAR v := PARSEJSON(OptimizeJson, "$.data.recompute_interval_sec", true);
IF ISNULL(v)
    RETURN("-");
END
RETURN(TOSTRING(v, "F0") + " s");
```

Plan computed at

```taphome
VAR s := PARSEJSON(DispatchJson, "$.meta.plan_created_at", true);
IF ISNULL(s)
    RETURN("-");
END
datetime t := DATETIME(s);
VAR l := t.LOCALDATETIME;
RETURN(TOSTRING(l, "yyyy-MM-dd HH:mm"));
```

Plan run

```taphome
VAR v := PARSEJSON(DispatchJson, "$.meta.run_id", true);
RETURN(IF(ISNULL(v), "-", v));
```

API version

```taphome
VAR v := PARSEJSON(DispatchJson, "$.meta.version.api", true);
RETURN(IF(ISNULL(v), "-", v));
```

SpotLogic command Multi-value Switch

Values / States: No plan · Self-use · Force charge · Force discharge to grid · Self-use, no discharging · Self-use, no charging · Stop PV (reserved) · Grid charge without PV (reserved)

Read switch state

```taphome
IF DispatchCode = 0
    RETURN(NaN);
END
IF DispatchCode = 401
    ADDERROR(1, "SpotLogic rejected the PLC ID or the token (HTTP 401) - check the module variables PlcId and Token.");
    RETURN(NaN);
END
IF DispatchCode = 404
    ADDINFO(2, "No usable plan yet (no_plan) - keep the inverter in its own safe mode.");
    RETURN(0);
END
IF DispatchCode != 200
    ADDERROR(3, "Command not available: HTTP " + DispatchCode);
    RETURN(NaN);
END
VAR id := PARSEJSON(DispatchJson, "$.data.command.action_id", true);
IF ISNULL(id)
    ADDERROR(4, "Unexpected SpotLogic answer: data.command.action_id is missing.");
    RETURN(NaN);
END
RETURN(id);
```

Service Attributes

Command name

```taphome
VAR v := PARSEJSON(DispatchJson, "$.data.command.action_name", true);
IF ISNULL(v)
    v := PARSEJSON(DispatchJson, "$.data.action_name", true);
END
RETURN(IF(ISNULL(v), "-", v));
```

Command valid until

```taphome
VAR s := PARSEJSON(DispatchJson, "$.data.command.valid_until", true);
IF ISNULL(s)
    RETURN("-");
END
datetime t := DATETIME(s);
VAR l := t.LOCALDATETIME;
RETURN(TOSTRING(l, "yyyy-MM-dd HH:mm"));
```

SpotLogic target state of charge Variable

Read

```taphome
IF DispatchCode = 0
    RETURN(NaN);
END
IF DispatchCode = 401
    ADDERROR(1, "SpotLogic rejected the PLC ID or the token (HTTP 401) - check the module variables PlcId and Token.");
    RETURN(NaN);
END
IF DispatchCode != 200
    RETURN(NaN);
END
VAR v := PARSEJSON(DispatchJson, "$.data.command.target_soc_percent", true);
IF ISNULL(v)
    RETURN(NaN);
END
RETURN(v);
```

SpotLogic next command Multi-value Switch

Values / States: No plan · Self-use · Force charge · Force discharge to grid · Self-use, no discharging · Self-use, no charging · Stop PV (reserved) · Grid charge without PV (reserved)

Read switch state

```taphome
IF DispatchCode = 0
    RETURN(NaN);
END
IF DispatchCode = 401
    ADDERROR(1, "SpotLogic rejected the PLC ID or the token (HTTP 401) - check the module variables PlcId and Token.");
    RETURN(NaN);
END
IF DispatchCode = 404
    RETURN(0);
END
IF DispatchCode != 200
    ADDERROR(3, "Next command not available: HTTP " + DispatchCode);
    RETURN(NaN);
END
VAR id := PARSEJSON(DispatchJson, "$.data.context.next_action_id", true);
IF ISNULL(id)
    RETURN(NaN);
END
RETURN(id);
```

Service Attributes

Next command name

```taphome
VAR v := PARSEJSON(DispatchJson, "$.data.context.next_action_name", true);
RETURN(IF(ISNULL(v), "-", v));
```

Next command starts

```taphome
VAR s := PARSEJSON(DispatchJson, "$.data.context.next_action_time", true);
IF ISNULL(s)
    RETURN("-");
END
datetime t := DATETIME(s);
VAR l := t.LOCALDATETIME;
RETURN(TOSTRING(l, "yyyy-MM-dd HH:mm"));
```

SpotLogic plan age Variable

Read

```taphome
IF DispatchCode = 0
    RETURN(NaN);
END
IF DispatchCode = 401
    ADDERROR(1, "SpotLogic rejected the PLC ID or the token (HTTP 401) - check the module variables PlcId and Token.");
    RETURN(NaN);
END
IF DispatchCode != 200
    RETURN(NaN);
END
VAR v := PARSEJSON(DispatchJson, "$.meta.plan_age_sec", true);
IF ISNULL(v)
    RETURN(NaN);
END
RETURN(v);
```

Battery state of charge (input) Variable

Read

```taphome
IF(SocNow < 0, NaN, SocNow)
```

Write

```taphome
SocNow := Va;
```

Battery reserve for SpotLogic Variable

Read

```taphome
RETURN(SocMin);
```

Write

```taphome
SocMin := Va;
```

**Connection:** Packet Parser → HTTP

## Import parameters

Enter these values when you import the XML.

| Asked in the app                                            | Default         |
|-------------------------------------------------------------|-----------------|
| SpotLogic PLC ID (from the activation e-mail)               | Enter at import |
| SpotLogic access token (from the activation e-mail, secret) | Enter at import |
| Time zone (IANA name)                                       | `Europe/Prague` |
| Battery capacity \[kWh]                                     | Enter at import |
| Battery max charge and discharge power \[kW]                | Enter at import |
| Max grid import power \[kW] (0 = never import)              | Enter at import |
| Max grid export power \[kW] (0 = never export)              | Enter at import |
| Max state of charge \[%] (recorded only)                    | `100`           |
| Hard battery floor from the inverter manufacturer \[%]      | `10`            |

## Related Documentation

- [Packet Parser Integration](https://taphome.com/en/compatibility/packet-parser-guide/)
- [Packet Parser (HTTP, TCP, UDP, FTP, MQTT)](https://taphome.com/en/docs/integration/packet-parser/)
- [Packet parser functions](https://taphome.com/en/docs/script/packet-parser/)
- [Parsing functions](https://taphome.com/en/docs/script/parsing-functions/)

