Implemented the full clean rewrite for Gitea
All checks were successful
Test blackout notifier / test (push) Successful in 3m41s
Hourly blackout check / check (push) Successful in 8s

This commit is contained in:
Meghdad
2026-07-17 04:33:16 +03:30
parent d7f53ba234
commit 4218e4ac36
30 changed files with 1437 additions and 384 deletions

104
README.md
View File

@@ -1,30 +1,94 @@
# daily-blackout-check
# Daily Blackout Check
Checks planned power outages and sends new notices to an Eitaa chat.
Checks the official SAAPA planned-outage API and sends Persian notifications to
an Eitaa chat when an outage is added, changed, cancelled, or restored.
## Setup
The checker is designed for an hourly Gitea Actions workflow. Its deduplication
state is stored in `state/outages.json` and committed back to this repository.
1. Create and activate a Python virtual environment, then install dependencies:
## Behavior
```sh
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
- Queries each configured bill ID from today through five days ahead.
- Uses Tehran time regardless of the runner container's timezone.
- Sends all upcoming outages when starting with empty state.
- Treats an existing outage number with changed time, address, date, reason, or
planned status as an update.
- Reports a future outage as cancelled only after two consecutive successful
checks omit it.
- Records a notification only after Eitaa accepts it. This favors delivery over
perfect deduplication: a failed state push can cause a duplicate next hour.
- Rejects malformed responses and snapshots larger than the configured safety
limit without changing that bill's state.
2. Copy the example configuration and replace its placeholder values:
## Local setup
```sh
cp .env.example .env
```
Python 3.11 or newer is required. CI uses Python 3.13.
3. Run the checker:
```sh
python -m venv .venv
source .venv/bin/activate
python -m pip install -e '.[test]'
cp .env.example .env
```
```sh
python main.py
```
Fill in the required values in `.env`, then preview the next run without sending
messages or changing state:
The `.env` file is ignored by Git so tokens are not committed. Environment
variables supplied by the shell or GitHub Actions take precedence over `.env`.
```sh
python -m blackout_notifier check --dry-run
```
`BILL_IDS` accepts one or more comma-separated electricity bill IDs.
Run the live checker with:
```sh
python -m blackout_notifier check
```
## Configuration
| Variable | Required | Default | Purpose |
| --- | --- | --- | --- |
| `BARGHEMAN_TOKEN` | Yes | — | SAAPA bearer token |
| `EITAAYAR_TOKEN` | Yes | — | EitaaYar bot token |
| `CHAT_ID` | Yes | — | Destination Eitaa chat |
| `BILL_IDS` | Yes | — | Comma-separated decimal bill IDs |
| `STATE_FILE` | No | `state/outages.json` | Durable notification state |
| `LOOKAHEAD_DAYS` | No | `5` | Query horizon, from 1 to 30 days |
| `REQUEST_TIMEOUT_SECONDS` | No | `15` | HTTP timeout, from 1 to 120 seconds |
| `MAX_EVENTS_PER_BILL` | No | `25` | Response safety limit, from 1 to 100 |
Shell and Gitea-provided variables take precedence over `.env`.
## Gitea deployment
This repository targets Gitea 1.25.x and a Docker-based runner advertising the
`ubuntu-latest` label. The runner needs outbound access to the Gitea instance,
`gitea.com`, PyPI, SAAPA, and EitaaYar.
1. Enable Actions in the repository settings.
2. Confirm an online runner advertises `ubuntu-latest`.
3. Add these repository Actions secrets:
`BARGHEMAN_TOKEN`, `EITAAYAR_TOKEN`, `CHAT_ID`, and `BILL_IDS`.
4. Run the test workflow manually.
5. Run **Hourly blackout check** manually once and inspect the notification and
resulting state commit.
6. Leave the `@hourly` schedule enabled.
The workflow uses fully qualified `https://gitea.com/actions/...` actions rather
than resolving actions through GitHub. Gitea 1.25 ignores workflow `permissions`
and `concurrency`, so the notifier workflow deliberately does not rely on them.
Its checkout credential must retain the default ability to push to the current
repository. Scheduled jobs should not be manually overlapped; in the rare event
of a push race, the job fails and unsaved notices may be repeated on the next run.
## Development
```sh
ruff check .
pytest
```
Tests mock both external services and never send real messages.
Historical state from the previous implementation is retained at
`archive/blackouts-1404.json` for reference only and is not imported.