Skip to content
Back to Blog
1 min read

Carbon-Aware Computing: Building Climate-Conscious Applications

I wrote “Carbon-Aware Computing: Building Climate-Conscious Applications” to share practical, production-minded guidance on this topic.

Understanding Grid Carbon Intensity

Electricity grids mix various energy sources. Carbon intensity varies by:

  • Time of day (solar peaks midday)
  • Weather (wind varies)
  • Demand (peak hours often use dirtier peaker plants)
  • Season (heating/cooling loads)
from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import List, Optional
import httpx

@dataclass
class CarbonIntensityData:
    timestamp: datetime
    intensity_g_co2_kwh: float
    is_low_carbon: bool
    energy_mix: dict

class CarbonIntensityProvider:
    """Interface with carbon intensity data providers"""

    def __init__(self, provider: str = "electricitymap"):
        self.provider = provider
        self.base_urls = {
            "electricitymap": "https://api.electricitymap.org/v3",
            "watttime": "https://api2.watttime.org/v2"
        }

    async def get_current_intensity(self, region: str) -> CarbonIntensityData:
        """Get current carbon intensity for a region"""
        async with httpx.AsyncClient() as client:
            if self.provider == "electricitymap":
                response = await client.get(
                    f"{self.base_urls['electricitymap']}/carbon-intensity/latest",
                    params={"zone": region},
                    headers={"auth-token": self.api_key}
                )
                data = response.json()
                return CarbonIntensityData(
                    timestamp=datetime.fromisoformat(data["datetime"]),
                    intensity_g_co2_kwh=data["carbonIntensity"],
                    is_low_carbon=data["carbonIntensity"] < 200,
                    energy_mix=data.get("powerBreakdown", {})
                )

    async def get_forecast(
        self,
        region: str,
        hours: int = 24
    ) -> List[CarbonIntensityData]:
        """Get carbon intensity forecast"""
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{self.base_urls['electricitymap']}/carbon-intensity/forecast",
                params={"zone": region},
                headers={"auth-token": self.api_key}
            )
            data = response.json()

            forecasts = []
            for point in data["forecast"][:hours]:
                forecasts.append(CarbonIntensityData(
                    timestamp=datetime.fromisoformat(point["datetime"]),
                    intensity_g_co2_kwh=point["carbonIntensity"],
                    is_low_carbon=point["carbonIntensity"] < 200,
                    energy_mix={}
                ))

            return forecasts

    def find_optimal_window(
        self,
        forecasts: List[CarbonIntensityData],
        duration_hours: int,
        deadline: Optional[datetime] = None
    ) -> Optional[datetime]:
        """Find the optimal time window for lowest carbon intensity"""

        if deadline:
            forecasts = [f for f in forecasts if f.timestamp <= deadline]

        if len(forecasts) < duration_hours:
            return None

        # Sliding window to find lowest average intensity
        best_start = None
        best_avg_intensity = float('inf')

        for i in range(len(forecasts) - duration_hours + 1):
            window = forecasts[i:i + duration_hours]
            avg_intensity = sum(f.intensity_g_co2_kwh for f in window) / len(window)

            if avg_intensity < best_avg_intensity:
                best_avg_intensity = avg_intensity
                best_start = window[0].timestamp

        return best_start

Carbon-Aware Kubernetes Scheduler

# Carbon-aware pod scheduling
apiVersion: v1
kind: ConfigMap
metadata:
  name: carbon-aware-config
  namespace: kube-system
data:
  config.yaml: |
    carbonIntensityProvider: electricitymap
    regions:
      - name: australiaeast
        zone: AU-NSW
        priority: 3
      - name: northeurope
        zone: IE
        priority: 1
      - name: swedencentral
        zone: SE
        priority: 1
    thresholds:
      lowCarbon: 100
      mediumCarbon: 300
      highCarbon: 500
    scheduling:
      enableDeferral: true
      maxDeferralHours: 6
      preferLowCarbonRegions: true\n\n## Takeaways\n\n*Add a concise, personal takeaway and recommended next steps here.*\n
Michael John Pena

Michael John Pena

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.