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 (clone the repo first):

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.0.tar.gz (18.9 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.0-py3-none-any.whl (19.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: minol-1.0.0.tar.gz
  • Upload date:
  • Size: 18.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for minol-1.0.0.tar.gz
Algorithm Hash digest
SHA256 8a68e6c322afec7020295b1d9fa6a3b0373e7e73bc5ddad6b72a035eec09e712
MD5 79ffcab5f6ada5d50a772329cffc3328
BLAKE2b-256 d1b40ffd142940689ad8a0c801295b316568b7b35da23d07547d5781e4d12bb4

See more details on using hashes here.

File details

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

File metadata

  • Download URL: minol-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 19.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for minol-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 977eff1e802227c56578eb7054c5c4dca4b36dbc59c4cc760b821fe3f76aae69
MD5 eb11eb00e30d0413b3985106c7905701
BLAKE2b-256 5c6761b65ef94bc1e76ede79019bcbca1f202068c97ceb5bfe82013246d9e761

See more details on using hashes here.

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