ForecastSolarConnection

This module provides a read-only REST API connector to the forecast.solar API.

You can obtain an estimate of solar production for a specific location, defined by latitude and longitude, and a specific plane orientation, defined by declination and azimuth, based on the installed module power.

Supported endpoints include: “Estimate”, “Historic”, and “Clearsky”:

Estimate Solar Production The estimate endpoint provides the forecast for today and the upcoming days, depending on the account model.

Historic Solar Production The historic endpoint calculates the average solar production for a given day based on historical weather data, excluding current weather conditions.

Clear Sky Solar Production The clearsky endpoint calculates the theoretically possible solar production assuming no cloud cover.

For more information, visit the forecast.solar API documentation.


ForecastSolarConnection

class eta_utility.connectors.ForecastSolarConnection(url: str = 'https://api.forecast.solar', *, api_key: str = 'None', url_params: dict[str, Any] | None = None, query_params: dict[str, Any] | None = None, nodes: Nodes | None = None)[source]

ForecastSolarConnection is a class to download and upload multiple features from and to the Forecast.Solar database as timeseries.

Parameters:
  • url – URL of the server with scheme (https://).

  • usr – Not needed for Forecast.Solar.

  • pwd – Not needed for Forecast.Solar.

  • api_key – Token for API authentication.

  • nodes – Nodes to select in connection.

url_params: dict[str, Any] | None

Url parameters for the forecast.Solar api

query_params: dict[str, Any] | None

Query parameters for the forecast.Solar api

read(nodes: Nodes | None = None) pd.DataFrame[source]

Return forecast data from the Forecast.Solar Database.

Parameters:

nodes – List of nodes to read values from.

Returns:

pandas.DataFrame containing the data read from the connection.

write(values: Mapping[AnyNode, Any]) None[source]

Warning

Cannot read single values from the Forecast.Solar API. Use read_series instead

Raises:

NotImplementedError

subscribe(handler: SubscriptionHandler, nodes: Nodes | None = None, interval: TimeStep = 1) None[source]

Warning

Cannot read single values from the Forecast.Solar API. Use read_series instead

Raises:

NotImplementedError

read_series(from_time: datetime, to_time: datetime, nodes: Nodes | None = None, interval: TimeStep = 1, **kwargs: Any) pd.DataFrame[source]

Return a time series of forecast data from the Forecast.Solar Database.

Parameters:
  • nodes – List of nodes to read values from.

  • from_time – Starting time to begin reading (included in output).

  • to_time – Time to stop reading at (not included in output).

  • interval – Interval between time steps. It is interpreted as seconds if given as integer.

  • kwargs – Other parameters (ignored by this connector).

Returns:

Pandas DataFrame containing the data read from the connection.

subscribe_series(handler: SubscriptionHandler, req_interval: TimeStep, offset: TimeStep | None = None, nodes: Nodes | None = None, interval: TimeStep = 1, data_interval: TimeStep = 1, **kwargs: Any) None[source]

Warning

Cannot read single values from the Forecast.Solar API. Use read_series instead

Raises:

NotImplementedError

close_sub() None[source]

Warning

Cannot read single values from the Forecast.Solar API. Use read_series instead

Raises:

NotImplementedError

timestr_from_datetime(dt: datetime) str[source]

Create an Forecast.Solar compatible time string.

Parameters:

dt – Datetime object to convert to string.

Returns:

Forecast.Solar compatible time string.

classmethod route_valid(nodes: Nodes) bool[source]

Check if node routes make up a valid route, by using the Forecast.Solar API’s check endpoint.

Parameters:

nodes – List of nodes to check.

Returns:

Boolean if the nodes are on the same route.

classmethod calculate_watt_hours_period(df: pandas.DataFrame, watts_column: str) pandas.DataFrame[source]

Calculates watt hours for each period based on the average watts provided. Assumes the DataFrame is indexed by timestamps.

classmethod summarize_watt_hours_over_day(df: pandas.DataFrame) pandas.DataFrame[source]

Sums up watt hours over each day.

classmethod get_dataframe_of_values(df: pandas.DataFrame, watts_column: str = 'watts') tuple[pandas.DataFrame, pandas.DataFrame][source]

Process the original DataFrame to return a DataFrame with watt_hours_period, watt_hours (summarized over the day), and watt_hours_day.

usr: str | None

Username for login to server

pwd: str | None

Password for login to server

exc: BaseException | None

NodeForecastSolar

class eta_utility.connectors.node.NodeForecastSolar(name: str, url: str, protocol: str, *args: Any, **kwargs: Any)[source]

Node for using the Forecast.Solar API.

Mandatory parameters are:

  • The location of the forecast solar plane(s): latitude, longitude,

  • Plane parameters: declination, azimuth and kwp.

Additionally api_key must be set for endpoints other than ‘estimate’, multiple planes or if requests capacity is exceeded.

For multiple planes, the parameters shall be passed as lists of the same length (e.g. [0, 30], [180, 180], [5, 5]).

api_key: str | None

API key for the Forecast.Solar API; string

endpoint: str

Endpoint in (estimate, history, clearsky), defaults to estimate; string

data: str | None

What data to query, i.e. only watts, watt hours, watt hours per period or watt hours per day; string

latitude: int

Latitude of plane location, -90 (south) … 90 (north); handled with a precision of 0.0001 or abt. 10 m

longitude: int

Longitude of plane location, -180 (west) … 180 (east); handled with a precision of 0.0001 or abt. 10 m

declination: int | list[int]

Plane declination, 0 (horizontal) … 90 (vertical) - always in relation to earth’s surface; integer

azimuth: int | list[int]

Plane azimuth, -180 … 180 (-180 = north, -90 = east, 0 = south, 90 = west, 180 = north); integer

kwp: float | list[float]

Installed modules power of plane in kilo watt; float

no_sun: int | None

Format of timestamps in the response, see API doc for values; string Forecast for full day or only sunrise to sunset, 0|1 (API defaults to 0); int

damping_morning: float | None

Damping factor for the morning (API defaults to 0.0)

damping_evening: float | None

Damping factor for the evening (API defaults to 0.0)

horizon: int | list[int] | None

Horizon information; string, (comma-separated list of numerics) See API doc

inverter: float | None

Maximum of inverter in kilowatts or kVA; float > 0

actual: float | None

Actual production until now; float >= 0

name: str

Name for the node.

url: str

URL of the connection.

url_parsed: ParseResult

Parse result object of the URL (in case more post-processing is required).

protocol: str

Protocol of the connection.

usr: str | None

Username for login to the connection (default: None).

pwd: str | None

Password for login to the connection (default: None).

interval: str | None

Interval

dtype: Callable | None

Data type of the node (for value conversion). Note that strings will be interpreted as utf-8 encoded. If you do not want this behaviour, use ‘bytes’.


Example Usage

Simple node without API key:

from eta_utility.connectors import ForecastSolarConnection
from eta_utility.connectors.node import NodeForecastSolar

# ------------------------------
# Simple node without API key:
# ------------------------------
node_simple = NodeForecastSolar(
    name="ForecastSolar Node",
    url="https://api.forecast.solar",
    protocol="forecast_solar",
    latitude=49.86381,
    longitude=8.68105,
    declination=14,
    azimuth=90,
    kwp=23.31,
)

# Create an instance of the ForecastSolarConnection class
conn_simple = ForecastSolarConnection()

# Use the read method of the ForecastSolarConnection instance to get an estimation
# The read method takes a node as an argument, here represented by node_simple
estimation = conn_simple.read(node_simple)

Node with api key and multiple planes:


# ------------------------------
# Node with api key and multiple planes:
# ------------------------------
node_eta = NodeForecastSolar(
    name="ForecastSolar Node",
    url="https://api.forecast.solar",
    protocol="forecast_solar",
    api_key="A1B2C3D4E5F6G7H8",  # Your API key
    latitude=49.86381,
    longitude=8.68105,
    declination=[14, 10, 10],
    azimuth=[90, -90, 90],
    kwp=[23.31, 23.31, 23.31],
)

# Create a connection instance from the node_eta using the from_node method
conn_eta = ForecastSolarConnection.from_node(node_eta)

if isinstance(conn_eta, ForecastSolarConnection):
    # Get a series of estimations for a specified time interval
    estimation = conn_eta.read_series(
        from_time=datetime(2024, 5, 7), to_time=datetime(2024, 5, 8), interval=timedelta(minutes=15)
    )
else:
    raise TypeError("The connection must be a ForecastSolarConnection, to be able to call read_series.")