Initial SolarEdge Optimizer Home Assistant App
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
# SolarEdge internal optimizer API
|
||||
|
||||
> Status: experimental and unsupported. This document describes calls observed
|
||||
> in the SolarEdge Monitoring web portal on 2026-08-09. SolarEdge can change or
|
||||
> remove them without notice.
|
||||
|
||||
## Why a second client is required
|
||||
|
||||
The official API at `https://monitoringapi.solaredge.com` does not expose
|
||||
per-optimizer measurements. Its API key is rejected by the internal portal
|
||||
endpoints with HTTP 401.
|
||||
|
||||
The Monitoring portal instead uses an OAuth2 authorization-code flow with PKCE:
|
||||
|
||||
1. Load the hosted SolarEdge/AWS Cognito login form.
|
||||
2. Submit the configured portal username and password together with the CSRF
|
||||
token and login cookies.
|
||||
3. Exchange the returned authorization code for OAuth tokens.
|
||||
4. Exchange those tokens at `/services/auth/token?legacy=false` for a Monitoring
|
||||
portal session.
|
||||
5. Send both the bearer access token and session cookies to internal services.
|
||||
6. Refresh the session through `POST /services/auth/refresh` when necessary.
|
||||
|
||||
`SolarEdgePortalClient` performs this flow with HTTP requests and a memory-only
|
||||
cookie jar. It does not start or depend on a browser. Tokens and cookies are not
|
||||
persisted to disk.
|
||||
|
||||
## Configuration
|
||||
|
||||
Keep all values on the server:
|
||||
|
||||
```env
|
||||
SOLAREDGE_SITE_ID=...
|
||||
SOLAREDGE_USERNAME=owner@example.com
|
||||
SOLAREDGE_PASSWORD=...
|
||||
```
|
||||
|
||||
Do not use the `EXPO_PUBLIC_` prefix. Values with that prefix are embedded in
|
||||
the client application and are not secret.
|
||||
|
||||
```ts
|
||||
import { createSolarEdgePortalClientFromEnv } from "@solar-dash/solaredgeapi";
|
||||
|
||||
const portal = createSolarEdgePortalClientFromEnv();
|
||||
await portal.authenticate();
|
||||
```
|
||||
|
||||
## Observed endpoints
|
||||
|
||||
### Logical layout including optimizers
|
||||
|
||||
```http
|
||||
GET /services/layout/logical/generic/v2/site/{siteId}?include-optimizers=true
|
||||
```
|
||||
|
||||
```ts
|
||||
const layout = await portal.getLogicalLayout();
|
||||
const optimizerSerials = await portal.listOptimizerSerials();
|
||||
const optimizerMappings = await portal.listOptimizerMappings();
|
||||
```
|
||||
|
||||
The response contains the site's logical device tree and optimizer serials.
|
||||
`listOptimizerSerials()` traverses that tree and returns only nodes whose type
|
||||
is `OPTIMIZER`. The raw layout is deliberately typed as a generic object because
|
||||
this undocumented structure is more likely to change.
|
||||
|
||||
`listOptimizerMappings()` preserves SolarEdge's logical position fields:
|
||||
|
||||
```ts
|
||||
type SolarEdgeOptimizerMapping = {
|
||||
serial: string;
|
||||
inverterId?: string; // e.g. "1"
|
||||
stringId?: string; // e.g. "1.1"
|
||||
optimizerId?: string; // e.g. "1.1.16"
|
||||
inverterOrder?: number;
|
||||
stringOrder?: number;
|
||||
optimizerOrder?: number;
|
||||
};
|
||||
```
|
||||
|
||||
The IDs come from the portal's `displayOrder` properties and are therefore
|
||||
preferable to deriving positions from array indexes.
|
||||
|
||||
### Optimizer information
|
||||
|
||||
```http
|
||||
POST /services/layout/information/optimizers
|
||||
Content-Type: application/json
|
||||
|
||||
["OPTIMIZER_SERIAL_1", "OPTIMIZER_SERIAL_2"]
|
||||
```
|
||||
|
||||
Observed response container:
|
||||
|
||||
```ts
|
||||
type SolarEdgeOptimizerInformation = {
|
||||
basicInformationList: Array<{
|
||||
serial: string;
|
||||
type_?: string;
|
||||
model?: string;
|
||||
bundleType?: string;
|
||||
multiOptimizers?: boolean;
|
||||
modules?: Array<{
|
||||
orientation?: string;
|
||||
tilt?: number;
|
||||
azimuth?: number;
|
||||
manufacturer?: string;
|
||||
model?: string;
|
||||
}>;
|
||||
[property: string]: unknown;
|
||||
}>;
|
||||
serialToLiveData: Record<string, {
|
||||
lastMeasurement?: string;
|
||||
current_A?: number | null;
|
||||
optimizerVoltage_V?: number | null;
|
||||
power_W?: number | null;
|
||||
voltage_V?: number | null;
|
||||
total_last_telemetry_energy_WH?: number | null;
|
||||
[property: string]: unknown;
|
||||
}>;
|
||||
};
|
||||
```
|
||||
|
||||
```ts
|
||||
const information = await portal.getOptimizerInformation([
|
||||
"OPTIMIZER_SERIAL_1",
|
||||
"OPTIMIZER_SERIAL_2",
|
||||
]);
|
||||
```
|
||||
|
||||
### Optimizer energy graph
|
||||
|
||||
```http
|
||||
GET /services/layout/energy-graph/site/{siteId}/optimizers
|
||||
?chart-time-unit=hours
|
||||
&start-date=yyyy-MM-dd
|
||||
&end-date=yyyy-MM-dd
|
||||
&optimizer-serials=SERIAL_1,SERIAL_2
|
||||
```
|
||||
|
||||
Observed response:
|
||||
|
||||
```ts
|
||||
type SolarEdgeOptimizerEnergy = {
|
||||
totalEnergy: number;
|
||||
energyBars: Array<{
|
||||
measurementTime: string;
|
||||
energy: number | null;
|
||||
}>;
|
||||
};
|
||||
```
|
||||
|
||||
```ts
|
||||
const energy = await portal.getOptimizerEnergy({
|
||||
startDate: "2026-08-09",
|
||||
endDate: "2026-08-09",
|
||||
optimizerSerials: ["OPTIMIZER_SERIAL_1"],
|
||||
chartTimeUnit: "hours",
|
||||
});
|
||||
```
|
||||
|
||||
## Limitations and operational safety
|
||||
|
||||
- The implementation currently supports username/password login without an
|
||||
additional MFA challenge. It throws `AUTH_CHALLENGE_REQUIRED` if SolarEdge
|
||||
asks for an OTP, authenticator, passkey, or another step.
|
||||
- Credentials remain in process memory because they are needed for a fresh
|
||||
login after session expiry. Do not log client options or error request bodies.
|
||||
- Use conservative polling and caching. These endpoints have no published rate
|
||||
limits or stability guarantees.
|
||||
- Use this only for an account and site you are authorized to access. Review the
|
||||
SolarEdge Monitoring Portal terms before production use.
|
||||
@@ -0,0 +1,498 @@
|
||||
# SolarEdge Monitoring API reference
|
||||
|
||||
Local working reference for the SolarEdge Monitoring API. This file summarizes
|
||||
the official March 2026 documentation in a compact, implementation-oriented
|
||||
form. The [official PDF](https://knowledge-center.solaredge.com/sites/kc/files/se_monitoring_api.pdf)
|
||||
remains the authoritative source.
|
||||
|
||||
## Base URL and authentication
|
||||
|
||||
```text
|
||||
https://monitoringapi.solaredge.com
|
||||
```
|
||||
|
||||
All requests use `GET` over HTTPS and pass the API key as the `api_key` query
|
||||
parameter:
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/overview?api_key={apiKey}
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
Only JSON is supported. CSV and XML support were removed in March 2026.
|
||||
|
||||
The local server-side configuration is:
|
||||
|
||||
```dotenv
|
||||
SOLAREDGE_API_KEY=...
|
||||
SOLAREDGE_SITE_ID=...
|
||||
```
|
||||
|
||||
Never expose the API key in browser code, an `EXPO_PUBLIC_` variable, logs, or a
|
||||
repository. SolarEdge recommends using a site-level key where possible and
|
||||
rotating keys periodically.
|
||||
|
||||
## Dates, time zones, encoding, and units
|
||||
|
||||
- Date: `YYYY-MM-DD`
|
||||
- Date and time: `YYYY-MM-DD hh:mm:ss`
|
||||
- All dates and times use the site's local time zone.
|
||||
- URL query values, including spaces in date-times, must be URL encoded.
|
||||
- Text is UTF-8.
|
||||
- Physical measurements use metric units; temperatures are Celsius.
|
||||
- Common time units are `QUARTER_OF_AN_HOUR`, `HOUR`, `DAY`, `WEEK`, `MONTH`,
|
||||
and `YEAR`. Each endpoint defines which values it accepts.
|
||||
- A time-series value can be `null` or entirely absent when no measurement is
|
||||
available.
|
||||
|
||||
## Limits and errors
|
||||
|
||||
SolarEdge uses standard HTTP status codes.
|
||||
|
||||
| Status | Meaning |
|
||||
| --- | --- |
|
||||
| `403` | Invalid parameter range, endpoint-specific limit exceeded, or access to a requested site is forbidden. |
|
||||
| `404` | Resource does not exist. |
|
||||
| `429` | Daily request quota or concurrency limit exceeded. |
|
||||
|
||||
Global limits from the March 2026 documentation:
|
||||
|
||||
- 300 requests per account token.
|
||||
- 300 requests per specific site ID and source IP.
|
||||
- At most 3 concurrent API calls from the same source IP.
|
||||
- Bulk endpoints accept at most 100 comma-separated site IDs.
|
||||
- A bulk call consumes one quota unit for every site included in the call.
|
||||
|
||||
The package client automatically limits itself to three concurrent requests.
|
||||
It does not track daily quotas or split date ranges automatically.
|
||||
|
||||
## Endpoint index
|
||||
|
||||
`{siteIds}` means a comma-separated list of at most 100 site IDs.
|
||||
|
||||
| Area | Endpoint | Typed client method |
|
||||
| --- | --- | --- |
|
||||
| Sites | `GET /sites/list` | `listSites()` |
|
||||
| Sites | `GET /site/{siteId}/details` | `getSiteDetails()` |
|
||||
| Sites | `GET /site/{siteId}/dataPeriod` | `getSiteDataPeriod()` |
|
||||
| Sites | `GET /sites/{siteIds}/dataPeriod` | Use `get<T>()` |
|
||||
| Energy | `GET /site/{siteId}/energy` | `getSiteEnergy()` |
|
||||
| Energy | `GET /sites/{siteIds}/energy` | Use `get<T>()` |
|
||||
| Energy | `GET /site/{siteId}/timeFrameEnergy` | Use `get<T>()` |
|
||||
| Energy | `GET /sites/{siteIds}/timeFrameEnergy` | Use `get<T>()` |
|
||||
| Power | `GET /site/{siteId}/power` | `getSitePower()` |
|
||||
| Power | `GET /sites/{siteIds}/power` | Use `get<T>()` |
|
||||
| Overview | `GET /site/{siteId}/overview` | `getSiteOverview()` |
|
||||
| Overview | `GET /sites/{siteIds}/overview` | Use `get<T>()` |
|
||||
| Meters | `GET /site/{siteId}/powerDetails` | `getSitePowerDetails()` |
|
||||
| Meters | `GET /site/{siteId}/energyDetails` | `getSiteEnergyDetails()` |
|
||||
| Flow | `GET /site/{siteId}/currentPowerFlow` | `getCurrentPowerFlow()` |
|
||||
| Storage | `GET /site/{siteId}/storageData` | Use `get<T>()` |
|
||||
| Environment | `GET /site/{siteId}/envBenefits` | Use `get<T>()` |
|
||||
| Equipment | `GET /equipment/{siteId}/list` | `listSiteEquipment()` |
|
||||
| Equipment | `GET /site/{siteId}/inventory` | `getSiteInventory()` |
|
||||
| Equipment | `GET /equipment/{siteId}/{serialNumber}/data` | Use `get<T>()` |
|
||||
| Meters | `GET /site/{siteId}/meters` | Use `get<T>()` |
|
||||
|
||||
## Site endpoints
|
||||
|
||||
### List sites
|
||||
|
||||
```text
|
||||
GET /sites/list
|
||||
```
|
||||
|
||||
Returns sites available to an account-level key. A site-level key may not be
|
||||
able to use this endpoint meaningfully.
|
||||
|
||||
| Parameter | Required | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `size` | No | `100` | Page size, maximum 100. |
|
||||
| `startIndex` | No | `0` | Zero-based first result. |
|
||||
| `searchText` | No | - | Searches name, notes, address, city, zip, and country. Full-address search is no longer supported. |
|
||||
| `sortProperty` | No | - | `name`, `country`, `state`, `city`, `address`, `zip`, `status`, `peakPower`, `installationDate`, `amount`, or `maxSeverity`. |
|
||||
| `sortOrder` | No | `ASC` | `ASC` or `DESC`. |
|
||||
| `Status` | No | `Active,Pending` | `Active`, `Pending`, `Disabled`, or `All`. The parameter name begins with uppercase `S`. |
|
||||
|
||||
Site objects can contain:
|
||||
|
||||
- `id`, `accountId`, `name`, `status`, `type`, and `notes`
|
||||
- `peakPower`, `currency`, `installationDate`, and `ptoDate`
|
||||
- `location` with country, state, city, address, address2, zip, and time zone
|
||||
- `alertQuantity` and `alertSeverity` for account-level keys
|
||||
- `publicSettings` with public name and visibility
|
||||
- API-specific `uris`
|
||||
|
||||
The PDF examples use `Sites.list`, while the live JSON API currently returns
|
||||
`sites.site`. The package follows the live response and exposes `{ count, site }`.
|
||||
|
||||
### Site details
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/details
|
||||
```
|
||||
|
||||
Returns one site object with the same core metadata as the site list. Response
|
||||
root: `details`.
|
||||
|
||||
### Site data period
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/dataPeriod
|
||||
GET /sites/{siteIds}/dataPeriod
|
||||
```
|
||||
|
||||
Returns the first and last available production timestamps. For a site that is
|
||||
not transmitting, `startDate` and `endDate` can be `null`.
|
||||
|
||||
Single-site response root:
|
||||
|
||||
```json
|
||||
{
|
||||
"dataPeriod": {
|
||||
"startDate": "YYYY-MM-DD hh:mm:ss",
|
||||
"endDate": "YYYY-MM-DD hh:mm:ss"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The bulk response adds `count` and a `list` whose entries include `id`.
|
||||
|
||||
## Energy endpoints
|
||||
|
||||
### Energy time series
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/energy
|
||||
GET /sites/{siteIds}/energy
|
||||
```
|
||||
|
||||
| Parameter | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `startDate` | Yes | Start date in `YYYY-MM-DD`. |
|
||||
| `endDate` | Yes | End date in `YYYY-MM-DD`. |
|
||||
| `timeUnit` | No | Defaults to `DAY`; accepts `QUARTER_OF_AN_HOUR`, `HOUR`, `DAY`, `WEEK`, `MONTH`, or `YEAR`. |
|
||||
|
||||
Limits:
|
||||
|
||||
- `DAY`: at most one year.
|
||||
- `QUARTER_OF_AN_HOUR` or `HOUR`: at most one month.
|
||||
- The PDF does not state an additional range limit for week, month, or year.
|
||||
|
||||
Response root `energy` contains `timeUnit`, `unit`, and `values`. Each value has
|
||||
`date` and a numeric or `null` `value`. The regular energy endpoint matches the
|
||||
Site Dashboard calculation.
|
||||
|
||||
The bulk response adds `count` and a `list` of `{ id, values }`.
|
||||
|
||||
### Total energy for a date range
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/timeFrameEnergy
|
||||
GET /sites/{siteIds}/timeFrameEnergy
|
||||
```
|
||||
|
||||
| Parameter | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `startDate` | Yes | Start date in `YYYY-MM-DD`. |
|
||||
| `endDate` | Yes | End date in `YYYY-MM-DD`. |
|
||||
|
||||
Maximum range: one year.
|
||||
|
||||
Response root `timeFrameEnergy` contains `energy` and `unit`. The bulk response
|
||||
contains `unit`, `count`, and `{ id, energy }` entries.
|
||||
|
||||
This endpoint reports on-grid energy. On storage or backup sites it may differ
|
||||
from the Site Dashboard; use `/energy` when dashboard-equivalent values are
|
||||
required.
|
||||
|
||||
### Detailed energy by meter
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/energyDetails
|
||||
```
|
||||
|
||||
| Parameter | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `startTime` | Yes | Start in site-local `YYYY-MM-DD hh:mm:ss`. |
|
||||
| `endTime` | Yes | End in site-local `YYYY-MM-DD hh:mm:ss`. |
|
||||
| `timeUnit` | No | Defaults to `DAY`; accepts all six common time units. |
|
||||
| `meters` | No | Comma-separated `PRODUCTION`, `CONSUMPTION`, `SELFCONSUMPTION`, `FEEDIN`, and/or `PURCHASED`. |
|
||||
|
||||
Limits:
|
||||
|
||||
- `QUARTER_OF_AN_HOUR` or `HOUR`: at most one month.
|
||||
- `DAY`: at most one year.
|
||||
- `WEEK`, `MONTH`, or `YEAR`: no documented period limit.
|
||||
|
||||
Response root `energyDetails` contains `timeUnit`, `unit`, and `meters`. Each
|
||||
meter has `type` and `values`; a missing measurement may omit `value` entirely.
|
||||
|
||||
## Power endpoints
|
||||
|
||||
### Site power
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/power
|
||||
GET /sites/{siteIds}/power
|
||||
```
|
||||
|
||||
| Parameter | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `startTime` | Yes | Start in site-local `YYYY-MM-DD hh:mm:ss`. |
|
||||
| `endTime` | Yes | End in site-local `YYYY-MM-DD hh:mm:ss`. |
|
||||
|
||||
Maximum range: one month. Resolution is 15 minutes. Response root `power`
|
||||
contains `timeUnit`, `unit`, and `values`. Missing values can be `null`.
|
||||
|
||||
The bulk response adds `count` and a list of `{ id, values }`.
|
||||
|
||||
### Detailed power by meter
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/powerDetails
|
||||
```
|
||||
|
||||
| Parameter | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `startTime` | Yes | Start in site-local `YYYY-MM-DD hh:mm:ss`. |
|
||||
| `endTime` | Yes | End in site-local `YYYY-MM-DD hh:mm:ss`. |
|
||||
| `meters` | No | Comma-separated `PRODUCTION`, `CONSUMPTION`, `SELFCONSUMPTION`, `FEEDIN`, and/or `PURCHASED`. |
|
||||
|
||||
Maximum range: one month. Response root `powerDetails` contains a fixed
|
||||
`QUARTER_OF_AN_HOUR` time unit, the measurement unit, and per-meter series.
|
||||
A missing measurement may omit `value` entirely.
|
||||
|
||||
## Overview and live power flow
|
||||
|
||||
### Site overview
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/overview
|
||||
GET /sites/{siteIds}/overview
|
||||
```
|
||||
|
||||
Response root `overview` contains:
|
||||
|
||||
- `lastUpdateTime`
|
||||
- `currentPower.power`
|
||||
- `lastDayData.energy`
|
||||
- `lastMonthData.energy`
|
||||
- `lastYearData.energy`
|
||||
- `lifeTimeData.energy` and lifetime revenue
|
||||
- Revenue fields can also appear in the period summaries.
|
||||
|
||||
The bulk response contains `count` and a list with `id` on every overview.
|
||||
|
||||
### Current power flow
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/currentPowerFlow
|
||||
```
|
||||
|
||||
If unsupported, the API may return an empty power-flow object. Otherwise,
|
||||
`siteCurrentPowerFlow` contains:
|
||||
|
||||
- `unit`
|
||||
- `connections` entries with `from` and `to`
|
||||
- `GRID` and `LOAD`
|
||||
- Optional `PV`
|
||||
- Optional `STORAGE`
|
||||
|
||||
Every component provides `status` (`Active`, `Idle`, or `Disabled`) and a
|
||||
positive `currentPower`. Direction comes from `connections`, not the sign.
|
||||
Storage can additionally provide `chargeLevel`, `critical`, and `timeLeft`.
|
||||
|
||||
## Storage data
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/storageData
|
||||
```
|
||||
|
||||
| Parameter | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `startTime` | Yes | Start in site-local `YYYY-MM-DD hh:mm:ss`. |
|
||||
| `endTime` | Yes | End in site-local `YYYY-MM-DD hh:mm:ss`. |
|
||||
| `serials` | No | Comma-separated battery serial numbers. Defaults to every battery at the site. |
|
||||
|
||||
Maximum range: seven days.
|
||||
|
||||
Response root `storageData` contains `batteryCount` and `batteries`. A battery
|
||||
contains `serialNumber`, `nameplate`, `modelNumber`, `telemetryCount`, and
|
||||
`telemetries`. Telemetry can include:
|
||||
|
||||
- `timeStamp`
|
||||
- `power` (positive means charging, negative means discharging)
|
||||
- `batteryState`: `0` invalid, `1` standby, `2` thermal management, `3` enabled,
|
||||
`4` fault
|
||||
- Lifetime energy charged and discharged
|
||||
- Full-pack energy available
|
||||
- Internal temperature
|
||||
- AC grid charging energy
|
||||
- State of charge from 0 to 100 percent
|
||||
|
||||
The documentation warns that some lifetime battery energy values are aggregated
|
||||
and can be incomplete when telemetry is missing. They are not revenue-grade.
|
||||
|
||||
## Environmental benefits
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/envBenefits
|
||||
```
|
||||
|
||||
| Parameter | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `systemUnits` | No | Case-sensitive `Metrics` or `Imperial`. |
|
||||
|
||||
Response root `envBenefits` contains `gasEmissionSaved` (`units`, `co2`, `so2`,
|
||||
and `nox`), `treesPlanted`, and `lightBulbs`.
|
||||
|
||||
## Equipment endpoints
|
||||
|
||||
### Components list
|
||||
|
||||
```text
|
||||
GET /equipment/{siteId}/list
|
||||
```
|
||||
|
||||
Returns inverters and SMIs with `name`, `manufacturer`, `model`, and
|
||||
`serialNumber`.
|
||||
|
||||
The PDF example shows a top-level `list`; the live API currently wraps the
|
||||
result in `reporters` with `count` and `list`. The package follows the live
|
||||
response.
|
||||
|
||||
### Inventory
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/inventory
|
||||
```
|
||||
|
||||
Response root `Inventory` can contain arrays for:
|
||||
|
||||
- `inverters`
|
||||
- `thirdPartyInverters`
|
||||
- `smiList`
|
||||
- `meters`
|
||||
- `sensors`
|
||||
- `gateways`
|
||||
- `batteries`
|
||||
|
||||
Fields vary by device type. Common fields include names, manufacturer, model,
|
||||
serial number (`SN` or `serialNumber`), firmware versions, communication method,
|
||||
connected device serials, connected optimizer count, and battery nameplate
|
||||
capacity.
|
||||
|
||||
### Inverter technical data
|
||||
|
||||
```text
|
||||
GET /equipment/{siteId}/{serialNumber}/data
|
||||
```
|
||||
|
||||
| Parameter | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `startTime` | Yes | Start in site-local `YYYY-MM-DD hh:mm:ss`. |
|
||||
| `endTime` | Yes | End in site-local `YYYY-MM-DD hh:mm:ss`. |
|
||||
|
||||
Maximum range: seven days.
|
||||
|
||||
Response root `data` contains `count` and inverter telemetry. Unsupported fields
|
||||
are omitted. Depending on inverter type and firmware, telemetry can contain:
|
||||
|
||||
- Timestamp, inverter mode, and operation mode
|
||||
- Total active power, DC voltage, power limit, total energy, temperature, and
|
||||
ground-fault resistance
|
||||
- Per-phase current, voltage, frequency, apparent power, active power, reactive
|
||||
power, and power factor
|
||||
- Phase-to-neutral and phase-to-phase voltages where applicable
|
||||
|
||||
Inverter modes include normal states such as off, sleeping, starting, MPPT,
|
||||
throttled, shutdown, fault, and standby, plus several locked states. Operation
|
||||
mode `0` is on-grid, `1` is off-grid using PV or battery, and `2` is off-grid
|
||||
with a generator present.
|
||||
|
||||
## Meter lifetime data
|
||||
|
||||
```text
|
||||
GET /site/{siteId}/meters
|
||||
```
|
||||
|
||||
| Parameter | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `startTime` | Yes | Start in site-local `YYYY-MM-DD hh:mm:ss`. |
|
||||
| `endTime` | Yes | End in site-local `YYYY-MM-DD hh:mm:ss`. |
|
||||
| `timeUnit` | No | Defaults to `DAY`; accepts all six common time units. |
|
||||
| `meters` | No | Comma-separated `Production`, `Consumption`, `FeedIn`, and/or `Purchased`. |
|
||||
|
||||
Response root `meterEnergyDetails` contains `timeUnit`, `unit`, and `meters`.
|
||||
Each meter includes `meterSerialNumber`, `connectedSolaredgeDeviceSN`, `model`,
|
||||
`meterType`, and lifetime-energy `values` by timestamp.
|
||||
|
||||
## Bulk endpoint behavior
|
||||
|
||||
Bulk endpoints use comma-separated IDs directly in the path:
|
||||
|
||||
```text
|
||||
GET /sites/1,4,8/overview
|
||||
```
|
||||
|
||||
- Maximum 100 site IDs.
|
||||
- Responses normally contain `count` and `list` inside the endpoint root.
|
||||
- Each list item includes the site `id`.
|
||||
- If the key lacks permission for any requested site, the entire request can
|
||||
fail with `403`.
|
||||
- Dates are interpreted in each site's own time zone.
|
||||
|
||||
## March 2026 removals and changes
|
||||
|
||||
Do not build new integrations against these removed endpoints or capabilities:
|
||||
|
||||
- Site Image
|
||||
- Installer Logo Image
|
||||
- Equipment Change Log
|
||||
- Account List
|
||||
- Sensor List and Sensor Data
|
||||
- API Versions: Current and Supported
|
||||
- CSV and XML response formats
|
||||
- `CreationTime` site-list sorting
|
||||
- Full-address matching in `searchText`
|
||||
|
||||
## Package usage
|
||||
|
||||
```ts
|
||||
import { createSolarEdgeClientFromEnv } from "@solar-dash/solaredgeapi";
|
||||
|
||||
const client = createSolarEdgeClientFromEnv();
|
||||
|
||||
const [overview, powerFlow] = await Promise.all([
|
||||
client.getSiteOverview(),
|
||||
client.getCurrentPowerFlow(),
|
||||
]);
|
||||
```
|
||||
|
||||
For an endpoint without a typed method, use the authenticated generic reader:
|
||||
|
||||
```ts
|
||||
type EnvironmentalBenefitsResponse = {
|
||||
envBenefits: {
|
||||
gasEmissionSaved: {
|
||||
units: string;
|
||||
co2: number;
|
||||
so2: number;
|
||||
nox: number;
|
||||
};
|
||||
treesPlanted: number;
|
||||
lightBulbs: number;
|
||||
};
|
||||
};
|
||||
|
||||
const siteId = process.env.SOLAREDGE_SITE_ID;
|
||||
if (!siteId) {
|
||||
throw new Error("Missing SOLAREDGE_SITE_ID");
|
||||
}
|
||||
|
||||
const response = await client.get<EnvironmentalBenefitsResponse>(
|
||||
`/site/${siteId}/envBenefits`,
|
||||
{ systemUnits: "Metrics" },
|
||||
);
|
||||
```
|
||||
Reference in New Issue
Block a user