Production-ready Python desktop app that monitors a user-defined list of IPs/hosts by ICMP ping at configurable intervals. Windows-first, cross-platform where possible.
- Targets: Add/edit/remove targets with required alias, host (IP/hostname), interval (s), timeout (ms), enabled.
- Live Monitor: Status per target as
<ALIAS> - OK <DETAIL>or<ALIAS> - DOWN <DETAIL>(OK/DOWN exactly as shown). - Ping: System ICMP ping (1 packet), subprocess-based; per-target interval + global concurrency limit + jitter.
- Outage state machine: First DOWN → notification with sound; subsequent DOWNs → silent notification; DOWN→UP → “reachable again” once.
- Display modes: Latency (e.g.
OK 23ms,DOWN TIMEOUT) or Status codes (200 / 408 / 503). - Tray: Minimize to tray when window is closed (configurable).
- Headless:
--headlessruns monitoring without GUI. - Run at startup: Toggle uses Windows Task Scheduler (no admin).
- Single instance: Prevents double-running.
- Daily logs:
TimedRotatingFileHandler(midnight); Log Viewer tab shows last ~200 lines.
Pingu/
├── app_main.py # Entry point, --headless, single-instance
├── requirements.txt
├── README.md
├── gui/
│ ├── main_window.py # Tabs, Start/Stop, tray, queue drain
│ ├── targets_tab.py # CRUD, import/export JSON
│ ├── monitor_tab.py # Live Monitor list
│ ├── settings_tab.py # Concurrency, jitter, display, tray, startup, log path
│ └── log_viewer.py # Last ~200 log lines
├── core/
│ ├── config.py # Load/save JSON (user app data)
│ ├── state.py # Outage state machine (UP/DOWN)
│ ├── ping.py # Subprocess ping (Windows/Linux)
│ ├── monitor.py # Asyncio scheduler, queue
│ ├── notify.py # Notifications + sound
│ └── logging_setup.py # Daily rotating logs
├── resources/
│ ├── alert.wav # Sound on first DOWN (generated by scripts/make_alert_wav.py)
│ └── icon.png # Optional tray icon
├── scripts/
│ └── make_alert_wav.py
└── tests/
├── test_state.py # State machine transitions
└── test_ping.py # Ping result parsing (mock subprocess)
# From project root
cd yourpath
# Create venv (recommended)
python -m venv .venv
.venv\Scripts\activate
# Install
pip install -r requirements.txt
# GUI
python app_main.py
# Headless (no window)
python app_main.py --headlessConfig and logs are stored under %APPDATA%\Pingu\ (config.json, logs/pingu.log, pingu.lock).
- Add target: Targets tab → Add target → set alias (e.g. "Router"), host (e.g. 192.168.1.1 or 8.8.8.8), interval 30, timeout 1000, Enabled.
- Start monitoring: Click “Start monitoring” → switch to Live Monitor tab → within ~interval seconds see rows like
Router - OK 12msorRouter - DOWN .... - Trigger DOWN: Add a target with a non-routable IP (e.g. 192.168.255.254) or disconnect network → first failure: notification with sound; subsequent failures: notification without sound.
- Reachable again: Restore network or use a reachable IP → one “reachable again” notification.
- Display mode: Settings → Display mode → “codes” → Live Monitor shows
Router - OK 200/Router - DOWN 408etc. - Logs: Check
%APPDATA%\Pingu\logs\pingu.log; Log Viewer tab shows last ~200 lines; transitions (UP→DOWN, DOWN→UP) and ping results logged. - Tray: Settings → “Minimize to tray when window is closed” → close window → app stays in tray; double-click tray to show again.
- Single instance: Start Pingu twice → second instance should exit with “Another instance already running”.
pip install pytest
pytest tests/ -vtest_state.py: Outage state machine (record_success / record_failure, first failure vs subsequent, reachable again).test_ping.py: Parsing ping output and return codes (mocked subprocess).
- PySide6: GUI (and tray notifications via
QSystemTrayIcon.showMessage). No extra notification library; sound useswinsound(Windows) orafplay/aplay(macOS/Linux).
This project is shared for viewing, personal and educational use only. All rights are reserved. Redistribution, modification, or commercial use without explicit permission is not allowed.
