Skip to main content

Scraper for the Minol Kundenportal (utility metering data)

Project description

Minol Kundenportal Scraper

A Python scraper that authenticates to the Minol Kundenportal and fetches consumption data (heating, warm water, cold water) on a per-room basis. Pure Python — stdlib only, no third-party dependencies.

For authentication internals, data endpoint reference, and debugging, see DEVELOPMENT.md.


Credentials

Credentials are resolved in order: CLI arguments > environment variables > config file.

Source Email Password User Number
CLI --email --password --user-num
Env var MINOL_EMAIL MINOL_PASSWORD MINOL_USER_NUM
Config file email password user_num

The default config file location is ~/.minol.json (override with --config):

{
  "email": "user@example.com",
  "password": "password",
  "user_num": "000000000000"
}

Password security

Avoid --password on shared systems. Any value passed via --password is visible to other local users in the process listing (ps aux) and in /proc/PID/cmdline for the lifetime of the process.

Safer alternatives, in order of preference:

  1. Config file — store credentials in ~/.minol.json and restrict access:

    chmod 600 ~/.minol.json
    

    The scraper warns at startup if the file is readable by group or other users.

  2. Environment variables — set MINOL_EMAIL, MINOL_PASSWORD, and MINOL_USER_NUM in your shell profile or via a secrets manager.

  3. --password-stdin — pipe the password from a secrets store or a variable, avoiding it ever appearing in the argument list:

    echo "$MINOL_PASSWORD" | minol --email 'user@example.com' --user-num '000000000000' --password-stdin
    # Or from a file:
    minol --email 'user@example.com' --user-num '000000000000' --password-stdin < ~/.minol_password
    

The session cache (~/.minol_session.json) is created with permissions 0600 (owner-read-write only) and contains the session token rather than the plaintext password. See Session Caching.


Installation

Install from PyPI:

pip install minol

Or install from source:

git clone https://codeberg.org/BastiOfBerlin/minol
cd minol
pip install .

python -m minol also works without installation — just clone the repo and run from the project root.

Note for bind-mounted filesystems (e.g. container setup: some mounts do not support atomic file rename, which causes pip install to fail with EPERM. Install from a /tmp copy instead:

cp -r /workspace/minol /workspace/pyproject.toml /workspace/README.md /workspace/LICENSE /tmp/minol-build/
pip install /tmp/minol-build

Usage

All examples use the minol console script installed by pip install minol. If you are running from source without installing, substitute python -m minol for minol.

# Fetch all consumption types, last 12 months
minol \
  --email 'user@example.com' \
  --password 'password' \
  --user-num '000000000000'

# Heating only, specific date range, verbose, save to file
minol \
  --email 'user@example.com' \
  --password 'password' \
  --user-num '000000000000' \
  --type heating \
  --start 202501 \
  --end 202603 \
  --output consumption.json \
  -v

# Warm water in KWH instead of the default M3
minol \
  --email 'user@example.com' \
  --password 'password' \
  --user-num '000000000000' \
  --type warm_water \
  --unit kwh

# Raw API response (unprocessed JSON from the portal)
minol \
  --email 'user@example.com' \
  --password 'password' \
  --user-num '000000000000' \
  --raw

# Credentials from env vars or ~/.minol.json — no flags needed
minol

Shell escaping — Passwords containing $, !, backticks, or backslashes will be mangled by bash in double quotes. Always use single quotes for --password and --email on the command line, or use --password-stdin to avoid the issue entirely.


Output Format

By default the scraper returns structured data with only the relevant fields:

{
  "unit": "KWH",
  "rooms": {
    "Küche": {
      "total": 111.0,
      "device": "04B648FD82639440",
      "monthly": {
        "202503": 0,
        "202504": 5.107,
        "202505": null
      }
    }
  }
}
  • unit"KWH" (heating) or "M3" (warm water, cold water) by default. Override with --unit kwh or --unit m3.
  • rooms — keyed by room name; each entry has total, device, and monthly (null for months with no data yet).

Pass --raw to get the unprocessed API response instead.


Programmatic Usage

from minol import MinolScraper

scraper = MinolScraper("user@example.com", "password", "000000000000")
scraper.login()

# Parsed structured data (default)
heating = scraper.fetch_heating(timeline_start="202501", timeline_end="202603")
warm = scraper.fetch_warm_water()
cold = scraper.fetch_cold_water()
all_data = scraper.fetch_all()

# Override unit of measurement (warm water defaults to M3)
warm_kwh = scraper.fetch_warm_water(unit="kwh")

# Raw API response
all_raw = scraper.fetch_all_raw()
heating_raw = scraper.fetch_heating(raw=True)

# Force fresh login (skip session cache)
scraper.login(use_cache=False)

Session Caching

After a successful login the scraper saves session cookies and the token expiry timestamp to ~/.minol_session.json. On the next run, expired tokens are rejected immediately without a network request; still-valid tokens are restored from the cache, skipping the full SAML login. Pass --no-cache to force a fresh login.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

minol-1.0.1.tar.gz (30.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

minol-1.0.1-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

Details for the file minol-1.0.1.tar.gz.

File metadata

  • Download URL: minol-1.0.1.tar.gz
  • Upload date:
  • Size: 30.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for minol-1.0.1.tar.gz
Algorithm Hash digest
SHA256 c666e25ae5c15e1362095c61c8de088a8d3238aea9d3920ccb3539ad175ea91d
MD5 f78497b136dd8c82fe09e998703637f8
BLAKE2b-256 4ac039020d09bf5041c883267c57404c868450b9a2753e807d535e65e749bd7a

See more details on using hashes here.

Provenance

The following attestation bundles were made for minol-1.0.1.tar.gz:

Publisher: ci.yml on BastiOfBerlin/minol

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file minol-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: minol-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 19.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for minol-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 76397ee9651f437cdf70365169cab85232e5bf8cd9e410e22021bb6969d31159
MD5 9df6f79e7dad69d3718b1831421a3540
BLAKE2b-256 eecfd63b6049311beb40df476f1ba151f1b7fa67564a665dfa20fbc07748bf0f

See more details on using hashes here.

Provenance

The following attestation bundles were made for minol-1.0.1-py3-none-any.whl:

Publisher: ci.yml on BastiOfBerlin/minol

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page