# OpenMeteo
TESTING ETM CONSUMER
Get current weather data for your location.
The OpenMeteo plugin gives the box the **weather and solar forecasts** for your site:
today's and tomorrow's weather, and the expected PV production for each roof
orientation. The data come from the public [Open-Meteo](https://open-meteo.com)
service, queried directly by the box — **no account, no API key**, and no detour
through an ETM service.
Package: `powersync-plugin-openmeteo`.
## 1. What the plugin publishes
The plugin creates two kinds of objects:
- a **site** (`Open-Meteo site`): weather at the location (temperature, clouds, wind,
humidity…), forecast solar irradiance, sunrise and sunset, and a satellite
observation of the past hour;
- one or more **PV planes** (`Open-Meteo PV plane`), attached to the site — one per
roof orientation. Each plane publishes the forecast irradiance on its modules and
the expected production derived from it: for the current hour, the next 3, 6 and 12
hours, the rest of the day and tomorrow.
The ETM-PowerSync app shows these forecasts next to the measurements (expected
production on the charts, hour-by-hour weather).
## 2. Adding the site
In installer mode, add an **Open-Meteo site** device (see
[Adding a device](../../installation/application.md)) and enter:
| Field | Content |
| --- | --- |
| `Latitude`, `Longitude` | Position of the site, in decimal degrees |
| `Elevation (m, optional)` | Altitude of the site in metres. Optional: left at `0`, Open-Meteo uses the altitude of its own terrain model. Enter it in mountains or narrow valleys, where the forecast temperature depends on it. |
The site is not discovered automatically: it is created by hand, once per location.
## 3. Adding the PV planes
Once the site exists, add an **Open-Meteo PV plane** device: discovery offers one
plane for each existing site. Create **one plane per orientation** — an east-west roof
gives two planes.
| Field | Content |
| --- | --- |
| `Tilt (deg, 0=horizontal)` | Tilt of the modules in degrees: `0` = flat, `90` = vertical |
| `Azimuth (deg geographic, 180=South)` | Orientation, in **geographic convention**: `180` = south, `90` = east, `270` = west |
| `Peak power kWp` | Peak power of the modules on this plane |
| `Performance ratio (declared, not learned)` | Overall system efficiency, **declared** by the installer (the box does not learn it). Left at `1.0`, the expected production is overestimated. |
Depending on the plugin version, two values from the module datasheet complete the
plane: `Power temperature coefficient (%/K, declared, not learned)` (default
−0.37 %/K) and `NOCT (°C, declared, not learned)` (default 45 °C). They correct the
expected production when the modules heat up.
!!! warning "Mind the azimuth"
Other tools count the azimuth from south (`0` = south). Here, `0` is **north**:
an azimuth of `0` entered for a due-south roof gives a heavily underestimated
production forecast.
## 4. A forecast, never a measurement
Everything this plugin publishes is a **weather forecast** converted into production,
or a **satellite observation** about an hour old. It is never a measurement of your
installation: the actual production is read from the inverter or the meter.
This is why the values are named `forecast…` or `observed…` (satellite observation):
there is no `pvPower` in this plugin, only `forecastPvPower`.
The expected production is a simple calculation: forecast irradiance × peak power ×
declared efficiency. It **does not account for** shading, soiled modules or inverter
clipping. The error therefore always goes the same way: **the forecast is
optimistic**. 4 kW forecast is not 4 kW produced.
The **weather spread** published for today and tomorrow (in %) says how uncertain the
weather itself is. It says nothing about the accuracy of the expected production: on a
clear, stable day it is low, precisely when the overestimate is at its highest.
## 5. Refresh and internet outage
Weather models do not publish more often than this: the forecast and the satellite
observation are fetched **every hour**, the spread **every 3 hours**. The site's
`Refresh` action forces all three.
If Open-Meteo does not answer, the plugin retries after 5 minutes, then 10, 20, 40… —
never less often than the source's normal rate — and returns to its normal rate at the
first answer. After **3 hours** without a forecast, `Forecast valid` turns false.
An internet outage blocks nothing: the box keeps controlling with its measurements,
safety is maintained, and only the forecasts degrade until the connection returns.
## 6. What leaves the box
To get its forecasts, the box sends Open-Meteo **only**:
- the site's coordinates, **rounded to two decimals** (about 1 km): precise enough for
the weather, too blurred to point to an address;
- the site's altitude, if you entered it;
- the tilt and azimuth of each PV plane.
No measurement, no consumption and no usage data is sent. The peak power and the
efficiency stay on the box: the conversion into production happens locally.
## 7. Commercial use: a dedicated Open-Meteo instance
The public Open-Meteo API is for **non-commercial use** only. For a commercial
deployment, the plugin settings can point to a self-hosted Open-Meteo instance
(`Base URL (forecast)`, `Base URL (satellite radiation)`, `Base URL (ensemble
spread)`) or take a key for Open-Meteo's commercial offer (`API key (commercial
endpoint, optional)`). Unchanged, the plugin queries the public API.
## 8. Data sources
Weather data by Météo-France, satellite radiation by EUMETSAT, provided through
[Open-Meteo](https://open-meteo.com) under the CC-BY 4.0 licence.
---
## Reference
!!! info "Application labels"
The keys and labels below are the ones the application shows,
**in English**. They are left verbatim so that you find them
word for word on screen.
**Manufacturer:** Open-Meteo
**Plugin:** `OpenMeteo`
#### Supported models
| Model | Role | Transport | Pairing | Quantities |
| --- | --- | --- | --- | --- |
| **Open-Meteo site** | weather, daylightsensor | — | Manual | 29 |
| **Open-Meteo PV plane** | — | — | Auto-discovery | 15 |
#### Per-model detail
??? abstract "Open-Meteo site — `openMeteoSite`"
_Settings:_
| Key | Label | Type | Range | Default | Read-only |
| --- | --- | --- | --- | --- | --- |
| `name` | Name | QString | — | — | no |
| `latitude` | Latitude | double | — | `48.9` | no |
| `longitude` | Longitude | double | — | `7.85` | no |
| `elevation` | Elevation (m, optional) | double | — | `0` | no |
_Measured quantities:_
| Key | Quantity | Type | Unit |
| --- | --- | --- | --- |
| `weatherDescription` | Weather description | QString | — |
| `weatherCondition` | Weather condition | QString | — |
| `updateTime` | Last update | int | UnixTime |
| `temperature` | Temperature | double | DegreeCelsius |
| `temperatureMin` | Minimum temperature (today) | double | DegreeCelsius |
| `temperatureMax` | Maximum temperature (today) | double | DegreeCelsius |
| `humidity` | Humidity | int | Percentage |
| `pressure` | Pressure | double | HectoPascal |
| `windSpeed` | Wind speed | double | MeterPerSecond |
| `windDirection` | Wind direction | int | Degree |
| `cloudiness` | Cloudiness | int | Percentage |
| `snowfall` | Snowfall (preceding hour) | double | CentiMeter |
| `forecastGhi` | GHI forecast (W/m²) | double | — |
| `forecastDni` | DNI forecast (W/m²) | double | — |
| `forecastDhi` | DHI forecast (W/m²) | double | — |
| `terrestrialRadiation` | TOA radiation (W/m2) | double | — |
| `forecastGhiSumToday` | GHI sum forecast today (kWh/m²) | double | — |
| `observedGhi` | GHI observed, satellite (W/m²) | double | — |
| `observedClearSkyGhi` | Clear-sky GHI observed, satellite (W/m²) | double | — |
| `observedClearSkyIndex` | Clear-sky index kt (observed) | double | — |
| `sunriseTime` | Sunrise time | int | UnixTime |
| `sunsetTime` | Sunset time | int | UnixTime |
| `daylight` | Daylight | bool | — |
| `forecastModel` | Forecast model that answered | QString | — |
| `forecastValid` | Forecast valid | bool | — |
| `forecastTendencyToday` | Sky tendency forecast today | QString | — |
| `observedTime` | Satellite sample time | int | UnixTime |
| `forecastIssuedAt` | Model run initialisation — revision key | int | UnixTime |
| `forecastAvailableAt` | Model run publication — informational, never a revision key | int | UnixTime |
??? abstract "Open-Meteo PV plane — `openMeteoPvPlane`"
_Settings:_
| Key | Label | Type | Range | Default | Read-only |
| --- | --- | --- | --- | --- | --- |
| `name` | Name | QString | — | — | no |
| `tilt` | Tilt (deg, 0=horizontal) | double | 0–90 | `30` | no |
| `azimuth` | Azimuth (deg geographic, 180=South) | double | 0–360 | `180` | no |
| `kwp` | Peak power kWp | double | — | `0` | no |
| `performanceRatio` | Performance ratio (declared, not learned) | double | 0.1–1.0 | `1.0` | no |
_Measured quantities:_
| Key | Quantity | Type | Unit |
| --- | --- | --- | --- |
| `forecastGtiSource` | GTI forecast, source quantity (W/m²) | double | — |
| `updateTime` | Last update | int | UnixTime |
| `forecastPvPower` | PV power forecast | double | Watt |
| `forecastEnergyNext3h` | PV energy forecast, next 3 h (rolling, may cross midnight) | double | KiloWattHour |
| `forecastEnergyNext6h` | PV energy forecast, next 6 h (rolling, may cross midnight) | double | KiloWattHour |
| `forecastEnergyNext12h` | PV energy forecast, next 12 h (rolling, may cross midnight) | double | KiloWattHour |
| `forecastEnergyRestOfDay` | PV energy forecast, now until sunset | double | KiloWattHour |
| `forecastEnergyTomorrow` | PV energy forecast, tomorrow | double | KiloWattHour |
| `forecastPeakTime` | Forecast peak irradiance time today | int | UnixTime |
| `observedGti` | GTI observed, satellite (W/m²) | double | — |
| `observedGtiTime` | Satellite sample time | int | UnixTime |
| `forecastWeatherSpreadTodayPercent` | GTI weather spread today — qualifies weather only, not PV accuracy | double | Percentage |
| `forecastWeatherSpreadTomorrowPercent` | GTI weather spread tomorrow — qualifies weather only, not PV accuracy | double | Percentage |
| `forecastSpreadModel` | Ensemble model used for spread | QString | — |
| `forecastCurveTransport` | Forecast curve — transport channel, not a value | QVariantMap | — |