enphaseR pulls solar production data for your own Enphase system from the official Enphase Enlighten cloud API (v4). It handles the awkward part — OAuth authentication — so that after a one-time browser step, a scheduled job can fetch data forever without you ever logging in again.
Two honest limitations, up front, because they’re built into Enphase’s API and no package can remove them:
-
The first authorization must happen in a browser.
Enphase requires you to log in and approve access once.
enphase_authorize()walks you through it in a couple of minutes. -
Tokens stay alive only if something refreshes them at least
monthly. Access tokens last about a day and refresh tokens
about a month. enphaseR rotates both on every API call, so any job that
runs daily or weekly keeps authentication perpetually fresh. But if
nothing runs for over a month — say, the machine was off — you’ll have
to repeat the browser step (a single
enphase_authorize()call).
One-time setup
1. Create an Enphase developer application
You need three credentials, all free:
- Go to https://developer-v4.enphase.com and create a developer account (separate from your homeowner/Enlighten account).
- Choose the free Watt plan (1,000 API requests per month, 10 per minute — plenty for a daily fetch).
- Create an application, and grant it access to both
System Details and Site Level Production
Monitoring when asked what the application can use. This
matters: Enphase checks each endpoint against the application’s access
list, and an application missing a category gets
401 Not authorized to access this resourcefrom those endpoints even with valid credentials.enphase_systems()andenphase_summary()need System Details;enphase_production()needs Site Level Production Monitoring. The application’s page shows the three values you need: Client ID, Client Secret, and API Key.
2. Authorize in the browser
In an interactive R session:
library(enphaseR)
enphase_authorize(
client_id = "your-client-id",
client_secret = "your-client-secret",
api_key = "your-api-key"
)Your browser opens Enphase’s authorization page. Log in with your homeowner (Enlighten) account — the one you use in the Enphase app — approve access, copy the code it displays, and paste it into the R console.
That’s it. Credentials and tokens are saved (with restrictive
permissions) to tools::R_user_dir("enphaseR", "config"), or
wherever the ENPHASER_CONFIG_DIR environment variable or
the config_dir argument points.
Fetching production data
enphase_production() returns a tibble with one row per
15-minute interval: the date, the interval’s end time
(end_at), and watt-hours delivered
(wh_del).
# Yesterday (the default):
prod <- enphase_production(system_id = 1234567)
# A specific day:
enphase_production(1234567, start_date = "2026-06-15")
# A range -- one API request per day, automatically paced to respect
# the free plan's rate limit:
june <- enphase_production(
1234567,
start_date = "2026-06-01",
end_date = "2026-06-30"
)A completed day has 96 intervals. If Enphase hasn’t finished reporting a recent day you’ll get fewer rows and a warning; just re-fetch that day later.
Don’t expect the totals to match the Enlighten app exactly. Enphase
records production two ways — the site’s revenue-grade production meter
and the microinverters’ own reports — and the two typically differ by
around 1% because they measure at different points in the system.
enphase_production() returns the meter values; the app may
display either source. A mismatch of that size isn’t a bug on anyone’s
part.
Saving is up to you — the result is an ordinary tibble, so use whatever format you like:
readr::write_csv(prod, "production.csv")
# or saveRDS(prod, "production.rds"), arrow::write_parquet(), ...There’s also enphase_summary(system_id) for a one-row
snapshot of current power, today’s energy, and lifetime production.
Automating it (so you never re-authenticate)
The whole point: Schedule a small script that runs daily. Every run refreshes and rotates the tokens as a side effect, which keeps authentication alive indefinitely.
A complete example script, fetch_solar.R, that appends
yesterday’s data to a CSV:
library(enphaseR)
system_id <- 1234567
csv_path <- "~/solar/production.csv"
new_rows <- enphase_production(system_id)
if (file.exists(csv_path)) {
old <- readr::read_csv(csv_path, show_col_types = FALSE)
# Keep only intervals we don't already have
new_rows <- dplyr::anti_join(new_rows, old, by = c("date", "end_at"))
readr::write_csv(new_rows, csv_path, append = TRUE)
} else {
readr::write_csv(new_rows, csv_path)
}
message(nrow(new_rows), " new rows written")Linux/macOS: cron
Run it every morning at 6:05 (production for yesterday is complete by then):
5 6 * * * /usr/bin/Rscript /home/you/solar/fetch_solar.R >> /home/you/solar/fetch.log 2>&1
Add the entry with crontab -e. If cron runs as a
different user than the one who ran enphase_authorize(),
set ENPHASER_CONFIG_DIR in the script (or pass
config_dir=) so it finds the token files.
Windows: Task Scheduler
Either use Task Scheduler directly — create a daily task whose action
runs Rscript.exe C:\path\to\fetch_solar.R — or set it up
from R with the taskscheduleR
package:
taskscheduleR::taskscheduler_create(
taskname = "enphase_daily",
rscript = "C:/path/to/fetch_solar.R",
schedule = "DAILY",
starttime = "06:05"
)Note that a scheduled task only runs while the machine is on; if your computer sleeps through the scheduled time, enable “Run task as soon as possible after a scheduled start is missed” in the task’s settings.
Make failures visible
A silent cron job can fail for a month without you noticing — which is exactly how a refresh token lapses. Have the script log to a file (as the cron line above does) and, ideally, alert you on failure. A minimal pattern:
result <- try(enphase_production(system_id))
if (inherits(result, "try-error")) {
# write to a log, send an email (e.g. with the emayili package),
# or trigger any notification you already use
}If the refresh token lapses anyway
You’ll see an error like:
Enphase rejected the token refresh. The refresh token has likely expired
(they last about a month) — run enphase_authorize() to re-authorize in
the browser, then try again.
Recovery is one no-argument call in an interactive session — your saved credentials are reused, so there’s nothing to look up:
Then your scheduled job resumes working, and past days can be
backfilled with a start_date/end_date
range.