Skip to content

zzwong/coned-cli

coned-cli

CI golangci-lint License

A headless CLI for accessing Con Edison account, billing, and energy-usage data.

coned supports:

  • Native login with SMS MFA and remembered devices
  • Secure credential and session storage through the OS keyring
  • Bill history and validated PDF downloads
  • Historical usage, costs, forecasts, weather, and neighbor comparisons
  • Green Button CSV, JSON, XML, and ZIP exports
  • Human-readable tables and structured JSON output
  • A deterministic offline demo that requires no account or network access

The project is pre-1.0. Commands and JSON schemas may change between minor releases. Authentication credentials and utility data are sensitive; review the security model before use.

Install

Download a release archive, verify its checksum, and, when the gh CLI is available, verify its GitHub build provenance:

sha256sum -c checksums.txt --ignore-missing
gh attestation verify coned-cli_<version>_<os>_<arch>.tar.gz --repo zzwong/coned-cli

Alternatively, install with Go:

go install github.com/zzwong/coned-cli/cmd/coned@latest

To build from a checkout:

make install

Go 1.25.12 or newer is required. Release binaries are available for Linux and macOS on amd64 and arm64.

Try it without an account

Demo mode is deterministic, offline, and isolated from your keyring:

coned --demo --json entities list
coned --demo usage forecast
coned --demo usage reads --aggregate hour \
  --from 2026-01-01 \
  --to 2026-01-02

Authentication

coned auth init
coned auth login
coned auth status
coned auth logout
coned auth logout --forget

Interactive password input is hidden. With persistence enabled, credentials and session cookies are stored only in macOS Keychain or Linux Secret Service. Credentials are saved only after confirmation, and there is no plaintext fallback.

For a one-off session:

coned auth login --no-store

For operator-controlled input, pass one newline-terminated password through standard input:

printf '%s\n' "$CONED_PASSWORD" | \
  coned auth login --password-stdin --no-store

There is intentionally no --password argument.

If native login is unavailable, auth import-browser can import an authenticated local Chrome or Brave session over a loopback CDP endpoint:

coned auth import-browser

Bills

coned bills list
coned --json bills list
coned bills download 2026-06-30-<id>
coned bills download 2026-06-30-<id> --output bill.pdf

Bill PDFs are first written to an owner-only temporary file with mode 0600. Before atomically moving the file to its destination, coned verifies the PDF file signature and enforces the download size limit. Existing files are left unchanged unless you pass --force.

Usage data

coned accounts list
coned usage summary
coned usage forecast
coned usage bills
coned usage weather
coned usage neighbors
coned usage meters
coned usage realtime

Use --json for structured output:

coned --json usage summary

Historical reads and costs

coned usage reads --aggregate bill
coned usage reads --aggregate day \
  --from 2026-01-01 \
  --to 2026-01-31
coned usage costs --aggregate hour \
  --from 2026-01-01 \
  --to 2026-01-02

Supported aggregation levels are bill, day, and hour. Day and hour queries require both --from and --to. Large ranges are split automatically to stay within provider limits. When granular cost data is unavailable, non-bill cost queries fall back to usage-only reads.

Normalized exports

coned usage export --format csv > usage.csv
coned usage export --format json --output usage.json

Exports support csv and json. When --output is used, coned writes to an owner-only temporary file and atomically moves it to the requested destination. Existing files are left unchanged unless you pass --force.

All usage commands are read-only. Missing real-time readings are reported as unavailable rather than returned as a provider error payload.

Accounts and meters

Provider identifiers can be represented by stable, profile-specific HMAC handles. The HMAC key is stored in the OS keyring. Raw account, premise, meter, and register identifiers are not written to configuration or diagnostic files.

coned entities list
coned --json entities list --type meter
coned entities alias account-xxxxxxxxxxxx home
coned entities alias meter-xxxxxxxxxxxx electric
coned entities select home

Use an alias or handle to select an account or meter:

coned --account home usage summary
coned --account home --meter electric usage realtime

If more than one eligible entity exists, coned requires an explicit selection instead of silently choosing the first one.

Forecast and REST-history commands currently span all authorized utility accounts. They reject explicit selectors rather than guessing how Con Edison and Opower account identifiers correspond.

Green Button exports

coned green-button inspect
coned green-button inspect --json
coned green-button export --format csv \
  --from 2026-01-01 \
  --to 2026-01-31 > usage.csv
coned green-button export --format json > usage.ndjson
coned green-button export --format xml > usage.xml
coned green-button download --format csv --output usage.zip

The provider generates these exports asynchronously. export writes the selected CSV or XML file to standard output; JSON output consists of newline-delimited objects converted from CSV. download saves the original provider ZIP through the same owner-only, atomic file-writing process.

Safe schema diagnostics

When a provider response changes, generate a value-free structural report:

coned diagnostics schema --output schema.json
coned diagnostics inspect schema.json

Diagnostics contain JSON paths, types, nullability, array cardinality, a schema version, provenance, and a small allowlist of non-sensitive enum values. They do not retain identifiers, names, addresses, dates, usage, costs, tokens, URLs, or response bodies. Diagnostic files are written with mode 0600.

Profiles and configuration

Use profiles to isolate credentials and sessions:

coned --profile home auth login

On Linux, non-secret configuration is stored at ~/.config/coned/config.json. Other operating systems use their standard user configuration directory:

{
  "base_url": "https://www.coned.com",
  "profile": "default",
  "request_timeout": 30000000000
}

CLI flags override the configured profile and timeout. The production client accepts only https://www.coned.com as its base URL.

Development

make check
make build
./bin/coned version

See CONTRIBUTING.md for development and pull-request guidance. Provider fixtures must be synthetic and include version, provenance, and last-verified metadata.

Support and security

Use GitHub issues for reproducible, sanitized bugs and feature requests. This community project cannot help with Con Edison account, billing, outage, or service requests.

Report vulnerabilities privately according to SECURITY.md. See docs/security.md for storage behavior, headless Linux limitations, and the threat model.

Disclaimer

This project interoperates with non-public web interfaces used by Con Edison’s My Account site. These interfaces are not offered as a documented or supported developer API and may change without notice. It is intended only for account holders and authorized agents accessing data they are permitted to view. Users are responsible for complying with their utility agreements and applicable terms. The software does not bypass access controls.

This project is not affiliated with or endorsed by Consolidated Edison, Inc., Opower, or Oracle. “Con Edison” and related marks belong to their respective owners.

License

Licensed under the Apache License 2.0. Copyright 2026 zzwong. Third-party license texts distributed with release archives are in third_party_licenses/.

About

Headless CLI for Con Edison account, billing, and energy-usage data

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors