- Características Principales
- Funcionalidades
- Arquitectura
- Tecnologías
- Estructura del Proyecto
- Instalación y Configuración
- Uso del Sistema
- Testing
- Sistema de Logging
- Validaciones y Seguridad
- Manejo de Excepciones
- Autores
El sistema cuenta con una interfaz de consola profesional implementada con la librería Rich:
- ✅ Tablas formateadas con colores y bordes
- ✅ Paneles estilizados para mensajes y menús
- ✅ Banner de bienvenida adaptable al tamaño de terminal
- ✅ Mensajes de estado con íconos (✓, ✗,
⚠️ , 🏠, 📱, ⚡) - ✅ Progress bars para operaciones largas
- ✅ Colores semánticos (verde=éxito, rojo=error, amarillo=advertencia)
- ✅ Variables de entorno (.env) para credenciales sensibles
- ✅ Validaciones robustas de todos los inputs del usuario
- ✅ Expresiones regulares para validación de emails
- ✅ Requisitos de contraseña configurables
- ✅ Autenticación por roles (Admin/Usuario Estándar)
- ✅ Excepciones personalizadas para cada tipo de error
Sistema profesional de registro de eventos con:
- ✅ Logs rotativos (5MB por archivo, 5 backups automáticos)
- ✅ Múltiples handlers (archivos + consola)
- ✅ Loggers especializados por componente (auth, database, devices, automations)
- ✅ Separación de logs:
app.log(general) yerrors.log(solo errores) - ✅ Formato estructurado con timestamps, niveles y contexto
- ✅ Registro automático de todas las operaciones críticas
- ✅ 285 tests automatizados (unitarios + integración)
- ✅ 71% de cobertura total de código
- ✅ 95% de cobertura en capa de dominio
- ✅ 60% de cobertura en capa DAO
- ✅ 84% de cobertura en capa de servicios
- ✅ Tests organizados por capas (domain, dao, services, integration)
- ✅ Configuración pytest profesional con fixtures reutilizables
- ✅ Reportes HTML de cobertura automáticos
- ✅ 100% de tests pasando sin fallos
- Registro de nuevos usuarios con validaciones
- Inicio de sesión seguro
- Consulta de datos personales
- Visualización de dispositivos por hogar
- Información completa de cada dispositivo (tipo, estado, ubicación)
- Organización por hogares y ubicaciones
- Visualización de automatizaciones por hogar
- Información completa de cada automatiazción
- Crear nuevos dispositivos
- Listar todos los dispositivos del sistema
- Actualizar información y estados
- Eliminar dispositivos
- Cambiar estados de dispositivos
- Crear automatizaciones personalizadas
- Visualizar automatizaciones por hogar
- Activar/Desactivar automatizaciones
- Actualizar automatizaciones existentes
- Eliminar automatizaciones
- Cambiar roles de usuarios (admin ↔ estándar)
- Visualizar información de usuarios
┌─────────────────────────────────────┐
│ main.py (Orquestación) │ ← Punto de entrada
└───────────────┬─────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ UI LAYER (rich_console_ui.py) │ ← Presentación (Rich UI)
│ └── rich_utils.py │
│ └── rich_utils.py │
└───────────────┬─────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ SERVICE LAYER │ ← Lógica de Negocio
│ ├── auth_service.py │ • Validaciones
│ ├── device_service.py │ • Reglas de negocio
│ └── automation_service.py │ • Orquestación
└───────────────┬─────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ DAO LAYER (Acceso a Datos) │ ← Persistencia
│ ├── user_dao.py │ • CRUD operations
│ ├── device_dao.py │ • Queries
│ ├── automation_dao.py │ • Transacciones
│ └── ... (más DAOs) │
└───────────────┬─────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ DOMAIN LAYER (Entidades) │ ← Modelos de Dominio
│ ├── user.py │ • Entidades
│ ├── device.py │ • Lógica de dominio
│ ├── automation.py │ • Encapsulación
│ └── ... (más entidades) │
└───────────────┬─────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ UTILS LAYER │ ← Utilidades
│ ├── logger.py (Logging) │ • Logging
│ ├── validators.py (Validaciones) │ • Validaciones
│ └── exceptions.py (Excepciones) │ • Excepciones
└───────────────┬─────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ DATABASE LAYER │ ← Gestión de BD
│ ├── setup_database.py │ • Setup automatizado
│ ├── config.py │ • Configuración
│ ├── schema/ │ • DDL
│ └── seeds/ │ • Datos iniciales
└───────────────┬─────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ CONNECTION LAYER │ ← Conexión a BD
│ └── db_connection.py (Singleton) │ • Singleton pattern
└───────────────┬─────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ MySQL Database (BD) │ ← Almacenamiento
└─────────────────────────────────────┘
- Layered Architecture - Separación clara de responsabilidades
- Service Layer Pattern - Lógica de negocio encapsulada
- DAO Pattern - Acceso a datos desacoplado del dominio
- Singleton Pattern - Única instancia de conexión a BD
- Dependency Injection - Inversión de control manual
- Repository Pattern - Abstracción de colecciones de datos
- Python 3.11+ - Lenguaje principal con type hints
- MySQL 8.0 - Base de datos relacional
mysql-connector-python==8.0.33 # Conexión a MySQL
rich==13.7.0 # UI avanzada en consola
python-dotenv==1.0.0 # Gestión de variables de entorno
pytest==7.4.3 # Framework de testing
pytest-cov==4.1.0 # Cobertura de código
SmartHome/
│
├── 📁 database/ # Gestión de Base de Datos
│ ├── 📁 schema/ # DDL - Estructura
│ │ ├── create_tables.sql # Definición de tablas
│ │ └── __init__.py
│ ├── 📁 seeds/ # DML - Datos iniciales
│ │ ├── 01_roles.sql # Roles del sistema
│ │ ├── 02_states.sql # Estados de dispositivos
│ │ ├── 03_locations.sql # Ubicaciones
│ │ ├── ...(más seeds)
│ │ └── __init__.py
│ ├── config.py # Configuración de BD
│ ├── setup_database.py # Script de setup
│ └── __init__.py
│
├── 📁 scripts/ # Scripts de automatización
│ ├── init_db.sh # Inicialización (Linux/Mac)
│ └── init_db.bat # Inicialización (Windows)
│
├── 📁 ui/ # Capa de Presentación
│ ├── rich_console_ui.py # UI con Rich (principal)
│ ├── rich_utils.py # Utilidades de Rich
│ └── __init__.py
│
├── 📁 services/ # Lógica de Negocio
│ ├── auth_service.py
│ ├── device_service.py
│ ├── automation_service.py
│ └── __init__.py
│
├── 📁 dao/ # Acceso a Datos
│ ├── user_dao.py
│ ├── device_dao.py
│ ├── automation_dao.py
│ └── ... (más DAOs)
│
├── 📁 dominio/ # Entidades de Dominio
│ ├── user.py
│ ├── device.py
│ ├── automation.py
│ └── ... (más entidades)
│
├── 📁 interfaces/ # Interfaces DAO
│ ├── i_dao.py
│ ├── i_user_dao.py
│ └── i_device_dao.py
│
├── 📁 conn/ # Conexión a BD
│ ├── db_connection.py
│ └── __init__.py
│
├── 📁 utils/ # Utilidades del Sistema
│ ├── logger.py
│ ├── validators.py
│ ├── exceptions.py
│ └── __init__.py
│
├── 📁 tests/ # Tests (241 tests)
│ ├── 📁 test_domain/
│ ├── 📁 test_services/
│ ├── 📁 test_dao/
│ ├── 📁 test_integration/
│ ├── conftest.py
│ └── __init__.py
│
├── 📁 logs/ # Archivos de Log
│ ├── app.log
│ └── errors.log
│
├── .env # Variables de entorno (gitignored)
├── .env.example # Template de configuración
├── .gitignore
├── pytest.ini
├── requirements.txt
├── main.py
└── README.md
- Python 3.11 o superior
- MySQL 8.0 o superior
- pip (gestor de paquetes de Python)
- Git
git clone https://github.com/tu-usuario/SmartHome.git
cd SmartHome# Windows
python -m venv venv
venv\Scripts\activate
# Linux/Mac
python3 -m venv venv
source venv/bin/activatepip install -r requirements.txtSe instalarán:
- ✅
mysql-connector-python(8.0.33) - ✅
rich(13.7.0) - ✅
python-dotenv(1.0.0) - ✅
pytest(7.4.3) - ✅
pytest-cov(4.1.0)
a) Copiar el template:
# Windows
copy .env.example .env
# Linux/Mac
cp .env.example .envb) Editar .env con tus credenciales:
# Database Configuration
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=smarthome
DB_USER=root
DB_PASSWORD=tu_password_aqui # ⚠️ CAMBIAR ESTO.env contiene información sensible. NUNCA lo subas a Git.
El sistema incluye un módulo completo de gestión de base de datos con scripts automáticos.
database/
├── schema/
│ └── create_tables.sql # DDL - Define estructura
├── seeds/
│ ├── 01_roles.sql # Roles (admin, standard)
│ ├── 02_states.sql # Estados de dispositivos
│ ├── 03_locations.sql # Ubicaciones
│ ├── 04_device_types.sql # Tipos de dispositivos
│ ├── 05_homes.sql # Hogares de ejemplo
│ ├── 06_users.sql # Usuarios de prueba
│ ├── 07_user_homes.sql # Relaciones
│ ├── 08_devices.sql # Dispositivos de ejemplo
│ ├── 09_automations.sql # Automatizaciones
│ ├── 10_device_automations.sql
│ └── 11_events.sql # Eventos del sistema
├── config.py # Configuración centralizada
└── setup_database.py # Script de setup automático
Esta es la forma más rápida y sencilla de configurar todo el sistema.
# Ejecutar el script de inicialización
scripts\init_db.bat# Dar permisos de ejecución
chmod +x scripts/init_db.sh
# Ejecutar el script
./scripts/init_db.sh# Ejecutar directamente el script Python
python database/setup_database.py --allEste comando hace:
- ✅ Crea la base de datos
smarthome - ✅ Crea todas las tablas (schema)
- ✅ Inserta datos iniciales (seeds)
- ✅ Verifica la configuración
Si prefieres ejecutar cada paso manualmente:
python database/setup_database.py --create-dbSalida esperada:
python database/setup_database.py --schemaSalida esperada:
python database/setup_database.py --seedSalida esperada:
python database/setup_database.py --verifySalida esperada:
Si necesitas empezar de cero durante el desarrollo:
python database/setup_database.py --reset --all⚠️ ¿Está seguro de ELIMINAR la base de datos? (escriba 'SI'): SI
Reset Ok
# Ver todas las opciones disponibles
python database/setup_database.py --help
# Comandos individuales
python database/setup_database.py --create-db # Solo crear BD
python database/setup_database.py --schema # Solo crear tablas
python database/setup_database.py --seed # Solo insertar datos
python database/setup_database.py --verify # Solo verificar
# Comandos combinados
python database/setup_database.py --all # Todo: crear + schema + seed + verify
python database/setup_database.py --reset --all # Resetear y recrear todoEdita el archivo database/config.py:
DB_CONFIG: Dict[str, str] = {
'host': os.getenv('DB_HOST', 'localhost'),
'user': os.getenv('DB_USER', 'root'),
'password': os.getenv('DB_PASSWORD'),
'port': int(os.getenv('DB_PORT', '3306'))
}O mejor aún, usa variables de entorno en .env:
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=mi_password_seguroDespués de configurar todo, ejecuta:
python main.pySi ves el menú principal con la interfaz Rich, ¡todo está funcionando! 🎉
El sistema incluye datos de ejemplo listos para usar:
Email: [email protected]
Password: admin123
Email: [email protected]
Password: pass123
- ✅ 2 roles (admin, standard)
- ✅ 11 usuarios de prueba
- ✅ 10 hogares de ejemplo
- ✅ 25 dispositivos configurados
- ✅ 10 automatizaciones
- ✅ 10 estados de dispositivos
- ✅ 12 ubicaciones
- ✅ 12 tipos de dispositivos
- ✅ 15 eventos del sistema
Solución: Verifica que la contraseña en database/config.py sea correcta.
'password': os.getenv('DB_PASSWORD')Solución: Verifica que MySQL esté ejecutándose:
# Windows
net start MySQL80
# Linux/Mac
sudo service mysql startSolución: Ejecuta el comando de creación:
python database/setup_database.py --create-dbSolución: Ejecuta el comando de schema:
python database/setup_database.py --schemaPara más detalles sobre la estructura de la base de datos, consulta:
- 📄
database/schema/create_tables.sql- Definición de tablas - 📄
database/seeds/- Datos de ejemplo - 📄
database/setup_database.py- Código del script de setup
python main.pyAl ejecutar, verás una interfaz moderna con Rich:
Email: [email protected]
Password: admin123
Email: [email protected]
Password: pass123
Validaciones aplicadas:
- ✅ Email con formato correcto
- ✅ Contraseña con longitud mínima
- ✅ Nombre sin caracteres especiales
- ✅ Email único (no duplicados)
1. Ver datos personales
2. Ver Dispositivos
→ Visualiza dispositivos organizados por hogar
→ Información completa de cada dispositivo
3. Visualizar Automatizaciones
→ Ver automatizaciones por hogar con Descripción y Estado
1. Gestión de Dispositivos (CRUD)
2. Gestionar Automatizaciones (CRUD)
→ CRUD de automatizaciones
- Crear automatizaciones, ver, actualizar, activar, desactivar, eliminar
3. Cambiar rol de usuario
→ Ingresar email del usuario
→ Seleccionar nuevo rol (Admin/Estándar)
4. Cerrar sesión
tests/
├── 📁 test_domain/ # 78 tests - Tests de entidades del dominio
│ ├── test_user.py # 18 tests - Validaciones, autenticación
│ ├── test_device.py # 15 tests - Dispositivos inteligentes
│ ├── test_automation.py # 17 tests - Automatizaciones
│ ├── test_role.py # 7 tests - Roles del sistema
│ ├── test_state.py # 8 tests - Estados de dispositivos
│ ├── test_home.py # 10 tests - Hogares
│ ├── test_event.py # 16 tests - Eventos del sistema
│ ├── test_location.py # 9 tests - Ubicaciones
│ └── test_device_type.py # 9 tests - Tipos de dispositivos
│
├── 📁 test_dao/ # 67 tests - Tests de acceso a datos
│ ├── test_user_dao.py # 15 tests - CRUD de usuarios
│ ├── test_device_dao.py # 12 tests - CRUD de dispositivos
│ ├── test_automation_dao.py # 12 tests - CRUD de automatizaciones
│ ├── test_home_dao.py # 9 tests - CRUD de hogares
│ ├── test_role_dao.py # 9 tests - CRUD de roles
│ ├── test_state_dao.py # 9 tests - CRUD de estados
│ └── test_user_dao.py # 15 tests - Validaciones y autenticación
│
├── 📁 test_services/ # 112 tests - Tests de lógica de negocio
│ ├── test_auth_service.py # 26 tests - Autenticación
│ ├── test_device_service.py # 41 tests - Gestión de dispositivos
│ └── test_automation_service.py # 45 tests - Gestión de automatizaciones
│
├── 📁 test_integration/ # 28 tests - Tests de integración
│ ├── test_basic_integration.py # 4 tests - Tests básicos
│ ├── test_device_flow.py # 8 tests - Flujos de dispositivos
│ ├── test_automation_flow.py # 6 tests - Flujos de automatizaciones
│ └── test_home_management_flow.py # 10 tests - Gestión de hogares
│
├── conftest.py # Configuración y fixtures globales
├── __init__.py
└── pytest.ini # Configuración de pytest
Total: 285 tests distribuidos en 4 capas de testing
# Ejecutar todos los tests
pytest
# Tests con output verboso
pytest -v
# Tests con output detallado
pytest -vv
# Detener en el primer fallo
pytest -x# Solo tests de dominio
pytest tests/test_domain/
# Solo tests de servicios
pytest tests/test_services/
# Solo tests de DAO
pytest tests/test_dao/
# Solo tests de integración
pytest tests/test_integration/# Un archivo específico
pytest tests/test_domain/test_user.py
# Una clase específica
pytest tests/test_domain/test_user.py::TestUser
# Un test específico
pytest tests/test_domain/test_user.py::TestUser::test_crear_user_administrador
# Tests que contengan "admin" en el nombre
pytest -k "admin"# Cobertura de todas las capas principales
pytest --cov=dominio --cov=dao --cov=services
# Con reporte en terminal
pytest --cov=dominio --cov=dao --cov=services --cov-report=term
# Con líneas faltantes
pytest --cov=dominio --cov=dao --cov=services --cov-report=term-missing# Generar reporte HTML completo
pytest --cov=dominio --cov=dao --cov=services --cov-report=html
# El reporte se genera en: htmlcov/index.html
# Abrirlo con:
start htmlcov/index.html # Windows
open htmlcov/index.html # Mac
xdg-open htmlcov/index.html # Linux# Solo dominio
pytest --cov=dominio --cov-report=term-missing tests/test_domain/
# Solo servicios
pytest --cov=services --cov-report=term-missing tests/test_services/
# Solo DAO
pytest --cov=dao --cov-report=term-missing tests/test_dao/pytest --cov=dominio --cov=dao --cov=services --cov-report=xmlpytest --cov=dominio --cov=dao --cov=services \
--cov-report=html \
--cov-report=xml \
--cov-report=term-missing# Solo tests rápidos
pytest -m "not slow"
# Solo tests de integración
pytest -m integrationEl proyecto usa pytest.ini para configuración centralizada:
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
# Opciones de cobertura
addopts =
--strict-markers
--cov-fail-under=40
--cov-report=term-missing
# Marcadores personalizados
markers =
slow: Tests que tardan más tiempo
integration: Tests de integración
unit: Tests unitariosEl proyecto cuenta con fixtures reutilizables en conftest.py:
# Fixtures de DAO
@pytest.fixture
def user_dao() -> UserDAO
@pytest.fixture
def device_dao() -> DeviceDAO
@pytest.fixture
def automation_dao() -> AutomationDAO
# Fixtures de entidades de prueba
@pytest.fixture
def sample_user() -> User
@pytest.fixture
def sample_device() -> Device
# Fixtures de limpieza
@pytest.fixture
def cleanup_test_data()pytest --cov=dominio --cov=dao --cov=services --cov-report=term-missingSalida esperada:
===================================================================== test session starts ======================================================================
collected 285 items
tests/test_domain/test_user.py .................. [ 6%]
tests/test_domain/test_device.py ............... [12%]
tests/test_dao/test_user_dao.py ............... [18%]
...
---------- coverage: platform win32, python 3.13.9-final-0 -----------
Name Stmts Miss Cover Missing
--------------------------------------------------------------
dominio/user.py 31 0 100%
dominio/device.py 44 2 95% 114, 119
dao/user_dao.py 99 22 78% 36-39, 60-63
services/auth_service.py 82 6 93% 86-88
--------------------------------------------------------------
TOTAL 1568 461 71%
Required test coverage of 40% reached. Total coverage: 70.60%
===================================================================== 285 passed in 7.82s ======================================================================
pytest --cov=dominio --cov=dao --cov=services --cov-report=html
start htmlcov/index.htmlEl reporte HTML incluye:
- ✅ Cobertura por archivo con colores
- ✅ Líneas cubiertas/no cubiertas resaltadas
- ✅ Estadísticas detalladas por módulo
- ✅ Navegación interactiva
# Tests de dominio (más rápidos)
pytest tests/test_domain/ -v
# Output:
# tests/test_domain/test_user.py::test_user_basico PASSED [ 5%]
# tests/test_domain/test_user.py::test_login_exitoso PASSED [10%]
# ...
# ===================== 78 passed in 0.42s =====================# Con print statements visibles
pytest tests/test_services/test_auth_service.py -s
# Con debugger
pytest tests/test_services/test_auth_service.py --pdb# ❌ Mal
def test1():
...
# ✅ Bien
def test_crear_usuario_exitoso():
"""Test: Crear usuario con datos válidos debe retornar éxito."""
...def test_validar_credenciales_correctas():
# Arrange
role = Role(1, "Admin")
user = User("[email protected]", "pass123", "Test", role)
# Act
resultado = user.validate_credentials("[email protected]", "pass123")
# Assert
assert resultado is True@pytest.fixture
def sample_user():
role = Role(2, "Standard")
return User("[email protected]", "pass123", "Test User", role)
def test_cambiar_nombre_user(sample_user):
# Act
sample_user.name = "Nuevo Nombre"
# Assert
assert sample_user.name == "Nuevo Nombre"- Cada test puede ejecutarse solo
- No dependen de orden de ejecución
- Limpian sus datos después de ejecutar
| Objetivo | Estado | Cobertura Actual |
|---|---|---|
| Mínimo Requerido | ✅ Superado | 40% → 71% |
| Dominio | ✅ Alcanzado | 95% |
| Servicios | ✅ Alcanzado | 84% |
| DAO | ✅ Alcanzado | 60% |
| Próxima Meta | 🎯 En progreso | 75-80% |
Para más detalles sobre testing en el proyecto:
- 📄
tests/conftest.py- Configuración global y fixtures - 📄
pytest.ini- Configuración de pytest - 📄
tests/test_domain/- Ejemplos de tests unitarios - 📄
tests/test_integration/- Ejemplos de tests de integración
Sistema profesional de logs con rotación automática.
logs/
├── app.log # Logs generales (INFO+)
├── errors.log # Solo errores (ERROR+)
└── *.log.1-5 # Backups automáticos
Validaciones robustas en todas las entradas:
- ✅ Email con formato correcto
- ✅ Contraseñas seguras
- ✅ Nombres sin caracteres especiales
- ✅ IDs positivos
- ✅ Descripciones con longitud mínima
Excepciones personalizadas por tipo de error:
ValidationException- Errores de validaciónDatabaseException- Errores de BDEntityNotFoundException- Entidad no encontradaDuplicateEntityException- DuplicadosAuthenticationException- Errores de autenticación
Fernando Agustín Moyano
Última actualización: Diciembre 2025
Versión: 1.0.0























