274 lines
7.1 KiB
Markdown
274 lines
7.1 KiB
Markdown
# ElprisenLigeNu Python API Client
|
|
|
|
A Python library for accessing Danish electricity spot prices from the [ElprisenLigeNu.dk](https://www.elprisenligenu.dk) API.
|
|
|
|
[](https://python.org)
|
|
[](LICENSE)
|
|
|
|
## Overview
|
|
|
|
ElprisenLigeNu provides real-time and historical Danish electricity spot prices for the two Danish price zones:
|
|
|
|
- **DK1** (West of Great Belt - Jutland and Funen)
|
|
- **DK2** (East of Great Belt - Zealand and Bornholm)
|
|
|
|
This library provides a simple Python interface to fetch hourly electricity prices with automatic timezone handling and type-safe data models.
|
|
|
|
## Features
|
|
|
|
- 🔌 Simple API for fetching electricity prices
|
|
- 🇩🇰 Support for both Danish price zones (DK1/DK2)
|
|
- ⏰ Automatic timezone handling (Europe/Copenhagen)
|
|
- 📊 Type-safe data models using Pydantic
|
|
- 💰 Prices in both DKK and EUR with exchange rates
|
|
- 🕐 Hourly granularity with start/end timestamps
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
pip install elprisenligenu
|
|
```
|
|
|
|
Or using uv:
|
|
|
|
```bash
|
|
uv add elprisenligenu
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
```python
|
|
from datetime import datetime
|
|
from elprisenligenu import API
|
|
|
|
# Initialize the API client
|
|
api = API()
|
|
|
|
# Get today's prices for Copenhagen area (DK2)
|
|
prices = api.get_daily_prices(zone="DK2")
|
|
|
|
# Get prices for Aarhus area (DK1)
|
|
prices = api.get_daily_prices(zone="DK1")
|
|
|
|
# Get prices for a specific date
|
|
from datetime import datetime
|
|
from zoneinfo import ZoneInfo
|
|
|
|
date = datetime(2024, 10, 29, tzinfo=ZoneInfo("Europe/Copenhagen"))
|
|
prices = api.get_daily_prices(zone="DK2", date=date)
|
|
|
|
# Work with the price data
|
|
for hour_data in prices:
|
|
print(f"Time: {hour_data.time_start} - {hour_data.time_end}")
|
|
print(f"Price: {hour_data.DKK_per_kWh:.4f} DKK/kWh")
|
|
print(f"Price: {hour_data.EUR_per_kWh:.4f} EUR/kWh")
|
|
print(f"Exchange rate: {hour_data.EXR:.4f}")
|
|
print("---")
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### API Class
|
|
|
|
```python
|
|
from elprisenligenu import API
|
|
|
|
api = API()
|
|
```
|
|
|
|
#### Methods
|
|
|
|
##### `get_daily_prices(zone="DK1", date=datetime.now())`
|
|
|
|
Fetch hourly electricity prices for a specific day and zone.
|
|
|
|
**Parameters:**
|
|
|
|
- `zone` (str): Price zone, either "DK1" or "DK2". Default: "DK1"
|
|
- `date` (datetime): Date to fetch prices for. Must be timezone-aware. Default: current date
|
|
|
|
**Returns:**
|
|
|
|
- `list[HourData]`: List of hourly price data objects
|
|
|
|
**Raises:**
|
|
|
|
- `ValueError`: If zone is not "DK1" or "DK2", or if date is not timezone-aware
|
|
- `TypeError`: If date is not a datetime object
|
|
- `requests.HTTPError`: If the API request fails
|
|
|
|
### HourData Model
|
|
|
|
The `HourData` class represents electricity price data for a single hour:
|
|
|
|
```python
|
|
from elprisenligenu.dto import HourData
|
|
|
|
class HourData:
|
|
DKK_per_kWh: float # Price in Danish Kroner per kWh
|
|
EUR_per_kWh: float # Price in Euros per kWh
|
|
EXR: float # Exchange rate EUR to DKK
|
|
time_start: datetime # Hour start time
|
|
time_end: datetime # Hour end time
|
|
```
|
|
|
|
## Examples
|
|
|
|
### Find the cheapest and most expensive hours
|
|
|
|
```python
|
|
from elprisenligenu import API
|
|
|
|
api = API()
|
|
prices = api.get_daily_prices(zone="DK2")
|
|
|
|
# Find cheapest hour
|
|
cheapest = min(prices, key=lambda x: x.DKK_per_kWh)
|
|
print(f"Cheapest: {cheapest.DKK_per_kWh:.4f} DKK/kWh at {cheapest.time_start.hour}:00")
|
|
|
|
# Find most expensive hour
|
|
expensive = max(prices, key=lambda x: x.DKK_per_kWh)
|
|
print(f"Most expensive: {expensive.DKK_per_kWh:.4f} DKK/kWh at {expensive.time_start.hour}:00")
|
|
```
|
|
|
|
### Calculate daily average price
|
|
|
|
```python
|
|
from elprisenligenu import API
|
|
|
|
api = API()
|
|
prices = api.get_daily_prices(zone="DK1")
|
|
|
|
average_price = sum(hour.DKK_per_kWh for hour in prices) / len(prices)
|
|
print(f"Average price today: {average_price:.4f} DKK/kWh")
|
|
```
|
|
|
|
### Get price data for multiple days
|
|
|
|
```python
|
|
from datetime import datetime, timedelta
|
|
from zoneinfo import ZoneInfo
|
|
from elprisenligenu import API
|
|
|
|
api = API()
|
|
timezone = ZoneInfo("Europe/Copenhagen")
|
|
|
|
# Get prices for the last 7 days
|
|
for i in range(7):
|
|
date = datetime.now(timezone) - timedelta(days=i)
|
|
try:
|
|
prices = api.get_daily_prices(zone="DK2", date=date)
|
|
avg_price = sum(hour.DKK_per_kWh for hour in prices) / len(prices)
|
|
print(f"{date.strftime('%Y-%m-%d')}: {avg_price:.4f} DKK/kWh")
|
|
except Exception as e:
|
|
print(f"Failed to get data for {date.strftime('%Y-%m-%d')}: {e}")
|
|
```
|
|
|
|
## Price Zones
|
|
|
|
Denmark is divided into two electricity price zones:
|
|
|
|
- **DK1 (West)**: Jutland and Funen (west of the Great Belt)
|
|
- Major cities: Aarhus, Aalborg, Odense, Esbjerg
|
|
- **DK2 (East)**: Zealand, Lolland, Falster, and Bornholm (east of the Great Belt)
|
|
- Major cities: Copenhagen, Roskilde, Helsingør
|
|
|
|
## Data Source
|
|
|
|
This library uses the free API provided by [ElprisenLigeNu.dk](https://www.elprisenligenu.dk). The electricity prices are:
|
|
|
|
- Spot prices from the Nord Pool electricity market
|
|
- Provided without VAT or additional fees
|
|
- Updated daily (tomorrow's prices available from 13:00 the day before)
|
|
- Historical data available from November 1, 2022
|
|
- Originally sourced from [ENTSO-E](https://transparency.entsoe.eu/) in EUR, converted to DKK
|
|
|
|
## Development
|
|
|
|
### Requirements
|
|
|
|
- Python 3.12+
|
|
- Dependencies: `pydantic>=2.12.3`, `requests>=2.32.5`
|
|
|
|
### Setup
|
|
|
|
```bash
|
|
# Clone the repository
|
|
git clone https://github.com/yourusername/elprisenligenu.git
|
|
cd elprisenligenu
|
|
|
|
# Install with development dependencies
|
|
uv sync --dev
|
|
|
|
# Run tests (unit tests only)
|
|
uv run pytest tests/unit/
|
|
|
|
# Run all tests including integration tests (requires internet)
|
|
uv run pytest
|
|
|
|
# Run tests with coverage
|
|
uv run pytest --cov=src --cov-report=html
|
|
|
|
# Type checking
|
|
uv run mypy .
|
|
|
|
# Linting
|
|
uv run ruff check .
|
|
|
|
# Formatting
|
|
uv run ruff format .
|
|
```
|
|
|
|
### Test Structure
|
|
|
|
The test suite is organized into:
|
|
|
|
- **Unit Tests** (`tests/unit/`): Fast tests that mock external dependencies
|
|
|
|
- `test_hour_data.py`: Tests for the HourData model
|
|
- `test_api.py`: Tests for the API class with mocked HTTP requests
|
|
|
|
- **Integration Tests** (`tests/test_integration.py`): Tests that make real API calls
|
|
- Marked with `@pytest.mark.integration`
|
|
- Can be skipped with `pytest -m "not integration"`
|
|
|
|
### Running Specific Tests
|
|
|
|
```bash
|
|
# Run only unit tests
|
|
uv run pytest tests/unit/
|
|
|
|
# Run only integration tests (requires internet)
|
|
uv run pytest -m integration
|
|
|
|
# Run tests matching a pattern
|
|
uv run pytest -k "test_hour_data"
|
|
|
|
# Run with verbose output
|
|
uv run pytest -v
|
|
|
|
# Run with coverage report
|
|
uv run pytest --cov=src --cov-report=term-missing
|
|
```
|
|
|
|
## License
|
|
|
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
|
|
## Attribution
|
|
|
|
When using this library in public projects, please consider attributing the data source:
|
|
|
|
> Electricity prices provided by [ElprisenLigeNu.dk](https://www.elprisenligenu.dk)
|
|
|
|
## Support
|
|
|
|
- 🐛 [Report issues](https://github.com/yourusername/elprisenligenu/issues)
|
|
- 📧 Contact: [[email protected]](mailto:[email protected])
|
|
- 🌐 ElprisenLigeNu.dk: [[email protected]](mailto:[email protected])
|
|
|
|
## Related Projects
|
|
|
|
- [ElprisenLigeNu.dk](https://www.elprisenligenu.dk) - The source website
|
|
- [API Documentation](https://www.elprisenligenu.dk/elpris-api) - Official API docs
|