rocktopus
packagerocktopus
is an R package designed to interact with the
Octopus Energy API, allowing users to retrieve and process energy
consumption data. This vignette provides a brief overview of how to set
up and use the package.
To use the rocktopus
package, you need to install it
along with its dependencies. The following code snippet demonstrates how
to install the package and its required libraries:
# Install the rocktopus package from GitHub
if(!require("needs")) install.packages(c("needs"), repos = "https://cloud.r-project.org/")
#> Loading required package: needs
library(needs)
needs("tidyverse", "data.table", "janitor", "lubridate", "httr", "glue", "purrr", "rlist")
devtools::install_github("julianflowers12/rocktopus", force = TRUE)
#> Using GitHub PAT from the git credential store.
#> Downloading GitHub repo julianflowers12/rocktopus@HEAD
#>
#> ── R CMD build ─────────────────────────────────────────────────────────────────
#> checking for file ‘/private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpSZwcyJ/remotes2d1d5b8a88f1/julianflowers12-rocktopus-7eecdf9/DESCRIPTION’ ... ✔ checking for file ‘/private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpSZwcyJ/remotes2d1d5b8a88f1/julianflowers12-rocktopus-7eecdf9/DESCRIPTION’
#> ─ preparing ‘rocktopus’:
#> checking DESCRIPTION meta-information ... ✔ checking DESCRIPTION meta-information
#> Warning: /private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpEj4V5j/Rbuild2d324c1dd2c2/rocktopus/man/txt_to_parquet_dataset.Rd:20: unknown macro '\item'
#> Warning: /private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpEj4V5j/Rbuild2d324c1dd2c2/rocktopus/man/txt_to_parquet_dataset.Rd:21: unknown macro '\item'
#> Warning: /private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpEj4V5j/Rbuild2d324c1dd2c2/rocktopus/man/txt_to_parquet_dataset.Rd:22: unknown macro '\item'
#> Warning: /private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpEj4V5j/Rbuild2d324c1dd2c2/rocktopus/man/txt_to_parquet_dataset.Rd:99: unknown macro '\item'
#> Warning: /private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpEj4V5j/Rbuild2d324c1dd2c2/rocktopus/man/txt_to_parquet_dataset.Rd:100: unknown macro '\item'
#> Warning: /private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpEj4V5j/Rbuild2d324c1dd2c2/rocktopus/man/txt_to_parquet_dataset.Rd:101: unknown macro '\item'
#> ─ checking for LF line-endings in source and make files and shell scripts
#> ─ checking for empty or unneeded directories
#> Omitted ‘LazyData’ from DESCRIPTION
#> Warning: /private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpEj4V5j/Rbuild2d324c1dd2c2/rocktopus/man/txt_to_parquet_dataset.Rd:20: unknown macro '\item'
#> Warning: /private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpEj4V5j/Rbuild2d324c1dd2c2/rocktopus/man/txt_to_parquet_dataset.Rd:21: unknown macro '\item'
#> Warning: /private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpEj4V5j/Rbuild2d324c1dd2c2/rocktopus/man/txt_to_parquet_dataset.Rd:22: unknown macro '\item'
#> Warning: /private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpEj4V5j/Rbuild2d324c1dd2c2/rocktopus/man/txt_to_parquet_dataset.Rd:99: unknown macro '\item'
#> Warning: /private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpEj4V5j/Rbuild2d324c1dd2c2/rocktopus/man/txt_to_parquet_dataset.Rd:100: unknown macro '\item'
#> Warning: /private/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T/RtmpEj4V5j/Rbuild2d324c1dd2c2/rocktopus/man/txt_to_parquet_dataset.Rd:101: unknown macro '\item'
#> NB: this package now depends on R (>= 4.1.0)
#> WARNING: Added dependency on R >= 4.1.0 because package code uses the
#> pipe |> or function shorthand \(...) syntax added in R 4.1.0.
#> File(s) using such syntax:
#> ‘get_consumption_details.R’ ‘get_meter_details.R’
#> ‘get_mpan_details.R’ ‘get_tariff_details.R’ ‘get_tariffs.R’
#> ‘http_helper.R’ ‘process_consumption_data.R’ ‘process_ev.R’
#> ─ building ‘rocktopus_0.1.0.tar.gz’
#>
#>
#> Warning in i.p(...): installation of package
#> '/var/folders/bk/jrqs03tx5mq9s28mhml5xzhm0000gn/T//RtmpSZwcyJ/file2d1d6424b52a/rocktopus_0.1.0.tar.gz'
#> had non-zero exit status
library(rocktopus)
theme_set(ggthemes::theme_economist())
To use the rocktopus
package, you need to set up your
Octopus Energy account and API key as environment variables. This allows
the package to authenticate and access your energy consumption data
securely.
You can obtain an API key from your Octopus Energy account settings.
An API key can be generated by creating an Octopus developer account -
https://octopus.energy/dashboard/new/accounts/personal-details/api-access.
Once you have your account number and API key, you can set them as
environment variables in your R session or in your
.Renviron
file.
To retrieve meter details associated with your Octopus Energy
account, you can use the get_meter_details
function from
the rocktopus
package. This function requires your account
number and API key as inputs.
get_meter_details
retrieves a list of details about your
electricity and gas meters, including their unique identifiers (MPAN for
electricity and MPRN for gas), meter serial numbers, and other relevant
details.
# Retrieve meter details using the get_meter_details function
meter_details <- rocktopus::get_meter_info(acct, api_key)
#> Loading required package: httr2
We can now extract the MPAN and meter serial number for each property
associated with your account. The get_electric_mpan
function can be used to retrieve the MPAN and serial number for a
specific property index.
We can also extract a table of tariff information.
tariffs <- get_tariff_info(api_key, acct, property_index = params$property_index)
#> Using `unnest_wider(value)`; elements have 3 names in common
#> Using `unnest_wider(value)`; elements have 5 names in common
#> Using `unnest_wider(value)`; elements have 5 names in common
#> Using `unnest_wider(value)`; elements have 3 names in common
#> Using `unnest_wider(value)`; elements have 5 names in common
tariffs |>
head(10)
#> $standing_charges
#> # A tibble: 3 × 6
#> name value_exc_vat value_inc_vat valid_from valid_to payment_method
#> <chr> <dbl> <dbl> <chr> <chr> <lgl>
#> 1 results 43.3 45.4 2025-06-30T23:00:… <NA> NA
#> 2 results 45.3 47.6 2025-03-31T23:00:… 2025-06… NA
#> 3 results 46.5 48.8 2024-10-29T00:00:… 2025-03… NA
#>
#> $unit_rates
#> # A tibble: 100 × 6
#> name value_exc_vat value_inc_vat valid_from valid_to payment_method
#> <chr> <dbl> <dbl> <chr> <chr> <lgl>
#> 1 results 6.67 7.00 2025-09-15T22:30… 2025-09… NA
#> 2 results 27.6 29.0 2025-09-15T04:30… 2025-09… NA
#> 3 results 6.67 7.00 2025-09-14T22:30… 2025-09… NA
#> 4 results 27.6 29.0 2025-09-14T04:30… 2025-09… NA
#> 5 results 6.67 7.00 2025-09-13T22:30… 2025-09… NA
#> 6 results 27.6 29.0 2025-09-13T04:30… 2025-09… NA
#> 7 results 6.67 7.00 2025-09-12T22:30… 2025-09… NA
#> 8 results 27.6 29.0 2025-09-12T04:30… 2025-09… NA
#> 9 results 6.67 7.00 2025-09-11T22:30… 2025-09… NA
#> 10 results 27.6 29.0 2025-09-11T04:30… 2025-09… NA
#> # ℹ 90 more rows
#>
#> $export_rates
#> # A tibble: 3 × 6
#> name value_exc_vat value_inc_vat valid_from valid_to payment_method
#> <chr> <dbl> <dbl> <chr> <chr> <lgl>
#> 1 results 15 15 2022-09-19T23:00:… <NA> NA
#> 2 results 7.5 7.5 2022-02-01T00:00:… 2022-09… NA
#> 3 results 5.5 5.5 2019-05-15T23:00:… 2022-02… NA
#>
#> $gas_standing_charges
#> # A tibble: 0 × 0
#>
#> $gas_unit_rates
#> # A tibble: 0 × 0
The next step is to create endpoints for retrieving consumption data.
The create_endpoint
function constructs a URL for accessing
consumption data based on the MPAN and meter serial number.
To retrieve consumption data, you can use the get_cons
function, which takes the consumption endpoint URL as input. This
function returns a tibble containing the consumption details.
consumption_data <- get_cons(cons_url, api_key = api_key)
#> Using `unnest_wider(value)`; elements have 3 names in common
head(consumption_data)
#> # A tibble: 6 × 4
#> name consumption interval_start interval_end
#> <chr> <dbl> <chr> <chr>
#> 1 results 3.74 2025-09-13T00:30:00+01:00 2025-09-13T01:00:00+01:00
#> 2 results 4.60 2025-09-13T00:00:00+01:00 2025-09-13T00:30:00+01:00
#> 3 results 0.009 2025-09-12T23:30:00+01:00 2025-09-13T00:00:00+01:00
#> 4 results 0 2025-09-12T23:00:00+01:00 2025-09-12T23:30:00+01:00
#> 5 results 0 2025-09-12T22:30:00+01:00 2025-09-12T23:00:00+01:00
#> 6 results 0 2025-09-12T22:00:00+01:00 2025-09-12T22:30:00+01:00
To process the retrieved consumption data, you can use the
process_consumption_data
function. This function cleans and
formats the data, making it easier to analyze and visualize.
processed_data <- process_consumption_data(consumption_data) |>
arrange(desc(date))
#> Warning: There were 2 warnings in `mutate()`.
#> The first warning was:
#> ℹ In argument: `time = hm(str_sub(interval_start, 12, 16))`.
#> Caused by warning in `.parse_hms()`:
#> ! Some strings failed to parse
#> ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
head(processed_data)
#> # A tibble: 6 × 14
#> wk name consumption interval_start interval_end interval
#> <dbl> <chr> <dbl> <dttm> <dttm> <drtn>
#> 1 37 results 3.74 2025-09-12 23:30:00 2025-09-13 00:00:00 30 mins
#> 2 37 results 4.60 2025-09-12 23:00:00 2025-09-12 23:30:00 30 mins
#> 3 37 results 0.009 2025-09-12 22:30:00 2025-09-12 23:00:00 30 mins
#> 4 37 results 0 2025-09-12 22:00:00 2025-09-12 22:30:00 30 mins
#> 5 37 results 0 2025-09-12 21:30:00 2025-09-12 22:00:00 30 mins
#> 6 37 results 0 2025-09-12 21:00:00 2025-09-12 21:30:00 30 mins
#> # ℹ 8 more variables: date <date>, time <Period>, start <dttm>, hour_st <int>,
#> # hour_end <int>, month <ord>, year <dbl>, peak <chr>
processed_data |>
mutate(day = lubridate::wday(date, label = TRUE),
month = lubridate::month(date, label = TRUE),
year = year(date),
sun = case_when(day == "Sun" ~ 'sun', TRUE ~ 'other')) |>
filter(peak == "off_peak", date >= "2025-04-01") |>
select(date, day, sun, consumption) |>
group_by(date, day) |>
reframe(sumconsmption = mean(consumption, na.rm = TRUE)) |>
#left_join(ev_data, by = "date") |>
ggplot(aes(x = date, y = sumconsmption, colour = day)) +
#geom_point() +
geom_smooth(method = "loess", se = FALSE, aes(lty = day), span = 0.5) +
theme_classic()
#> `geom_smooth()` using formula = 'y ~ x'
You can visualize the processed consumption data using
ggplot2
. The following code snippet demonstrates how to
create a bar plot showing electricity consumption over time, categorized
by peak and off-peak periods.
processed_data |>
group_by(date, peak) |>
summarise(total = sum(consumption, na.rm = TRUE)) |>
filter(date > "2024-08-31") |>
ggplot(aes(x = date, y = total, colour = peak)) +
geom_point() +
geom_smooth(method = "gam", se = FALSE, aes(fill = peak), alpha = 0.2) +
labs(
title = "Electricity Consumption",
x = "Date",
y = "Consumption (kWh)",
fill = "Peak"
) +
scale_x_date(date_labels = "%Y-%m-%d", date_breaks = "1 month") +
theme(axis.text.x= element_text(angle = 90, hjust = 1, size = 10),
title = element_text(size = 14, face = "bold"),
legend.position = "bottom",
plot.title.position = "plot") +
geom_vline(xintercept = as.Date(c("2025-05-18", "2025-04-29")), linetype = "dashed", color = "black") +
facet_wrap(~ peak, scales = "free")
#> `summarise()` has grouped output by 'date'. You can override using the
#> `.groups` argument.
#> `geom_smooth()` using formula = 'y ~ s(x, bs = "cs")'
off_peak <- processed_data |>
filter(date > "2024-08-31") |>
group_by(year = year(date), month = month(date), peak) |>
reframe(mon_cons = sum(consumption)) |>
pivot_wider(names_from = peak, values_from = mon_cons) |>
mutate(summer = mean(peak[month %in% c(4:9)]),
winter = mean(peak[month %in% c(10:12, 1:3)]),
summer1 = mean(off_peak[month %in% c(4:9)]),
winter1 = mean(off_peak[month %in% c(10:12, 1:3)]),
period = lubridate::my(paste0(month,"-", year))) |>
ggplot(aes(x = period, y = off_peak)) +
geom_point() +
geom_smooth(method = "gam", se = FALSE, alpha = 0.2) +
geom_line(aes(y = summer1), colour = "red") +
geom_line(aes(y = winter1), colour = "blue") +
labs(
title = "Electricity Consumption",
x = "Date",
y = "Consumption (kWh)",
fill = "Peak"
) +
scale_x_date(date_labels = "%Y-%m-%d", date_breaks = "1 month") +
theme(axis.text.x= element_text(angle = 90, hjust = 1, size = 10),
title = element_text(size = 14, face = "bold"),
legend.position = "bottom",
plot.title.position = "plot") +
geom_vline(xintercept = as.Date(c("2025-05-18", "2025-04-29")), linetype = "dashed", color = "black")
peak <- processed_data |>
filter(date > "2024-08-31") |>
group_by(year = year(date), month = month(date), peak) |>
reframe(mon_cons = sum(consumption)) |>
pivot_wider(names_from = peak, values_from = mon_cons) |>
mutate(summer = mean(peak[month %in% c(4:9)]),
winter = mean(peak[month %in% c(10:12, 1:3)]),
summer1 = mean(off_peak[month %in% c(4:9)]),
winter1 = mean(off_peak[month %in% c(10:12, 1:3)]),
period = lubridate::my(paste0(month,"-", year))) |>
ggplot(aes(x = period, y = peak)) +
geom_point() +
geom_smooth(method = "gam", se = FALSE, aes(fill = peak), alpha = 0.2) +
geom_line(aes(y = summer), colour = "red") +
geom_line(aes(y = winter), colour = "blue") +
labs(
title = "Electricity Consumption",
x = "Date",
y = "Consumption (kWh)",
fill = "Peak"
) +
scale_x_date(date_labels = "%Y-%m-%d", date_breaks = "1 month") +
theme(axis.text.x= element_text(angle = 90, hjust = 1, size = 10),
title = element_text(size = 14, face = "bold"),
legend.position = "bottom",
plot.title.position = "plot") +
geom_vline(xintercept = as.Date(c("2025-05-18", "2025-04-29")), linetype = "dashed", color = "black")
library(patchwork)
off_peak + peak + plot_layout(ncol = 1)
#> `geom_smooth()` using formula = 'y ~ s(x, bs = "cs")'
#> `geom_smooth()` using formula = 'y ~ s(x, bs = "cs")'
#> Warning: The following aesthetics were dropped during statistical transformation: fill.
#> ℹ This can happen when ggplot fails to infer the correct grouping structure in
#> the data.
#> ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
#> variable into a factor?
library(rocktopus)
agg_url <- create_endpoint_agg(mpan = mpan[2,3], serial = mpan[2,4], group_by = "month")
t <- get_cons(agg_url, api_key)
octo_request <- function(url, api_key) {
httr2::request(url) |>
httr2::req_auth_basic(username = api_key, password = "") |>
httr2::req_headers(
"User-Agent" = sprintf(
"rocktopus/%s (R httr2; https://github.com/julianflowers12/rocktopus)",
utils::packageVersion("rocktopus")
)
)
}
resp <- octo_request(agg_url, api_key = Sys.getenv("OCTOPUS_API_KEY")) |>
httr2::req_perform() |>
httr2::resp_body_json()
response <- resp |>
tibble::enframe() |>
dplyr::filter(name == "results") |>
tidyr::unnest(value) |>
tidyr::unnest_auto(value)
export <- get_cons(agg_url, api_key)
octo_request(agg_url, api_key)
agg_consumption_data <- get_cons(agg_url, api_key = api_key)
mutate(date_start = ymd(str_sub(interval_start, 1, 10)))
which.max(agg_consumption_data$consumption)
agg_consumption_data |>
select(date_start, export = consumption) |>
filter(date_start > params$start) |>
ggplot(aes(x = date_start, y = export)) +
geom_col() +
geom_smooth(method = "loess", lty= "dashed", colour = "red", se = FALSE) +
scale_x_date(date_labels = "%Y-%m", date_breaks = "1 month") +
theme(axis.text.x = element_text(angle = 90, hjust = 1, size = 10),
title = element_text(size = 14, face = "bold"),
legend.position = "bottom",
plot.title.position = "plot") +
ggtitle(glue::glue("Solar export by ", {params$frequency}))