Skip to content

Python Examples

Complete Python integration examples for the Tessellate Renewables API.

Installation

pip install requests

For async operations:

pip install aiohttp

Basic Client Class

"""
Tessellate Renewables API Client
"""
import requests
from typing import Optional, Dict, Any, List
import time


class TessellateClient:
    """Client for the Tessellate Renewables API."""

    def __init__(self, api_key: Optional[str] = None):
        self.base_url = "https://api.tessellaterenewables.com"
        self.session = requests.Session()
        if api_key:
            self.session.headers["X-API-Key"] = api_key
        self.session.headers["Content-Type"] = "application/json"

    def get_solar_resource(self, latitude: float, longitude: float) -> Dict[str, Any]:
        """Get solar irradiance data for a location."""
        response = self.session.post(
            f"{self.base_url}/solar/resource",
            json={"latitude": latitude, "longitude": longitude}
        )
        response.raise_for_status()
        return response.json()

    def quick_optimize(
        self,
        latitude: float,
        longitude: float,
        capacity_kw: float,
        objective: str = "energy"
    ) -> Dict[str, Any]:
        """Run quick optimization."""
        response = self.session.post(
            f"{self.base_url}/solar/optimization/quick",
            json={
                "site": {
                    "latitude": latitude,
                    "longitude": longitude,
                    "capacity_kw": capacity_kw
                },
                "objective": objective
            }
        )
        response.raise_for_status()
        return response.json()

    def full_optimize(
        self,
        latitude: float,
        longitude: float,
        capacity_kw: float,
        objective: str = "energy",
        max_iterations: int = 50,
        bounds: Optional[Dict] = None,
        poll_interval: float = 2.0
    ) -> Dict[str, Any]:
        """Run full optimization and wait for results."""
        payload = {
            "site": {
                "latitude": latitude,
                "longitude": longitude,
                "capacity_kw": capacity_kw
            },
            "objective": objective,
            "max_iterations": max_iterations
        }
        if bounds:
            payload["bounds"] = bounds

        # Submit job
        response = self.session.post(
            f"{self.base_url}/solar/optimization/run",
            json=payload
        )
        response.raise_for_status()
        job_id = response.json()["job_id"]

        # Poll for results
        while True:
            result = self.session.get(
                f"{self.base_url}/solar/optimization/{job_id}"
            ).json()

            if result["status"] == "completed":
                return result
            elif result["status"] == "failed":
                raise Exception(f"Optimization failed: {result.get('error_message')}")

            time.sleep(poll_interval)

    def multi_objective(
        self,
        latitude: float,
        longitude: float,
        capacity_kw: float,
        objectives: List[str],
        generations: int = 100,
        poll_interval: float = 2.0
    ) -> Dict[str, Any]:
        """Run multi-objective optimization."""
        response = self.session.post(
            f"{self.base_url}/solar/optimization/multi",
            json={
                "site": {
                    "latitude": latitude,
                    "longitude": longitude,
                    "capacity_kw": capacity_kw
                },
                "objectives": objectives,
                "generations": generations
            }
        )
        response.raise_for_status()
        job_id = response.json()["job_id"]

        while True:
            result = self.session.get(
                f"{self.base_url}/solar/optimization/{job_id}"
            ).json()

            if result["status"] == "completed":
                return result
            elif result["status"] == "failed":
                raise Exception(f"Optimization failed: {result.get('error_message')}")

            time.sleep(poll_interval)

    def predict(
        self,
        latitude: float,
        longitude: float,
        capacity_kw: float,
        tilt: float = 30.0,
        azimuth: float = 180.0,
        dc_ac_ratio: float = 1.2,
        gcr: float = 0.4
    ) -> Dict[str, Any]:
        """Predict solar power output."""
        response = self.session.post(
            f"{self.base_url}/solar/predict",
            json={
                "latitude": latitude,
                "longitude": longitude,
                "capacity_kw": capacity_kw,
                "tilt": tilt,
                "azimuth": azimuth,
                "dc_ac_ratio": dc_ac_ratio,
                "gcr": gcr
            }
        )
        response.raise_for_status()
        return response.json()


# Usage
if __name__ == "__main__":
    client = TessellateClient()

    # Quick optimization
    result = client.quick_optimize(
        latitude=35.0,
        longitude=-110.0,
        capacity_kw=1000,
        objective="energy"
    )

    print(f"Optimal tilt: {result['optimal_parameters']['tilt']}°")
    print(f"Annual energy: {result['energy_metrics']['annual_energy_mwh']:,.0f} MWh")

Site Comparison Tool

"""Compare multiple sites for solar development."""
from dataclasses import dataclass
from typing import List
import pandas as pd


@dataclass
class SiteResult:
    name: str
    latitude: float
    longitude: float
    annual_energy_mwh: float
    capacity_factor: float
    lcoe: float
    npv: float
    irr: float


def compare_sites(client: TessellateClient, sites: List[dict], capacity_kw: float) -> pd.DataFrame:
    """Compare multiple sites and return a DataFrame."""
    results = []

    for site in sites:
        result = client.quick_optimize(
            latitude=site["latitude"],
            longitude=site["longitude"],
            capacity_kw=capacity_kw,
            objective="npv"
        )

        results.append(SiteResult(
            name=site["name"],
            latitude=site["latitude"],
            longitude=site["longitude"],
            annual_energy_mwh=result["energy_metrics"]["annual_energy_mwh"],
            capacity_factor=result["energy_metrics"]["capacity_factor"],
            lcoe=result["financial_metrics"]["lcoe_cents_per_kwh"],
            npv=result["financial_metrics"]["npv_dollars"],
            irr=result["financial_metrics"]["irr_percent"]
        ))

    df = pd.DataFrame([vars(r) for r in results])
    df = df.sort_values("npv", ascending=False)
    return df


# Usage
sites = [
    {"name": "Phoenix, AZ", "latitude": 33.45, "longitude": -112.07},
    {"name": "Denver, CO", "latitude": 39.74, "longitude": -104.99},
    {"name": "Austin, TX", "latitude": 30.27, "longitude": -97.74},
    {"name": "Miami, FL", "latitude": 25.76, "longitude": -80.19},
]

client = TessellateClient()
comparison = compare_sites(client, sites, capacity_kw=1000)
print(comparison.to_string(index=False))

Async Client for High Volume

"""Async client for parallel requests."""
import asyncio
import aiohttp
from typing import List, Dict, Any


class AsyncTessellateClient:
    def __init__(self, api_key: str = None):
        self.base_url = "https://api.tessellaterenewables.com"
        self.headers = {"Content-Type": "application/json"}
        if api_key:
            self.headers["X-API-Key"] = api_key

    async def quick_optimize(
        self,
        session: aiohttp.ClientSession,
        latitude: float,
        longitude: float,
        capacity_kw: float,
        objective: str = "energy"
    ) -> Dict[str, Any]:
        async with session.post(
            f"{self.base_url}/solar/optimization/quick",
            json={
                "site": {
                    "latitude": latitude,
                    "longitude": longitude,
                    "capacity_kw": capacity_kw
                },
                "objective": objective
            },
            headers=self.headers
        ) as response:
            return await response.json()

    async def batch_optimize(
        self,
        sites: List[Dict],
        capacity_kw: float,
        objective: str = "energy"
    ) -> List[Dict[str, Any]]:
        async with aiohttp.ClientSession() as session:
            tasks = [
                self.quick_optimize(
                    session,
                    site["latitude"],
                    site["longitude"],
                    capacity_kw,
                    objective
                )
                for site in sites
            ]
            return await asyncio.gather(*tasks)


# Usage
async def main():
    client = AsyncTessellateClient()

    sites = [
        {"latitude": 33.45, "longitude": -112.07},
        {"latitude": 39.74, "longitude": -104.99},
        {"latitude": 30.27, "longitude": -97.74},
    ]

    results = await client.batch_optimize(sites, capacity_kw=1000)

    for site, result in zip(sites, results):
        print(f"Lat {site['latitude']}: {result['energy_metrics']['annual_energy_mwh']:.0f} MWh")


asyncio.run(main())

Integration with Pandas

"""Export results to various formats."""
import pandas as pd


def optimization_to_dataframe(result: dict) -> pd.DataFrame:
    """Convert optimization result to DataFrame."""
    data = {
        "Parameter": ["Tilt", "Azimuth", "DC/AC Ratio", "GCR"],
        "Value": [
            f"{result['optimal_parameters']['tilt']:.1f}°",
            f"{result['optimal_parameters']['azimuth']:.1f}°",
            f"{result['optimal_parameters']['dc_ac_ratio']:.2f}",
            f"{result['optimal_parameters']['gcr']:.2f}"
        ]
    }
    return pd.DataFrame(data)


def pareto_to_dataframe(pareto_front: list) -> pd.DataFrame:
    """Convert Pareto front to DataFrame."""
    rows = []
    for sol in pareto_front:
        row = {
            "tilt": sol["tilt"],
            "azimuth": sol["azimuth"],
            "dc_ac_ratio": sol["dc_ac_ratio"],
            "gcr": sol["gcr"],
            **sol["objectives"]
        }
        rows.append(row)
    return pd.DataFrame(rows)


# Export to Excel
# pareto_df.to_excel("pareto_results.xlsx", index=False)

# Export to CSV
# pareto_df.to_csv("pareto_results.csv", index=False)