Skip to content

wojt-janowski/laravel-amber

Repository files navigation

Laravel Amber

A Laravel package for interacting with the Amber Energy public API. Amber is an Australian electricity retailer that passes through real-time wholesale prices, allowing you to automate high-power devices based on current and forecast prices.

Features

  • 🔌 Full support for all Amber Energy API endpoints
  • 📊 Eloquent models for optional local data persistence
  • 🔄 Automatic retry logic with progressive backoff
  • ⚡ Rate limiting with graceful exception handling
  • 🎯 Fluent facade API for clean, readable code
  • 🛡️ Comprehensive exception handling
  • 📝 Publishable configuration and migrations
  • 🔍 Query scopes for easy data filtering

Requirements

  • PHP 8.1 or higher
  • Laravel 10.x, 11.x, or 12.x

Installation

Install the package via Composer:

composer require wojt-janowski/laravel-amber

Publish Configuration

Publish the configuration file:

php artisan vendor:publish --tag=amber-config

Run Migrations (Optional)

If you want to store API data locally, simply run the migrations:

php artisan migrate

The package migrations are automatically loaded and will be executed with your application's migrations.

Configuration

Add your Amber API key to your .env file:

AMBER_API_KEY=your-api-key-here

You can obtain an API key from the Amber app or by contacting Amber support.

Additional Configuration Options

AMBER_BASE_URL=https://api.amber.com.au/v1  # API base URL (default)
AMBER_TIMEOUT=30                             # Request timeout in seconds
AMBER_RETRY_TIMES=3                          # Number of retry attempts
AMBER_RETRY_SLEEP=1000                       # Base retry delay in milliseconds
AMBER_RATE_LIMIT_WARNING=10                  # Log warning when requests remaining < threshold

Usage

Using the Facade

The package provides a fluent facade for easy API access:

use WojtJanowski\LaravelAmber\Facades\Amber;

// Get all sites linked to your account
$sites = Amber::getSites();

// Get current prices for a site
$prices = Amber::getCurrentPrices('site-id-123');

// Get current prices with forecast and historical data
$prices = Amber::getCurrentPrices(
    siteId: 'site-id-123',
    next: 48,        // Next 48 intervals forecast
    previous: 48,    // Previous 48 actual intervals
    resolution: 30   // 30-minute intervals
);

// Get historical prices for a date range
$historicalPrices = Amber::getPrices(
    siteId: 'site-id-123',
    startDate: '2024-01-01',
    endDate: '2024-01-07',
    resolution: 30
);

// Get usage data
$usage = Amber::getUsage(
    siteId: 'site-id-123',
    startDate: '2024-01-01',
    endDate: '2024-01-07'
);

// Get renewable percentage for a state
$renewables = Amber::getCurrentRenewables(
    state: 'vic',
    next: 24,
    previous: 24
);

Using Dependency Injection

You can also inject the AmberClient directly:

use WojtJanowski\LaravelAmber\AmberClient;

class EnergyController extends Controller
{
    public function __construct(
        protected AmberClient $amber
    ) {}

    public function getCurrentPrices(string $siteId)
    {
        $prices = $this->amber->getCurrentPrices($siteId);

        return response()->json($prices);
    }
}

Working with Models

If you've published and run the migrations, you can persist API data locally:

Storing Sites

use WojtJanowski\LaravelAmber\Facades\Amber;
use WojtJanowski\LaravelAmber\Models\AmberSite;

$sitesData = Amber::getSites();

foreach ($sitesData as $siteData) {
    AmberSite::updateOrCreate(
        ['id' => $siteData['id']],
        $siteData
    );
}

Querying Sites

use WojtJanowski\LaravelAmber\Models\AmberSite;

// Get all active sites
$activeSites = AmberSite::active()->get();

// Get a site with its price intervals
$site = AmberSite::with('priceIntervals')->find('site-id-123');

// Get sites by status
$pendingSites = AmberSite::pending()->get();
$closedSites = AmberSite::closed()->get();

Storing Price Intervals

use WojtJanowski\LaravelAmber\Models\AmberPriceInterval;

$pricesData = Amber::getCurrentPrices('site-id-123');

foreach ($pricesData as $priceData) {
    AmberPriceInterval::create([
        'site_id' => 'site-id-123',
        'type' => $priceData['type'],
        'channel_type' => $priceData['channelType'],
        'duration' => $priceData['duration'],
        'spot_per_kwh' => $priceData['spotPerKwh'],
        'per_kwh' => $priceData['perKwh'],
        'date' => $priceData['date'],
        'nem_time' => $priceData['nemTime'],
        'start_time' => $priceData['startTime'],
        'end_time' => $priceData['endTime'],
        'renewables' => $priceData['renewables'],
        'spike_status' => $priceData['spikeStatus'],
        'descriptor' => $priceData['descriptor'],
        'estimate' => $priceData['estimate'] ?? null,
        'tariff_information' => $priceData['tariffInformation'] ?? null,
    ]);
}

Querying Price Intervals

use WojtJanowski\LaravelAmber\Models\AmberPriceInterval;

// Get all actual price intervals
$actualPrices = AmberPriceInterval::actual()->get();

// Get forecast prices for a specific channel
$forecastPrices = AmberPriceInterval::forecast()
    ->channelType('general')
    ->get();

// Get spike prices
$spikes = AmberPriceInterval::spike()->get();

Working with Usage Data

use WojtJanowski\LaravelAmber\Models\AmberUsage;

// Get billable usage only
$billableUsage = AmberUsage::billable()->get();

// Get usage for a date range
$usage = AmberUsage::betweenDates('2024-01-01', '2024-01-07')->get();

// Get usage by channel type
$generalUsage = AmberUsage::channelType('general')->get();

Working with Renewables

use WojtJanowski\LaravelAmber\Models\AmberRenewable;

// Get renewables for a specific state
$vicRenewables = AmberRenewable::state('vic')->get();

// Get actual renewables
$actualRenewables = AmberRenewable::actual()->get();

// Get renewables for a date range
$renewables = AmberRenewable::betweenDates('2024-01-01', '2024-01-07')->get();

Error Handling

The package throws specific exceptions for different error scenarios:

use WojtJanowski\LaravelAmber\Facades\Amber;
use WojtJanowski\LaravelAmber\Exceptions\AmberAuthenticationException;
use WojtJanowski\LaravelAmber\Exceptions\AmberRateLimitException;
use WojtJanowski\LaravelAmber\Exceptions\AmberApiException;

try {
    $sites = Amber::getSites();
} catch (AmberAuthenticationException $e) {
    // Invalid or missing API key
    Log::error('Authentication failed: ' . $e->getMessage());
} catch (AmberRateLimitException $e) {
    // Rate limit exceeded
    $retryAfter = $e->getRetryAfter();
    Log::warning("Rate limit hit. Retry after {$retryAfter} seconds");
} catch (AmberApiException $e) {
    // Other API errors (4xx, 5xx)
    $statusCode = $e->getStatusCode();
    $responseBody = $e->getResponseBody();
    Log::error("API error {$statusCode}", $responseBody);
}

Automatic Retry Logic

The package automatically retries failed requests with progressive backoff:

  • Retry attempts: 3 times by default (configurable)
  • Backoff strategy: Exponential (1s, 2s, 4s)
  • Retries on: Connection errors, 429 (rate limit), 500, 502, 503, 504
  • No retry on: 400, 401, 404, 422

Rate Limiting

The Amber API includes rate limiting. The package:

  • Automatically extracts rate limit headers from responses
  • Logs warnings when approaching the limit (configurable threshold)
  • Throws AmberRateLimitException when the limit is exceeded
  • Includes retry-after time in the exception

Available Models

AmberSite

Represents an Amber Energy site (property).

Relationships:

  • priceIntervals() - HasMany relationship to price intervals
  • usage() - HasMany relationship to usage records

Scopes:

  • active() - Only active sites
  • pending() - Only pending sites
  • closed() - Only closed sites

AmberPriceInterval

Stores price interval data (actual, current, or forecast).

Relationships:

  • site() - BelongsTo relationship to site

Scopes:

  • actual() - Only actual intervals
  • current() - Only current intervals
  • forecast() - Only forecast intervals
  • channelType(string) - Filter by channel type
  • spike() - Only spike prices

AmberUsage

Stores energy usage data.

Relationships:

  • site() - BelongsTo relationship to site

Scopes:

  • billable() - Only billable quality
  • estimated() - Only estimated quality
  • channelType(string) - Filter by channel type
  • betweenDates(string, string) - Date range filter

AmberRenewable

Stores renewable energy percentage data by state.

Scopes:

  • state(string) - Filter by state
  • actual() - Only actual renewables
  • current() - Only current renewables
  • forecast() - Only forecast renewables
  • betweenDates(string, string) - Date range filter

API Endpoints

Method Endpoint Description
getSites() GET /sites Get all sites linked to your account
getCurrentPrices() GET /sites/{siteId}/prices/current Get current prices with optional forecast/history
getPrices() GET /sites/{siteId}/prices Get historical prices for date range
getUsage() GET /sites/{siteId}/usage Get usage data for date range
getCurrentRenewables() GET /state/{state}/renewables/current Get renewable percentage for state

Support

For issues with the package, please open an issue on GitHub.

For Amber API support, contact dev@amber.com.au.

License

MIT License. See LICENSE file for details.

Credits

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors