Skip to content

EHrekov/voltage-bot

Repository files navigation

⚡ Voltage Bot

A Telegram bot that monitors mains voltage through a Tuya smart plug and reports it to a channel/group: a live pinned status message, a 24-hour chart with day/night tariff bands and power-outage shading, and edge-triggered alerts for low/high voltage.

Built for an area with an unstable grid and scheduled blackouts — the bot answers two questions at a glance: what's the voltage right now? and how long was there no power in the last 24 hours?

Voltage chart example

Features

  • Polls a Tuya plug locally over LAN (tinytuya, no cloud dependency).
  • Single self-updating pinned status message + pinned chart (edited in place, not re-posted).
  • Outage tracking with a flap debounce: one missed poll is a gap, not a blackout — only a sustained loss counts as downtime.
  • Voltage chart: normal band, low/high markers, day/night tariff strip, shaded outage periods.
  • Low/high voltage alerts that fire once per transition, not every cycle.
  • Pluggable storage: zero-config SQLite by default, PostgreSQL via a single env var.
  • Structured logging, graceful shutdown, bounded retries with backoff.

Hardware

Any Tuya/Smart Life plug that exposes a voltage data point (DPS) over the local API. You need the device's DEVICE_ID, LOCAL_KEY, and LAN IP (obtainable with python -m tinytuya wizard). The default decoding assumes voltage is on DPS 23 in decivolts (raw / 10); override via env if your device differs.

Architecture

tuya_client  ─► monitor ─► storage (SQLAlchemy: SQLite | PostgreSQL)
                  │  ▲
                  │  └── history (pure logic: outage, formatting, segments)
                  ├──► chart (matplotlib)
                  └──► telegram_client (pinned status + chart, alerts)
config (.env) ─► everything | logging_setup ─► console + rotating file

The interesting logic (outage duration, series segmentation, formatting) lives in history.py as pure functions with no I/O — easy to reason about and unit-test in isolation.

Project structure

src/voltage_bot/
  config.py          env → validated Settings
  logging_setup.py   console + rotating file
  tuya_client.py     tinytuya wrapper (timeout + retry)
  models.py          SQLAlchemy models
  storage.py         repositories + one-time history.json import
  history.py         pure logic (testable)
  chart.py           matplotlib rendering
  telegram_client.py pinned message / chart / alerts
  monitor.py         main loop, debounce, alert state machine
scripts/run_termux.sh  supervised restart loop for Android/Termux
docker-compose.yml     optional PostgreSQL service

Setup

python -m venv .venv
. .venv/bin/activate            # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env            # then edit .env
python -m voltage_bot

Configuration

All configuration is via environment variables (loaded from .env). BOT_TOKEN, TUYA_DEVICE_ID, TUYA_LOCAL_KEY, TUYA_IP are required, plus at least one of CHANNEL_ID / GROUP_ID. See .env.example for the full annotated list (intervals, voltage thresholds, tariff hours, timezone, log level, DATABASE_URL).

Deployment

  • Termux / Android (the original target): bash scripts/run_termux.sh — supervised restart loop with wake-lock and exponential backoff.
  • Server (systemd): run python -m voltage_bot under a unit with Restart=on-failure. The process handles SIGTERM cleanly.

Storage: SQLite vs PostgreSQL

The storage layer is a thin SQLAlchemy wrapper; the backend is selected entirely by DATABASE_URL:

  • SQLite (default) — no DATABASE_URL set. A single transactional file, zero configuration. This is the recommended mode for the real deployment target (Termux on an Android phone), where running a database server is impractical (resources, battery, no service manager). SQLite already gives transactional writes, which removes the corrupt-file failure mode of the old plain-JSON approach.
  • PostgreSQL (optional) — set DATABASE_URL=postgresql+psycopg2://voltage:voltage@localhost:5432/voltage and docker compose up -d. Same code path, timestamptz storage, indexed time queries — the "server / showcase" deployment.

An existing legacy history.json is imported automatically once, on first run, if the database is empty.

Security

  1. Telegram: open @BotFather/revoke → use the new BOT_TOKEN.
  2. Tuya: re-pair the device in the Smart Life app (re-pairing rotates the local key) or regenerate it in the Tuya IoT console; update TUYA_LOCAL_KEY.
  3. Put the new values only in a local .env — never commit it.
  4. .gitignore excludes .env, *.db, and the legacy state.json / history.json. Add it before git init so secrets/data never enter git history.

License

MIT — see LICENSE.

About

Telegram bot that monitors mains voltage via a Tuya smart plug — live charts, outage tracking, alerts. Python, SQLAlchemy, SQLite/PostgreSQL.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors