Actualiza barra de estado y README

This commit is contained in:
marcos 2025-12-05 22:21:17 +01:00
parent 9f7d1e247c
commit 2d62bf2530
2 changed files with 45 additions and 84 deletions

View File

@ -1,67 +1,68 @@
# Proyecto Global Dashboard
Panel de control escrito en Python 3.14 + Tkinter que reúne las prácticas solicitadas (scraping, monitorización, alarmas, notas, música y más) con una estética cuidada y paneles diferenciados.
Laboratorio interactivo construido con Python 3.13 + Tkinter. Reúne scraping, monitorización, chat TCP, alarmas, reproductor musical y utilidades varias en una única aplicación de escritorio.
## 🚀 Características principales
## 🎬 Demo en video
- **Dashboard modular**: panel izquierdo con accesos rápidos (scraping, clima de Jávea, Camellos, copias de seguridad, etc.), cuaderno central por pestañas y panel derecho con chat y listado de alumnos.
- **Scraping integrado**: workflows para Wallapop y scraping genérico con popups dedicados y avisos de estado.
- **Monitor de sistema**: gráficas PSUtil actualizadas mediante `after` de Tk, evitando bloqueos y mostrando CPU/RAM/Net de forma fluida.
- **Bloc de notas y backups reales**: edición rápida de texto con copias automáticas a una carpeta de respaldo mostrando progreso.
- **Widgets temáticos**: reproductor musical con tarjetas, gestor de alarmas rediseñado y popup meteorológico (OpenWeather, coordenadas de Jávea) cacheado para reducir llamadas.
- **Servidor de mensajería**: `servidor.py` permite broadcast TCP para pruebas de chat local.
- YouTube: https://youtu.be/HgJwU_HagD8
## 🚀 Características clave
- **Layout triple panel**: accesos rápidos a la izquierda, notebook central con pestañas temáticas y panel derecho para chat y utilidades.
- **Scraping Wallapop + genérico**: asistentes emergentes, validaciones y guardado de resultados.
- **Monitor de sistema**: gráficas en vivo de CPU, RAM e hilos gracias a psutil y matplotlib embebido.
- **Productividad integrada**: bloc de notas, gestor de alarmas, reproductor musical con pygame y lanzadores de procesos.
- **Popup meteorológico**: consulta OpenWeather para Jávea con caché y resumen formateado.
- **Servidor TCP incluido**: `servidor.py` permite pruebas de chat broadcast desde la propia app.
## ⚙️ Requisitos
- Python 3.8 o superior (desarrollado con 3.14)
- Python 3.8 o superior (desarrollado en 3.13)
- Dependencias listadas en `requirements.txt`
```sh
pip install -r requirements.txt
```
## ▶️ Puesta en marcha rápida
## ▶️ Puesta en marcha
1. (Opcional) Arranca el servidor de mensajería:
```sh
python3 servidor.py
```
Verás `Servidor escuchando en 0.0.0.0:3333` en consola.
2. Lanza la interfaz gráfica:
```sh
python3 app.py
```
3. Desde el panel derecho ajusta host/puerto y pulsa `Conectar` para chatear. Explora el resto de pestañas (scraping, notas, alarmas, música, clima) desde los botones laterales.
1. (Opcional) Inicia el servidor de chat:
```sh
python3 servidor.py
```
2. Lanza el panel principal:
```sh
python3 app.py
```
3. Usa el panel izquierdo para abrir scraping, notas, alarmas o el popup del clima; el panel derecho gestiona el chat y el reproductor.
## 🧱 Arquitectura de carpetas
## 🧱 Estructura del proyecto
```
app.py # GUI principal y lógica de scraping, clima, monitorización, alarmas...
servidor.py # Servidor TCP broadcast para el chat de pruebas
requirements.txt # Dependencias del proyecto
README.md # Este archivo
app.py # GUI principal y lógica de negocio
servidor.py # Servidor TCP broadcast para el chat
requirements.txt # Lista de dependencias
README.md # Documentación
```
## 🛠️ Funcionalidades destacadas
## 🛠️ Flujos destacados
- **Scraping Wallapop y genérico**: ventanas emergentes, peticiones HTTP con Requests + BeautifulSoup, mensajes de éxito/error.
- **Weather popup “API Tiempo”**: botón dedicado que consulta OpenWeather (con clave fallback), muestra iconos, temperaturas y caché temporal.
- **Copias de seguridad guiadas**: barra de progreso y notificaciones durante la duplicación de directorios.
- **Editor y bloc de notas**: pestañas separadas para notas rápidas y bloc organizado.
- **Gestor de alarmas**: UI modernizada con tarjetas, botones primarios y feedback visual.
- **Música y utilidades**: reproductor basado en pygame y accesos a herramientas externas (“Camellos”, lanzadores, etc.).
- **Scraping**: workers en segundo plano con colas y retroalimentación visual en la pestaña de resultados.
- **Copias de seguridad**: selección interactiva de carpetas y reporte final con totales copiados/omitidos.
- **Gestor de alarmas**: creación, cancelación y popups dedicados con recordatorio sonoro.
- **Panel de recursos**: mezcla de gráficas lineales, de área y de barras para CPU/RAM/hilos.
- **Popup “API Tiempo”**: resumen meteorológico en ventana modal con refresco bajo demanda.
## 🌤️ Servicios externos
## ⚙️ Configuración opcional
- **OpenWeatherMap**: usado para el popup del clima (coordenadas de Jávea). Define `OPENWEATHER_API_KEY` en el entorno para usar tu propia clave.
- **Wallapop / sitios objetivo**: las rutinas de scraping respetan temporizadores y headers básicos; ajusta las URLs o parámetros dentro de `app.py` para nuevos escenarios.
- `OPENWEATHER_API_KEY` / `OPENWEATHER_FALLBACK_API_KEY`: claves para OpenWeather.
- Variables `WALLAPOP_*`: encabezados y parámetros usados por el scraper.
- Ajusta el host/puerto del chat en el panel derecho o modificando `SERVER_HOST_DEFAULT` y `SERVER_PORT_DEFAULT` en `app.py`.
## 📌 Próximos pasos sugeridos
1. Añadir pruebas unitarias para la lógica no gráfica (scraping, backups, parsers).
2. Persistir chats y notas en SQLite para mantener el historial.
3. Integrar reproductor completo dentro de la app (playlist, carátulas).
1. Añadir almacenamiento persistente (SQLite) para chats y notas.
2. Incorporar pruebas unitarias para scraping y rutinas de backup.
3. Extender el reproductor musical con colas y visualizaciones.
---
¿Necesitas extender alguna funcionalidad? Abre un issue o comenta qué módulo quieres potenciar (más scraping, dashboards adicionales, automatización de backups, etc.).
¿Quieres ampliar alguna sección (scraping extra, nuevos paneles, automatización de tareas)? Adelante, la base está lista para seguir creciendo.

46
app.py
View File

@ -68,7 +68,6 @@ OPENWEATHER_FALLBACK_API_KEY = os.environ.get(
).strip()
_OPENWEATHER_ENV_KEY = os.environ.get('OPENWEATHER_API_KEY', '').strip()
OPENWEATHER_API_KEY = _OPENWEATHER_ENV_KEY or OPENWEATHER_FALLBACK_API_KEY
OPENWEATHER_CITY = os.environ.get('OPENWEATHER_CITY', 'Madrid,ES')
JAVEA_LATITUDE = 38.789166
JAVEA_LONGITUDE = 0.163055
@ -232,16 +231,12 @@ class DashboardApp(tk.Tk):
self.game_camel_count = 3
self.game_speed_factor = 1.0
self.music_temp_file: str | None = None
self.weather_city = OPENWEATHER_CITY
self.weather_api_key = OPENWEATHER_API_KEY
self.results_area: tk.Frame | None = None
self.results_title: tk.Label | None = None
self.scraping_popup: tk.Toplevel | None = None
self.simple_scraping_popup: tk.Toplevel | None = None
self.weather_popup: tk.Toplevel | None = None
self._last_weather_data: dict[str, Any] | None = None
self._last_weather_error: str | None = None
self._last_weather_timestamp: datetime.datetime | None = None
self.chart_canvas = None
self.ax_cpu = None
self.ax_mem = None
@ -263,8 +258,8 @@ class DashboardApp(tk.Tk):
self._build_center_panel()
self._build_right_panel()
self._build_status_bar()
self._update_clock()
if psutil:
self.after(1000, self._update_traffic)
try:
@ -275,8 +270,6 @@ class DashboardApp(tk.Tk):
threading.Thread(target=self._chat_loop, daemon=True).start()
self.after(100, self._process_scraping_queue)
self.after(1000, self._refresh_alarms_loop)
if REQUESTS_AVAILABLE and self.weather_api_key:
self.after(2000, self._update_weather)
# ------------------------ UI ------------------------
def _maximize_with_borders(self) -> None:
@ -765,7 +758,7 @@ class DashboardApp(tk.Tk):
def _build_status_bar(self) -> None:
status = tk.Frame(self, bg='#f1f1f1', bd=2, relief='ridge')
status.grid(row=2, column=0, columnspan=3, sticky='ew')
for idx in range(4):
for idx in range(3):
status.columnconfigure(idx, weight=1)
tk.Label(status, text='Correos sin leer', font=('Arial', 11, 'bold'), bg='#f1f1f1').grid(row=0, column=0, padx=16, pady=6, sticky='w')
@ -778,11 +771,8 @@ class DashboardApp(tk.Tk):
)
self.traffic_label.grid(row=0, column=1, padx=16, pady=6)
self.weather_label = tk.Label(status, text='Clima: configure API', font=('Arial', 11, 'bold'), bg='#f1f1f1')
self.weather_label.grid(row=0, column=2, padx=16, pady=6, sticky='n')
self.clock_label = tk.Label(status, text='--:--:--', font=('Arial', 12, 'bold'), bg='#f1f1f1')
self.clock_label.grid(row=0, column=3, padx=16, pady=6, sticky='e')
self.clock_label.grid(row=0, column=2, padx=16, pady=6, sticky='e')
# ------------------------ acciones ------------------------
def _open_web(self, url: str) -> None:
@ -2020,36 +2010,6 @@ class DashboardApp(tk.Tk):
def _fetch_javea_weather(self) -> dict[str, Any]:
return self._fetch_weather_by_coordinates(JAVEA_LATITUDE, JAVEA_LONGITUDE)
def _update_weather(self) -> None:
if not self._running:
return
try:
data = self._fetch_weather_data(self.weather_city)
temp = data.get('main', {}).get('temp')
desc = data.get('weather', [{}])[0].get('description', '').capitalize()
city = data.get('name') or self.weather_city
if temp is None:
raise ValueError('Respuesta sin temperatura')
self.weather_label.config(text=f'{city}: {temp:.1f}°C, {desc}')
self._last_weather_data = data
self._last_weather_error = None
self._last_weather_timestamp = datetime.datetime.now()
except RuntimeError as exc:
self.weather_label.config(text='Clima: configure API')
self._log(f'Clima: {exc}')
self._last_weather_data = None
self._last_weather_error = str(exc)
self._last_weather_timestamp = datetime.datetime.now()
except Exception as exc:
self.weather_label.config(text='Clima: N/D')
self._log(f'Clima: {exc}')
self._last_weather_data = None
self._last_weather_error = str(exc)
self._last_weather_timestamp = datetime.datetime.now()
finally:
if self._running:
self.after(300000, self._update_weather)
# ------------------------ chat ------------------------
def _connect_chat(self) -> None:
host = self.host_entry.get().strip() or SERVER_HOST_DEFAULT