Metadata-Version: 2.4
Name: thuhome-alert
Version: 0.1.1
Summary: Monitor water and electricity balance on Tsinghua University's myhome portal (myhome.tsinghua.edu.cn) and send email alerts when balances fall below user-defined thresholds.
Project-URL: Homepage, https://github.com/bill0628/thuhome-alert-py
Project-URL: Repository, https://github.com/bill0628/thuhome-alert-py
Project-URL: Issues, https://github.com/bill0628/thuhome-alert-py/issues
Project-URL: Changelog, https://github.com/bill0628/thuhome-alert-py/blob/main/CHANGELOG.md
Author-email: Bill Gao <gaobill@foxmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: alert,balance,dorm,myhome,tsinghua,utilities
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Email
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
Classifier: Topic :: System :: Monitoring
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: beautifulsoup4>=4.11
Requires-Dist: gmssl>=3.2.2
Requires-Dist: requests>=2.28
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest-mock>=3.12; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: responses>=0.24; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Requires-Dist: types-beautifulsoup4>=4.11; extra == 'dev'
Requires-Dist: types-requests>=2.28; extra == 'dev'
Description-Content-Type: text/markdown

# thuhome-alert

Monitor water and electricity balance on Tsinghua University's myhome portal
(`myhome.tsinghua.edu.cn`) and send email alerts when balances fall below
user-defined thresholds.

Python port of the R [`thuhomeAlert`](https://github.com/bill0628/thuhome-alert)
package. The two share the same `account.csv` schema — existing R users can
`pip install thuhome-alert` and keep their current config without migration.

## Features

- Login to Tsinghua myhome portal
- Fetch water and electricity balances
- Support monitoring water-only or electricity-only (for single-account users)
- Customizable threshold alerts
- Local history storage (append-only CSV)
- Schedule daily checks (Linux/macOS `crontab`, Windows Task Scheduler) via a
  single unified `schedule` command that auto-detects the OS
- CLI: `thuhome-alert setup | run | schedule | migrate`
- **Two runtime dependencies only** — `requests` and `beautifulsoup4`. SMTP,
  cron, paths, dates all via Python stdlib.

## Installation

```bash
pip install thuhome-alert
```

Or with [`pipx`](https://pypa.github.io/pipx/) for an isolated install:

```bash
pipx install thuhome-alert
```

Requires Python 3.12+.

## Quick Start

### 1. Configure Account

```bash
thuhome-alert setup \
  --user your_username \
  --passwd your_password \
  --sender sender@qq.com \
  --token your_smtp_token \
  --recipient recipient@email.com \
  --water 20 \
  --electr 20 \
  --no-test-email
```

Or from Python:

```python
import thuhome_alert

# Monitor both water and electricity
thuhome_alert.setup(
    user_name="your_username",
    user_pswd="your_password",
    email_sender="sender@qq.com",
    sender_token="your_smtp_token",
    email_recipient="recipient@email.com",
    water_threshold=20,
    electr_threshold=20,
    test_email=False,
)

# Monitor electricity only (set water_threshold = None)
thuhome_alert.setup(
    user_name="your_username",
    user_pswd="your_password",
    email_sender="sender@qq.com",
    sender_token="your_smtp_token",
    email_recipient="recipient@email.com",
    water_threshold=None,
    electr_threshold=20,
    test_email=False,
)

# Monitor water only (set electr_threshold = None)
thuhome_alert.setup(
    user_name="your_username",
    user_pswd="your_password",
    email_sender="sender@qq.com",
    sender_token="your_smtp_token",
    email_recipient="recipient@email.com",
    water_threshold=20,
    electr_threshold=None,
    test_email=False,
)
```

#### Local-only monitoring (no email alerts)

If you don't want email alerts — just local stat recording — skip the
email fields entirely:

```bash
# CLI: --no-email skips email prompts; alerts disabled, stats still recorded
thuhome-alert setup --user your_username --passwd your_password --no-email
```

```python
# Python: pass empty strings for email fields
thuhome_alert.setup(
    user_name="your_username",
    user_pswd="your_password",
    email_sender="",
    sender_token="",
    email_recipient="",
    test_email=False,
)
```

With no email config, `run_monitor()` skips alert sending and periodic
reports but still records balances to disk. Add email later with
`--update`:

```bash
thuhome-alert setup --update --sender sender@qq.com --token TOK --recipient r@e.com
```

Config is saved to `$XDG_CONFIG_HOME/thuhomeAlert/account.csv` (default
`~/.config/thuhomeAlert/account.csv`, XDG-compliant). Balance history is
stored at `$XDG_DATA_HOME/thuhomeAlert/stat.dorm.csv` (default
`~/.local/share/thuhomeAlert/stat.dorm.csv`).

### 2. Run Monitor

```bash
# Check balances and send alerts if needed
thuhome-alert run

# Check only (no recording, no alerts)
thuhome-alert run --no-record --no-alert
```

Or from Python:

```python
import thuhome_alert

# Check balances and send alerts if needed
thuhome_alert.run_monitor()

# Check only (no recording, no alerts)
thuhome_alert.run_monitor(record=False, alert=False)
```

### 3. Schedule Daily Checks

```bash
# Run daily at 8 AM (auto-detects OS: crontab on Linux/macOS, schtasks on Windows)
thuhome-alert schedule --time 08:00

# Run daily at 6 PM
thuhome-alert schedule --time 18:00

# Uninstall the scheduled job
thuhome-alert schedule --uninstall
```

Or from Python:

```python
import thuhome_alert

# Run daily at 8 AM
thuhome_alert.schedule_daily("08:00")

# Run daily at 6 PM
thuhome_alert.schedule_daily("18:00")
```

### 4. Migrate (no-op for compatibility)

```bash
thuhome-alert migrate
```

The config schema is already compatible with this version, so this command
is a no-op that simply reports the config/data paths. It exists to provide
a forward-compatible migration hook for future versions.

## Configuration

The `account.csv` file (CSV format) has these columns — names match the R
package exactly, including the non-obvious `passwd` and plural `recipients`:

| column             | meaning                                   |
|--------------------|-------------------------------------------|
| `user`             | portal username                           |
| `passwd`           | portal password (note: not `password`)    |
| `sender`           | SMTP sender email                          |
| `recipients`       | alert recipient email (note: plural)      |
| `token`            | SMTP password/token                        |
| `water_threshold`  | RMB; empty disables water monitoring      |
| `electr_threshold` | kWh; empty disables electricity monitoring |
| `report_freq`      | `none` / `weekly` / `monthly`             |
| `last_report`      | ISO date string; updated after each report |

### Behavior notes

- `setup(update=True)` merges into existing config (only overwrites provided
  fields); `setup(force=True)` overwrites the whole file. With neither, an
  existing config is left untouched.
- `setup()` is **interactive** — it prompts via `input()` / `getpass.getpass()`
  for any missing param. In non-interactive contexts (cron, tests, agents)
  pass every param explicitly, or use the CLI flags `--user`, `--passwd`,
  `--sender`, `--token`, `--recipient`, `--water`, `--electr`.
- CLI flags `--no-water` / `--no-electr` explicitly disable monitoring for a
  utility. `--no-email` skips email config entirely (local-only mode).
- When no email config is present (empty `sender` / `recipients` / `token`),
  `run_monitor()` skips alert sending and periodic reports but still records
  balances to disk.
- `run_monitor()` will **auto-disable** a threshold by writing `None` back to
  `account.csv` if the portal returns no balance for that utility (e.g. user
  has no water account). Both thresholds `None` triggers a `RuntimeError`.
- `report_freq = "weekly"` fires when ≥7 days since `last_report`; `"monthly"`
  fires when the calendar month/year changes. After sending, `last_report`
  is overwritten in `account.csv`.

## SMTP limitation

`send_alert()` is **hardcoded to `smtp.qq.com:587`** — only works with a QQ
Mail sender account. This mirrors the R package's behavior (per its
`AGENTS.md`) and is intentionally not parameterized. Do not try to change
this without explicit coordination — the limitation is documented as a known
issue in both implementations.

## Dependencies

- Python >= 3.12
- `requests` (HTTP client)
- `beautifulsoup4` (HTML parsing)

Optional (only for development):

- `pytest`, `pytest-cov`, `pytest-mock`, `responses` (testing)
- `ruff` (lint + format)
- `mypy` (typecheck)
- `build` (sdist/wheel building)

## Development

```bash
# Clone
git clone https://github.com/bill0628/thuhome-alert-py.git
cd thuhome-alert-py

# Install with dev dependencies (uses uv)
uv sync --extra dev

# Run tests
uv run pytest

# Lint
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/

# Typecheck
uv run mypy --strict src/thuhome_alert

# Build sdist + wheel
uv build
```

## Comparison with R package

| Aspect | R `thuhomeAlert` | Python `thuhome-alert` |
|---|---|---|
| Language | R >= 4.1 | Python >= 3.12 |
| Runtime deps | 8 packages + `rJava` JVM | 2 packages (`requests`, `beautifulsoup4`) |
| SMTP | `mailR` (requires JVM) | stdlib `smtplib` |
| Cron scheduling | `cronR` (Linux/mac) + `taskscheduleR` (Windows), separate functions | stdlib `subprocess` calling `crontab` / `schtasks`, **single unified** `schedule_daily()` |
| Interactive prompts | `readline()` / `getPass::getPass()` | stdlib `input()` / `getpass.getpass()` |
| Data frames | `tibble` / `dplyr` | `dataclass(frozen=True)` |
| Cold start | ~1-2s (R + tidyverse load) | ~150ms |
| `account.csv` schema | (canonical) | byte-for-byte identical |
| CLI | none (R functions only) | `thuhome-alert` console script |

The two implementations are designed to coexist: users can switch freely
between them since the config and data files are interchangeable.

## Scraping brittleness

The portal scraping depends on ASP.NET form field names and DOM element IDs
(mirrored exactly from the R implementation):

- Login form fields: `net_Default_LoginCtrl1$txtUserName`,
  `net_Default_LoginCtrl1$txtPassword`
- Login success is detected by absence of `noLogin` in the redirect URL.
- Balance elements:
  - `#Netweb_Home_water_DetailCtrl1_lblele` (water, suffix `元`)
  - `#Netweb_Home_electricity_DetailCtrl1_lblele` (electricity, numeric)

If scraping breaks, these selectors are the first thing to verify against the
live portal HTML.

## License

MIT — see [LICENSE](LICENSE).

## Contributing

Issues and Pull Requests are welcome at
[github.com/bill0628/thuhome-alert-py](https://github.com/bill0628/thuhome-alert-py).

## See also

- [thuhome-alert (R package)](https://github.com/bill0628/thuhome-alert) —
  the original R implementation, maintained in parallel.
