Autor: vejeta

  • Debian GNU/Linux en MacBook Pro 2013. Por 140€ en 3-5 años más de vida para mi MacBook Pro 2013

    Debian GNU/Linux en MacBook Pro 2013. Por 140€ en 3-5 años más de vida para mi MacBook Pro 2013

    Un MacBook Pro de 11 años puede seguir siendo útil en 2025, pero requiere cuidados específicos y decisiones técnicas informadas. Esta es la historia de cómo convertí 140€ en varios años más de vida útil, con lecciones técnicas importantes sobre las diferencias entre generaciones de hardware Apple.

    El problema: batería hinchada y decisión crítica

    Mi MacBook Pro 11,1 (Late 2013) tenía la bateria inutil desde hace años, pero el problema real se hizo evidente al decidir abrirlo para inspección: batería visiblemente hinchada.

    La batería había expandido lo suficiente para deformar el chasis interno, un problema común en MacBooks de esta generación después de años de uso. Este descubrimiento cambió completamente el diagnóstico de «batería gastada» a «riesgo de seguridad que requiere acción inmediata».

    Decisión crítica: Detener el uso inmediatamente hasta resolver el problema. Una batería hinchada no es solo un inconveniente, es un riesgo de seguridad real que puede dañar componentes internos o crear situaciones peligrosas.

    Análisis económico: ¿renovar o reemplazar?

    Alternativas consideradas:

    • ThinkPad E14 nuevo: ~350€
    • Renovación MacBook 2013: ~140€
    • Mantener como equipo fijo: 0€ (pero limitado)

    Factores decisivos:

    • Uso previsto: equipo secundario para desarrollo ocasional
    • Portabilidad necesaria: sí, para trabajar en diferentes ubicaciones
    • Presupuesto disponible: preferencia por inversión mínima efectiva

    La renovación ofreció la mejor relación costo-beneficio para mis necesidades específicas.

    Proceso de renovación técnica

    Reemplazo de batería: investigación y compra

    Opción elegida: Batería iFixit (119€ + herramientas)

    Alternativas descartadas:

    • Baterías genéricas de AliExpress: ~40€ (calidad dudosa, historiales de hinchazón temprana)
    • Servicio técnico oficial: >200€ (precio prohibitivo para equipo de 11 años)

    Instalación: Siguiendo la guía iFixit paso a paso, incluyendo limpieza interna completa con aire comprimido y alcohol isopropílico para remover años de acumulación de polvo.

    Resultado: Batería con 104.2% de capacidad (6669 mAh vs 6400 mAh de diseño), superando las especificaciones originales gracias a mejoras en la tecnología de celdas Li-ion.

    Cargador de repuesto

    Problema del cargador original: Conector T-pin excesivamente caliente tras años de uso, indicando posible degradación de contactos internos.

    Solución: Cargador compatible Ywcking (20€) como reemplazo principal, manteniendo el original como respaldo de emergencia.

    Optimizaciones de sistema críticas

    Gestión de memoria: zram como salvavidas

    Con solo 8GB de RAM física, implementé zram para expansión de memoria virtual comprimida:

    # Configuración zram implementada
    /dev/zram0: 3.8GB comprimidos
    Ratio compresión: ~3:1
    Resultado efectivo: ~10-12GB memoria utilizable

    Impacto medido: Firefox puede mantener 15-20 pestañas abiertas sin degradación perceptible del sistema.

    Optimización Firefox para RAM limitada

    # Configuraciones clave en about:config
    browser.cache.memory.capacity: 51200 (50MB)
    browser.sessionhistory.max_total_viewers: 0
    browser.tabs.unloadOnLowMemory: true

    Extensiones esenciales:

    • uBlock Origin: Bloqueo de contenido pesado
    • Auto Tab Discard: Suspensión automática de pestañas inactivas

    Gestión energética inteligente

    Limitaciones críticas del MacBook Pro 2013

    Realidad técnica: A diferencia de laptops más modernos, el MacBook Pro 11,1 bajo Linux NO soporta control automático de umbrales de carga de batería:

    # Verificación en mi sistema
    sudo tlp-stat -b
    # Resultado: "Supported features: none available"
    # charge_control_start_threshold = (not available)
    # charge_control_end_threshold = (not available)

    Esta limitación requiere estrategias manuales de protección.

    Sistema de monitorización automática

    Desarrollé scripts de protección que compensan las limitaciones del hardware:

    #!/bin/bash
    # Script de monitorización cada 5 minutos vía cron
    # Alertas por temperatura >42°C
    # Warnings por tiempo prolongado al 100%
    # Modo nocturno estricto 22:00-08:00

    Configuración TLP funcional (sin umbrales automáticos):

    # Configuraciones que SÍ funcionan en MacBook Pro 2013
    TLP_ENABLE=1
    CPU_SCALING_GOVERNOR_ON_AC=ondemand
    CPU_SCALING_GOVERNOR_ON_BAT=powersave
    CPU_BOOST_ON_BAT=0
    PLATFORM_PROFILE_ON_BAT=low-power
    WIFI_PWR_ON_BAT=on

    Estrategias diferenciadas por hardware

    MacBook Pro 2013: Rutina manual estricta

    Limitaciones técnicas:

    • Sin gestión automática de batería
    • Tecnología de carga de 2013
    • Mayor susceptibilidad a degradación térmica

    Rutina diaria implementada:

    • Rango óptimo: 20-85% (manual)
    • Desconexión nocturna obligatoria
    • Monitorización cada 5 minutos via cron
    • Hibernación inteligente configurada

    Rutina mensual para calibración:

    1. Desactivar protección automática
    2. Descarga controlada hasta 5% (NO 0%)
    3. Carga completa al 100%
    4. Reactivar protección

    Diferenciación importante: Mac M1

    ADVERTENCIA CRÍTICA: Las estrategias para MacBook 2013 NO se aplican a Mac M1.

    Mac M1 + Folding@Home:

    • Optimización automática de batería nativa
    • Conectado 24/7 durante Folding es aceptable
    • Rutina mensual 30% (NO semanal, NO 0%)
    • Gestión térmica superior

    Hibernación a disco: configuración avanzada

    Diagnóstico inicial

    # Estado original del sistema
    cat /sys/power/state
    # Output: "freeze mem" (hibernación no disponible)
    
    # Configuración kernel
    grep CONFIG_HIBERNATION /boot/config-$(uname -r)
    # Output: CONFIG_HIBERNATION=y (soporte disponible)

    Configuración paso a paso

    Requisitos cumplidos:

    • RAM: 7.7GB
    • Swap disponible: 15GB (11.2GB disco + 3.8GB zram)
    • UUID swap: a13628e9-f161-4315-afea-4d06e704d09d

    Implementación:

    # 1. Configurar GRUB
    sudo nano /etc/default/grub
    # Añadir: resume=UUID=a13628e9-f161-4315-afea-4d06e704d09d
    sudo update-grub
    
    # 2. Configurar initramfs
    echo "RESUME=UUID=a13628e9-f161-4315-afea-4d06e704d09d" | sudo tee /etc/initramfs-tools/conf.d/resume
    sudo update-initramfs -u
    
    # 3. Reiniciar y verificar
    sudo reboot
    cat /sys/power/state
    # Resultado esperado: "freeze mem disk"

    Sistema de hibernación inteligente

    Script automatizado que:

    • Crea snapshots de trabajo antes de hibernar
    • Hibernación automática al 15% de batería
    • Countdown cancelable de 60 segundos
    • Modo «descarga completa» para calibración
    • Restauración de sesión post-hibernación

    Resultados medibles

    Rendimiento del sistema

    Antes de optimizaciones:

    • RAM efectiva: 8GB
    • Multitarea limitada: 5-8 pestañas Firefox
    • Autonomía: ~2 horas
    • Temperaturas: CPU >80°C frecuente

    Después de optimizaciones:

    • RAM efectiva: ~12GB (con zram)
    • Multitarea mejorada: 15-20 pestañas estables
    • Autonomía: 5-7 horas uso real
    • Temperaturas: CPU <75°C normal

    Longevidad de batería

    Datos actuales (3 meses post-instalación):

    # Estado verificado
    Manufacturer: ifixit
    Model: bq20z451 (Texas Instruments - premium)
    Cycle Count: 4 (prácticamente nueva)
    Capacity: 104.2% (superior a original)
    Charge Full: 6669 mAh (vs 6400 mAh diseño)

    Lecciones técnicas importantes

    Inversión inteligente vs reemplazo

    Total invertido: 140€ (batería 120€ + cargador 20€)
    Alternativa evitada: 350€ ThinkPad nuevo
    Ahorro neto: 210€
    Vida útil proyectada: 3-5 años adicionales

    Diferencias generacionales críticas

    Error común: Aplicar estrategias modernas a hardware legacy. Las capacidades de gestión energética han evolucionado significativamente entre 2013 y 2020+.

    Realidad técnica: Hardware de 2013 requiere supervisión manual donde hardware moderno tiene automatización.

    Importancia de la monitorización

    Sin capacidades automáticas de protección, la implementación de sistemas de alertas y scripts de monitorización se vuelve esencial para prevenir degradación acelerada.

    Conclusión: viabilidad a largo plazo

    Un MacBook Pro de 2013 puede seguir siendo funcional en 2025 con:

    1. Hardware renovado: Batería premium + limpieza interna
    2. Optimizaciones específicas: zram, TLP, Firefox tuning
    3. Protección automatizada: Scripts de monitorización
    4. Rutinas disciplinadas: Carga manual inteligente
    5. Hibernación configurada: Protección total del trabajo

    Casos de uso viables:

    • Desarrollo ligero y scripting
    • Navegación web optimizada
    • Tareas de productividad básica
    • Equipo secundario/respaldo

    No recomendado para:

    • Edición de video pesada
    • Gaming moderno
    • Compilación de proyectos grandes
    • Uso como equipo principal

    La clave está en entender las limitaciones del hardware y trabajar dentro de ellas, no contra ellas. Con las optimizaciones correctas y expectativas realistas, la inversión de 140€ puede proporcionar varios años más de utilidad de un equipo que de otro modo sería descartado.

    Recursos técnicos:

  • Cómo darle nueva vida a un MacBook Pro 2013: Batería hinchada, optimizaciones Linux y decisiones inteligentes

    El problema inicial

    Mi MacBook Pro Retina 13″ de 2013 llevaba años funcionando solo con corriente. La batería había dejado de cargar hace tiempo, pero como lo usaba principalmente en casa, no me preocupé demasiado.

    Llegué a plantearme seriamente sustituirlo por una tablet Android con «6GB + 28GB expandidos» (spoiler: esa RAM expandida es básicamente almacenamiento lento disfrazado de memoria). Pero antes de tomar esa decisión, decidí investigar si mi viejo Mac tenía solución.

    Descubriendo el peligro oculto

    Cuando finalmente conseguí el destornillador Pentalobe P5 adecuado y abrí la carcasa inferior, me encontré con una sorpresa desagradable: uno de los módulos de la batería estaba hinchado.

    Esto es peligroso. Las baterías de litio hinchadas pueden:

    • Romper componentes internos (especialmente el trackpad, que está justo encima)
    • Liberar gases tóxicos
    • En casos extremos, incendiarse o explotar

    Si tu portátil tiene una batería vieja y notas que el trackpad está elevado, la carcasa no cierra perfectamente o hay separaciones visibles, revísalo inmediatamente.

    Manejo seguro de baterías hinchadas:

    1. NO la perfores, dobles o presiones
    2. Retírala del dispositivo inmediatamente
    3. Colócala en superficie no inflamable (metal, cerámica)
    4. Mantenla lejos de materiales inflamables
    5. Llévala a un punto limpio o tienda de electrónica cuanto antes
    6. NUNCA la tires a la basura normal

    La solución: inversión inteligente vs reemplazo

    Tenía dos opciones claras:

    Opción A: Comprar un portátil usado (ThinkPad T480 con 16GB RAM) → ~300-350€

    Opción B: Reparar el Mac → Batería + cargador → ~140€

    ¿Por qué reparar?

    Contexto importante: tengo un Slimbook Pro (2019) con 32GB RAM como equipo principal. El MacBook es mi portátil secundario para:

    • Desarrollo ligero en cafeterías
    • Movilidad sin preocuparme por golpes
    • Situaciones donde necesito algo compacto y resistente

    Para este uso ocasional, 8GB optimizados son suficientes. No necesitaba gastar el doble en otro equipo cuando el problema era solucionable.

    El proceso de reparación

    1. Batería nueva de iFixit (120€)

    Pedí el kit completo que incluye:

    • Batería A1493 (compatible con MacBook Pro 13″ Retina Late 2013 – modelo A1502)
    • Todas las herramientas necesarias (Pentalobe P5, Torx T5, spudger, pinzas)
    • Kit de adhesivos
    • Removedor de pegamento viejo

    Ventaja de iFixit: No tienes que comprar nada más. Otros vendedores solo dan la batería y luego descubres que necesitas herramientas especiales.

    2. Limpieza interna

    Aprovechando que tenía el Mac abierto, limpié el polvo acumulado:

    Materiales:

    • Aire comprimido en lata
    • Brocha suave
    • Paño de microfibra
    • Alcohol isopropílico 90%+

    Zonas críticas:

    • Ventiladores (sujetando las aspas para evitar que giren)
    • Disipador de calor
    • Conectores y puertos

    NO uses:

    • Aspiradora (carga estática)
    • Agua
    • Trapo húmedo normal

    3. Cargador de repuesto (20€)

    Mi cable MagSafe 2 original de 2013 estaba reparado con cinta aislante desde hacía años. Aunque funcionaba, con una batería nueva de 120€ no quería arriesgarme a dañarla con un cargador deteriorado.

    Después de investigar, compré un SCOVEE 60W T-Tip en Amazon (19,99€):

    • Compatible con A1502
    • 4.8/5 estrellas con 81 reseñas
    • Certificaciones CE/FCC/RoHS
    • Reseñas positivas sobre temperatura («no se calienta»)

    No es una marca premium como Green Cell, pero para uso ocasional y con las buenas valoraciones, era una opción sensata. El cable original queda como backup de emergencia.

    Optimizaciones de software: TLP para gestión de energía

    Además de la batería nueva, instalé TLP para optimizar automáticamente el consumo de energía.

    TLP optimiza el consumo de batería automáticamente sin configuración manual.

    # Instalación
    sudo apt install tlp tlp-rdw
    
    # Activar
    sudo systemctl enable tlp
    sudo systemctl start tlp
    
    # Ver estado de batería
    sudo tlp-stat -b
    

    Lo mejor de TLP: funciona completamente en segundo plano. Una vez instalado, se olvida.

    Calibración de la batería: crítico pero sencillo

    Las baterías nuevas deben calibrarse para que el indicador de porcentaje sea preciso. Sin calibración, el sistema no sabe la capacidad real y puede apagarse al 50% o seguir funcionando «al 1%» durante horas.

    Proceso correcto según iFixit/Apple:

    Para portátiles:

    1. Carga inicial:
      • Cargar hasta 100%
      • Mantener conectado 2 horas más (crítico para balanceo de celdas)
      • Puede estar apagado o encendido
    2. Descarga completa:
      • Desconectar y usar normalmente
      • Cuando aparezca advertencia de batería baja → guardar trabajo
      • Dejar que se apague solo (no apagarlo manualmente)
      • Esto establece el «ancla» inferior de calibración
    3. Espera:
      • Dejar 5 horas apagado y desconectado
      • Esto asegura que el sistema de gestión registre correctamente la descarga
    4. Carga final:
      • Cargar de forma ininterrumpida hasta 100%
      • ✅ Batería calibrada

    ¿Por qué dejar que se apague solo y no parar al 5-10%?

    El sistema de gestión mantiene una reserva de seguridad invisible. Cuando muestra «0%», todavía hay carga química real para proteger la batería de daños. Solo dejando que el sistema se apague por sí mismo se establece correctamente el punto de «descarga completa» que el controlador necesita.

    Resultados

    Estado de la batería después de la instalación:

    sudo tlp-stat -b
    
    manufacturer = ifixit
    model_name = bq20z451
    cycle_count = 1
    charge_full_design = 6400 mAh
    charge_full = 6661 mAh
    Capacity = 104.1%
    

    ¡La batería tiene 104.1% de capacidad! iFixit envió una batería mejor que las especificaciones originales.

    Mejoras del sistema:

    Antes:

    • ❌ Sin portabilidad (batería muerta)
    • ❌ Cable de carga deteriorado
    • ❌ Batería hinchada (peligro)

    Después:

    • ✅ Autonomía 5-7 horas
    • ✅ Cargador nuevo y seguro
    • ✅ Batería con 104% de capacidad
    • ✅ Sistema limpio internamente
    • ✅ TLP optimizando consumo automáticamente

    Conclusiones y aprendizajes

    1. Las baterías hinchadas son peligrosas

    No ignores las señales: trackpad elevado, carcasa que no cierra bien, separaciones visibles. Revísalo cuanto antes.

    2. Reparar puede ser más inteligente que reemplazar

    Contexto importa:

    • Equipo principal potente → reparar el secundario tiene sentido
    • Solo uso ocasional → 8GB optimizados son suficientes
    • Inversión: 140€ vs 300-350€ → ahorro de 160-210€

    3. iFixit vale cada euro

    Calidad garantizada, herramientas incluidas, guías detalladas, garantía sólida. Para reparaciones importantes, no escatimes en la batería.

    4. La calibración NO es opcional

    Dos horas extras al 100% + descarga completa + espera 5 horas. Parece tedioso pero es la diferencia entre un indicador preciso y uno errático.

    Mi setup final

    Equipo principal (oficina/casa):

    • Slimbook Pro 2019 con 32GB RAM
    • Backend pesado, Docker, IDEs, múltiples proyectos

    Portátil ocasional (movilidad):

    • MacBook Pro 2013 renovado
    • Desarrollo ligero, resistente, compacto
    • Autonomía real de 5-7 horas

    Total invertido en renovación: 140€

    • Batería iFixit: 120€
    • Cargador SCOVEE: 20€

    Vida útil esperada: 3-5 años más para uso ocasional

    Recursos útiles

    Para recordar

    Si tienes un portátil viejo y la batería está muerta o hinchada:

    1. Revisa la batería (ábrelo y comprueba hinchazón – es peligroso)
    2. iFixit para repuestos (calidad garantizada, incluye herramientas)
    3. Limpia el interior (aire comprimido, aprovecha que está abierto)
    4. Instala TLP (gestión automática de energía en Linux)
    5. Calibra después de batería nueva (proceso completo, no atajos)

    Un portátil de 2013 con batería nueva y bien mantenido puede seguir siendo perfectamente usable en 2025 para desarrollo ligero y uso diario. No todo necesita ser reemplazado.


    Hardware: MacBook Pro Retina 13″ 2013 (A1502) | Software: Debian GNU/Linux con XFCE

  • Packaging Stremio for Debian: A Journey to 100% System Library Integration

    Packaging Stremio for Debian: A Journey to 100% System Library Integration

    Stremio for Debian: A Journey to 100% System Library Integration

    How I replaced every bundled dependency in a complex Qt5 application—and what I learned about patch development, threading bugs, and the art of debugging runtime crashes

    By Juan Manuel Méndez Rey

    Last Updated: October 3, 2025

    Tags: #debian #packaging #qt5 #technical-writing #system-libraries #debugging #free-software


    TL;DR

    I packaged Stremio for Debian by replacing 100% of its bundled dependencies (libmpv, Qt libraries, OpenSSL) with system libraries. Along the way, I debugged five critical issues: QtWebEngine initialization order, threading conflicts with SingleApplication, missing QML modules, Node.js environment variables in QProcess, and debhelper install file pitfalls. The real lesson? I repeated patch creation 5+ times because I tested against modified sources instead of clean upstream. This article shares both the technical solutions and the meta-lesson about efficient patch development workflow that could have saved me 70% of development time.

    Key Takeaway: When packaging complex applications, test your patches against pristine upstream at each step, not at the end.


    Package Status (October 2025)

    This article documents the technical work behind packaging Stremio for Debian. The package has achieved 100% system library integration and is currently:

    • Technical work: Complete and validated
    • ITP submitted: Under review by Debian Developer sponsor
    • Status: Awaiting upload approval
    • Repository: salsa.debian.org/mendezr/stremio

    This is a technical deep-dive into the challenges and solutions, not an announcement of package availability. The work continues through the Debian review process.


    Introduction

    When I set out to package Stremio—a popular media center application—for Debian, I had one clear goal: achieve 100% system library integration. No bundled dependencies, no git submodules, just clean integration with Debian’s ecosystem. What seemed like a straightforward build system migration turned into a deep dive into Qt5 threading models, runtime initialization order, and the subtle art of creating minimal, maintainable patches.

    This is the story of that journey, the technical challenges I faced, and—perhaps most importantly—the lessons I learned about efficient patch development that could have saved me days of rework.

    The Challenge: System Libraries or Bust

    Stremio’s upstream repository arrived with several bundled dependencies as git submodules:

    • libmpv for video playback
    • qthelper for Qt utilities
    • singleapplication for single-instance behavior
    • OpenSSL libraries

    The Debian way is clear: use system-provided libraries. This isn’t just philosophical purity—it’s about security updates, dependency management, and integration with the broader ecosystem.

    The goal: Replace every bundled dependency with its Debian system library equivalent.

    The result: A working .deb package with a 293KB optimized binary using 100% system libraries.

    The journey: Five major technical hurdles, each revealing deeper insights into Qt5 application architecture.

    The First Victory (That Wasn’t)

    Initial packaging seemed straightforward. I modified CMakeLists.txt to use system libraries:

    find_package(PkgConfig REQUIRED)
    pkg_check_modules(MPV REQUIRED mpv)
    find_package(Qt5 REQUIRED COMPONENTS Core Gui Qml Quick WebEngine)
    find_package(OpenSSL REQUIRED)

    The build succeeded. Dependencies looked perfect:

    $ ldd build/stremio | head -5
        libQt5WebEngine.so.5 => /lib/x86_64-linux-gnu/libQt5WebEngine.so.5
        libQt5DBus.so.5 => /lib/x86_64-linux-gnu/libQt5DBus.so.5
        libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3
        libmpv.so.2 => /lib/x86_64-linux-gnu/libmpv.so.2

    Perfect! Ship it, right?

    Wrong. When I actually ran the application:

    Segmentation fault (core dumped)

    Thus began the real work.

    Challenge 1: The QtWebEngine Initialization Bug

    Symptom: Immediate segmentation fault when launching the application.

    First debugging attempt: Run with gdb, examine the stack trace:

    Program received signal SIGSEGV, Segmentation fault.
    0x00007ffff5a2b3c4 in QQmlApplicationEngine::QQmlApplicationEngine() ()

    The crash occurred during QQmlApplicationEngine construction. But why? The same code worked fine with bundled libraries.

    The investigation: After examining Qt5 WebEngine documentation and several failed attempts to reorganize the code, I discovered a critical initialization requirement buried in the QtWebEngine documentation:

    QtWebEngine::initialize() must be called before the QApplication constructor when using QML.

    The bundled library setup happened to satisfy this ordering by accident. With system libraries, the default main() function violated it:

    // WRONG - causes crashes
    int main(int argc, char *argv[]) {
        QApplication app(argc, argv);  // QApplication created first
        // QtWebEngine::initialize() never called!
        QQmlApplicationEngine engine;  // CRASH
    }

    The fix (patch 0007-add-qtwebengine-initialize-fix.patch):

    // CORRECT - initialize QtWebEngine before QApplication
    int main(int argc, char *argv[]) {
        QtWebEngine::initialize();     // CRITICAL: Must be first!
        QApplication app(argc, argv);
        QQmlApplicationEngine engine;  // Now works
    }

    Lesson: When replacing bundled libraries with system ones, initialization order assumptions may change. Always verify startup sequence requirements.

    Challenge 2: The SingleApplication Threading Nightmare

    Symptom: After fixing QtWebEngine initialization, the application launched but immediately crashed with:

    QObject: Cannot create children for a parent that is in a different thread.

    The culprit: System library libsingleapplication-dev version 3.3.4.

    Stremio needs single-instance behavior—when you launch it a second time, it should activate the existing window rather than start a new process. The upstream code used a bundled singleapplication library. The Debian system provides libsingleapplication-dev. Perfect replacement, right?

    Wrong again.

    The investigation: The system SingleApplication library sets up a threading context that conflicts with QQmlApplicationEngine. Specifically:

    1. System SingleApplication creates its IPC mechanism in a worker thread
    2. QQmlApplicationEngine expects to be created in the main thread
    3. Qt5’s threading model doesn’t allow cross-thread parent-child relationships for certain QML objects

    The bundled version used a different threading approach that happened to work with QML.

    The false starts: I tried:

    • Patching SingleApplication to use main thread (broke IPC)
    • Deferring QML engine creation (broke startup sequence)
    • Various Qt thread affinity hacks (broke other things)

    The solution: Write a custom CompatibleSingleApp class that provides identical functionality without threading conflicts:

    // compatible_singleapp.h
    class CompatibleSingleApp : public QApplication {
        Q_OBJECT
    public:
        CompatibleSingleApp(int &argc, char **argv);
        bool isPrimary() const;
        bool isSecondary() const;
    
    signals:
        void instanceStarted();
    
    private:
        QLocalServer *m_server;
        QString m_serverName;
        bool m_isPrimary;
    };

    Implementation highlights (patch 0008-add-compatible-singleapp-implementation.patch):

    CompatibleSingleApp::CompatibleSingleApp(int &argc, char **argv)
        : QApplication(argc, argv), m_isPrimary(false) {
    
        m_serverName = "stremio-" + QString(qgetenv("USER"));
    
        // Try to connect to existing instance
        QLocalSocket socket;
        socket.connectToServer(m_serverName);
    
        if (socket.waitForConnected(500)) {
            // Secondary instance - notify primary and exit
            m_isPrimary = false;
            socket.write("ACTIVATE");
            socket.waitForBytesWritten();
            return;
        }
    
        // Primary instance - create server
        m_isPrimary = true;
        m_server = new QLocalServer(this);
        m_server->listen(m_serverName);
    
        connect(m_server, &QLocalServer::newConnection, this, [this]() {
            QLocalSocket *client = m_server->nextPendingConnection();
            connect(client, &QLocalSocket::readyRead, [this, client]() {
                QByteArray data = client->readAll();
                if (data == "ACTIVATE") {
                    emit instanceStarted();
                }
                client->deleteLater();
            });
        });
    }

    Result: Perfect single-instance behavior using pure QApplication (no threading conflicts) with QLocalSocket/QLocalServer for IPC.

    Binary size: 424KB debug vs 293KB release—both using 100% system libraries.

    Key lesson: System libraries may have different implementation details (like threading models) even when providing the same API. Sometimes a custom minimal implementation is cleaner than patching around incompatibilities.

    Challenge 3: The Missing QML Modules

    Symptom: After fixing both initialization and threading issues, the application launched but showed a black screen with console errors:

    module "QtWebEngine" is not installed
    module "QtWebChannel" is not installed
    module "Qt.labs.platform" is not installed

    The problem: Qt5 QML modules are separate runtime packages in Debian, not automatically pulled in by qtdeclarative5-dev.

    The investigation: Stremio’s QML code imports numerous Qt modules:

    import QtQuick 2.12
    import QtQuick.Controls 2.12
    import QtWebEngine 1.10
    import QtWebChannel 1.0
    import Qt.labs.platform 1.1
    import Qt.labs.settings 1.0

    Each requires a separate Debian package.

    The solution: Comprehensive dependency mapping in debian/control:

    Depends: ${shlibs:Depends}, ${misc:Depends},
             qml-module-qtwebengine,
             qml-module-qtwebchannel,
             qml-module-qt-labs-platform,
             qml-module-qtquick-controls,
             qml-module-qtquick-dialogs,
             qml-module-qt-labs-settings,
             qml-module-qt-labs-folderlistmodel,
             qtbase5-dev-tools

    Lesson: When packaging Qt QML applications, trace every QML import statement to its corresponding Debian package. apt-file search is your friend:

    $ apt-file search QtWebEngine.qml
    qml-module-qtwebengine: /usr/lib/x86_64-linux-gnu/qt5/qml/QtWebEngine/...

    Challenge 4: The Streaming Server Mystery

    Symptom: GUI loads perfectly, but when trying to play media:

    Error while starting streaming server
    tcp: Connection to tcp://127.0.0.1:11470 failed: Connection refused

    The investigation: Stremio includes a Node.js server component (server.js) for streaming. The shell process log showed:

    TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
        at Object.join (node:path:1292:7)

    The root cause: Qt’s QProcess doesn’t inherit environment variables by default. The Node.js server expected HOME, USER, and PWD to be available, but they weren’t.

    The fix (patch 0011-fix-qprocess-environment-for-server-launch.patch):

    // stremioprocess.cpp
    void Process::start() {
        // Set up environment variables for Node.js server
        QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    
        if (!env.contains("HOME")) {
            env.insert("HOME",
                QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
        }
        if (!env.contains("USER")) {
            env.insert("USER", qgetenv("USER"));
        }
        if (!env.contains("PWD")) {
            env.insert("PWD", QDir::currentPath());
        }
    
        this->setProcessEnvironment(env);
        QProcess::start();
    }

    Result: Server starts successfully:

    hls executables located -> { ffmpeg: '/usr/bin/ffmpeg', ffsplit: null }
    Using app path -> /home/user/.stremio-server
    EngineFS server started at http://127.0.0.1:11470

    Lesson: When spawning processes from Qt applications, explicitly configure the environment. Don’t assume child processes inherit the parent’s environment variables.

    Challenge 5: Debian Packaging Structure Pitfalls

    Symptom: Package builds successfully, but files install to wrong locations or with wrong names.

    The problem: Misunderstanding debhelper’s .install file behavior.

    What I thought:

    # debian/stremio.install
    build/stremio usr/bin/stremio-bin    # Install as /usr/bin/stremio-bin

    What actually happened:

    /usr/bin/stremio-bin/stremio    # Created DIRECTORY, file inside!

    The revelation: In debhelper .install files:

    • Path ending with / → Install files INTO that directory using original names
    • Path WITHOUT / → Create directory with that name and install files inside

    The correct solution (actual implementation):

    # debian/stremio.install
    # Binary installed to /usr/libexec (FHS 3.0 compliance for helper executables)
    build/stremio usr/libexec/stremio/
    
    # Wrapper script becomes the primary user-facing command
    debian/stremio-wrapper usr/bin/
    
    # Desktop file for application menu integration
    debian/stremio.desktop usr/share/applications/
    
    # Application icons (multiple resolutions for different contexts)
    icons/smartcode-stremio_16.png usr/share/icons/hicolor/16x16/apps/
    icons/smartcode-stremio_64.png usr/share/icons/hicolor/64x64/apps/
    # ... (additional icon sizes)

    Why this structure?

    1. /usr/libexec/stremio/: Modern FHS 3.0 location for internal executables not meant to be called directly by users
    2. Wrapper script at /usr/bin/stremio: Sets environment variables (like QTWEBENGINE_DISABLE_SANDBOX=1) before launching the actual binary
    3. Trailing slashes: Install files INTO directories using original filenames—critical for correct placement

    Lesson: Read debhelper documentation carefully. Small syntax details (trailing slashes!) have big consequences. Modern Debian packaging also follows FHS 3.0 standards, placing helper binaries in /usr/libexec/ rather than /usr/bin/.

    The Meta-Lesson: Efficient Patch Development

    The technical challenges were difficult, but I made them harder through inefficient workflow. I created patches, tested them, found they failed on clean upstream, then reworked them—five times.

    The problem: I was testing patches against already-modified sources, not pristine upstream.

    Build System Strategy: Patch CMakeLists.txt First

    Critical principle: Always prioritize build system patches over source code modifications.

    When replacing bundled dependencies with system libraries, the first patches should target CMakeLists.txt:

    # Patch 0005-cmake-system-libraries-v4.4.169.patch
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(MPV REQUIRED mpv)
    find_package(Qt5 REQUIRED COMPONENTS Core Gui Qml Quick WebEngine DBus)
    find_package(OpenSSL REQUIRED)

    Why this matters: Smaller, focused patches that address build system integration separately from source code changes are easier to maintain and review.

    Build system preference: We used qmake to generate makefiles first (Stremio’s traditional build system), then ensured CMake compatibility. The stremio.pro file and release.makefile workflow took precedence for package builds.

    The Anti-Pattern

    1. Modify source files directly to fix issue
    2. Generate patches from modified state
    3. Try to apply patches to clean upstream
    4. Patches fail (missing context, wrong line numbers, missing dependencies)
    5. Repeat

    The Efficient Workflow I Should Have Used

    # 1. Start with clean upstream
    git checkout v4.4.169
    
    # 2. Create isolated test environment
    cp -r . /tmp/patch-test/
    cd /tmp/patch-test/
    
    # 3. Fix ONE issue, test, generate patch
    # (fix QtWebEngine initialization)
    mkdir build && cd build && cmake .. && make    # Test build
    cd .. && git diff > 0001-qtwebengine-init.patch
    
    # 4. Apply patch to clean upstream, fix next issue
    git checkout v4.4.169
    patch -p1 < 0001-qtwebengine-init.patch
    # (fix next issue)
    git diff > 0002-next-fix.patch
    
    # 5. Final validation: apply all patches to clean upstream
    git checkout v4.4.169
    for patch in *.patch; do
        patch -p1 < $patch || exit 1
    done
    mkdir build && cd build && cmake .. && make

    Dependency analysis checklist I wish I’d used from the start:

    ## Pre-Patch Analysis Template
    
    ### Files to Modify:
    - [ ] main.cpp - entry point changes
    - [ ] mainapplication.h - class definitions, includes
    - [ ] CMakeLists.txt - build system
    - [ ] compatible_singleapp.h/cpp - new files
    
    ### Dependency Chain:
    1. main.cpp includes → mainapplication.h
    2. mainapplication.h includes → singleapplication.h (to replace)
    3. CMakeLists.txt references → SingleApplication library
    4. Qt MOC will process → Q_OBJECT classes (check conflicts!)
    
    ### Build Test Plan:
    - [ ] Clean cmake build
    - [ ] ldd dependency verification
    - [ ] Runtime basic functionality

    Time saved if I’d done this from the start: ~70% reduction in patch development time.

    Key insight: Understand file dependencies and build system BEFORE making changes. Test patches against clean upstream at each step, not just at the end.

    The Complete Patch Set

    The final working solution consists of 11 patches:

    1. 0001-Fix-server.js-path-for-FHS-compliance.patch – Server location
    2. 0002-disable-server-download.patch – Use system Node.js
    3. 0004-minimal-qthelper-integration.patch – System Qt utilities
    4. 0005-cmake-system-libraries-v4.4.169.patch – MPV, OpenSSL integration
    5. 0007-add-qtwebengine-initialize-fix.patchCritical: QtWebEngine initialization
    6. 0008-add-compatible-singleapp-implementation.patchCritical: Custom single-instance
    7. 0009-remove-system-singleapplication-add-compatible.patch – Build integration
    8. 0010-fix-qmake-install-paths.patch – Install location fixes
    9. 0011-fix-qprocess-environment-for-server-launch.patchCritical: Server environment

    Validation Workflow

    The final validation workflow ensures patches work on clean upstream, using the GBP (git-buildpackage) import workflow for proper Debian package building:

    # Step 1: Create pristine test environment with GBP structure
    git clone --branch v4.4.169 https://github.com/Stremio/stremio-shell.git /tmp/validation
    cd /tmp/validation
    cp -r /path/to/debian .
    
    # Step 2: Apply all patches using quilt
    export QUILT_PATCHES=debian/patches
    quilt push -a
    
    # Step 3: Test local build first (fastest iteration)
    QT_DEFAULT_MAJOR_VERSION=5 dpkg-buildpackage -us -uc
    
    # Step 4: Verify dependencies
    ldd debian/stremio/usr/libexec/stremio/stremio | head -5
    # Should show: libQt5WebEngine.so.5, libcrypto.so.3, libmpv.so.2
    
    # Step 5: Test with pbuilder (clean chroot environment)
    sudo pbuilder update
    sudo pbuilder build ../*.dsc
    
    # Step 6: Test with sbuild (production-grade build)
    # WARNING: Qt5/WebEngine packages consume significant space
    # Typical requirement: 4-6GB build space (overlayfs in tmpfs)
    # Solution: Use machine with 16GB+ RAM or configure sbuild on disk
    
    sbuild -d unstable ../*.dsc
    # If sbuild fails with "No space left on device":
    # - Switch to larger machine (16GB+ RAM recommended)
    # - Or configure sbuild to use disk instead of tmpfs

    Build Environment Considerations

    Memory requirements for Qt5 applications:

    • dpkg-buildpackage: ~2GB RAM
    • pbuilder: ~4GB RAM
    • sbuild with overlayfs in tmpfs: 6-8GB RAM (Qt5WebEngine is memory-intensive)

    Our solution: After encountering space exhaustion on 8GB machines during sbuild, we migrated to a 32GB machine. This is typical for Qt5/WebEngine applications—always test sbuild capacity before committing to build infrastructure.

    Result: 293KB optimized binary, 100% system libraries, full functionality including streaming.

    Lessons for Other Packagers

    Technical Takeaways

    1. Initialization order matters: System libraries may have different startup requirements than bundled ones. Always verify initialization sequences.
    2. Threading models vary: Even libraries with identical APIs may use different threading approaches. Watch for cross-thread object creation errors.
    3. Environment variables aren’t automatic: QProcess and similar mechanisms need explicit environment setup.
    4. QML modules are separate packages: Trace every QML import to its Debian package dependency.
    5. Custom implementations beat complex patches: Sometimes writing 100 lines of clean code is better than a 500-line patch to an incompatible library.

    Process Takeaways

    1. Always test patches against clean upstream: Never generate patches from already-modified sources.
    2. Map dependencies before coding: Understand file relationships and build system before making changes.
    3. One fix, one patch, one test: Incremental development prevents cascading failures.
    4. Document assumptions: What works «by accident» with bundled libraries may fail with system ones.
    5. Validate completely: Test patches in isolated environments before declaring them «ready».

    Conclusion

    Packaging Stremio for Debian taught me far more than Qt5 internals and build system integration. It revealed how easily we fall into inefficient workflows when we don’t step back to examine our process.

    The technical achievement: A fully functional Debian package using 100% system libraries where the upstream used bundled dependencies—293KB binary, zero submodules, complete feature parity.

    The real achievement: Learning that the how of problem-solving matters as much as the what. Efficient patch development isn’t just about technical skill—it’s about disciplined workflow, systematic thinking, and honest self-assessment.

    Would I do anything differently? Absolutely. I’d use the validation workflow from day one, map dependencies before coding, and test each patch against clean upstream immediately.

    But would I have learned these lessons without making the mistakes? Probably not.

    Acknowledgments

    Thanks to the Stremio team for creating great software, the Debian community for maintaining high standards, my friend Arturo (a Debian Developer) that knowing my passion for Debian encouraged me to start working as a Debian Maintainer, and to every packager who has documented their struggles—your war stories make ours easier.


    Project Status (as of October 3, 2025)

    Note: This article documents the technical process and challenges. Package acceptance is pending Debian review. Status updates will be posted as the review process continues.


    This article is part of my journey toward becoming a Debian Developer. If you’re interested in Debian packaging or have questions about the technical details, feel free to reach out.

  • Optimizar GNU/Linux con 8GB de RAM: Firefox + zram para mejor rendimiento

    Mi viejo MacBookPro Retina del 2013, con Debian GNU/Linux y 8GB de RAM iba bastante lento al usar Firefox con múltiples pestañas.

    Estas optimizaciones le dieron una nueva vida sin gastar dinero en hardware.

    Problema

    Firefox es un devorador de RAM. Con varias pestañas abiertas, especialmente sitios web modernos (aplicaciones JavaScript pesadas), es fácil saturar 8GB de RAM. Cuando esto ocurre, el sistema empieza a usar swap en disco, lo que causa congelaciones y lentitud extrema.

    Solución en dos partes

    1. Optimizar Firefox

    Instalar uBlock Origin:

    • Ve a: Menú → Complementos → Buscar «uBlock Origin»
    • Bloquear ads y scripts innecesarios libera fácilmente 1-2GB de RAM

    Activar suspensión automática de pestañas:

    Opción A – Configuración nativa:

    about:config

    Busca browser.tabs.unloadOnLowMemory y actívalo (true)

    Opción B – Extensión (más control):

    • Instala la extensión «Auto Tab Discard»
    • Configura para suspender pestañas después de X minutos sin uso

    Reducir historial de sesión (opcional):

    about:config

    Busca browser.sessionhistory.max_entries y reduce a 5-10 (default: 50)

    Alternativa: Probar Brave Si Firefox sigue siendo muy pesado, Brave es un navegador basado en Chromium pero más eficiente con la RAM:

    bash

    sudo apt install brave-browser

    2. Configurar zram (RAM comprimida)

    ¿Qué es zram? zram crea un dispositivo de swap comprimido en RAM. En vez de escribir al disco cuando se llena la memoria (lento), comprime datos en la propia RAM (rápido). Típicamente logra ratios de compresión 2-3:1, dando efectivamente 10-12GB de RAM «útil» en un sistema de 8GB.

    Instalación:

    bash

    sudo apt install zram-tools

    Configuración:

    bash

    sudo nano /etc/default/zramswap

    Configura así:

    bash

    # Algoritmo de compresión (lz4 es rápido)
    ALGO=lz4
    
    # Porcentaje de RAM a usar para zram (50% = ~4GB)
    PERCENT=50
    
    # Comenta SIZE si usas PERCENT
    #SIZE=512
    
    # Prioridad alta (usa zram antes que swap en disco)
    PRIORITY=100

    Activar:

    bash

    sudo systemctl enable zramswap
    sudo systemctl start zramswap

    Verificar que funciona:

    bash

    zramctl
    # Deberías ver algo como:
    # NAME       ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
    # /dev/zram0 lz4           3.8G   ...
    
    free -h
    # Verás el swap total aumentado

    3. Ajustar swappiness (opcional)

    Por defecto, Linux usa valor 60 de swappiness, que significa que empieza a usar swap relativamente pronto. Con zram, puedes bajarlo para que use más la RAM física primero:

    bash

    # Ver valor actual
    cat /proc/sys/vm/swappiness
    
    # Configurar permanentemente a 10
    echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.conf
    sudo sysctl -p

    Resultados esperados

    Después de aplicar estas optimizaciones:

    • Firefox puede manejar más pestañas sin saturar el sistema
    • Menos «congelaciones» cuando la RAM se llena
    • Cambio entre aplicaciones más fluido
    • Reducción drástica del uso de swap en disco (menos desgaste SSD)
    • Sistema más responsive en general

    Monitorizar el sistema

    Para ver zram en acción:

    bash

    # Ver uso en tiempo real
    watch -n 2 zramctl
    
    # Ver estadísticas detalladas
    watch -n 2 'cat /sys/block/zram0/mm_stat'

    Hardware testado

    • MacBook Pro Retina 13″ (2013) con 8GB RAM
    • Debian con XFCE
    • Firefox con desarrollo web (múltiples pestañas, DevTools)

    Conclusión

    Con estas optimizaciones, un sistema de 8GB puede comportarse casi como uno de 10-12GB para la mayoría de tareas. No sustituye tener más RAM física para cargas de trabajo muy pesadas (compilaciones masivas, virtualización intensiva), pero para desarrollo web, programación backend ligera y uso diario, la diferencia es notable.





  • Resucitando un Slimbook Pro (2019): Cuando la Persistencia Vence al Hardware «Muerto»

    Resucitando un Slimbook Pro (2019): Cuando la Persistencia Vence al Hardware «Muerto»

    Cómo resolver problemas gráficos complejos en Intel UHD Graphics 620 mediante diagnóstico sistemático y parámetros del kernel

    Hace dos meses, mi Slimbook Pro 2019 comenzó a mostrar síntomas que cualquier técnico habría diagnosticado como «hardware muerto»: pantalla interna parpadeando constantemente, sistema extremadamente lento, sesiones gráficas que se colgaban al arrancar. Después de cinco años de funcionamiento perfecto, parecía que había llegado el momento de reemplazarlo.

    Sin embargo, la persistencia y un enfoque sistemático de diagnóstico demostraron que incluso los problemas más graves pueden tener soluciones inesperadas. Este es el relato completo de cómo conseguí que un portátil «desahuciado» volviera a funcionar perfectamente, incluso ejecutando Cinnamon con efectos activados.

    Estado Inicial: Síntomas del Problema

    Hardware afectado:

    • Slimbook Pro (2019) con Intel Core i7 Comet Lake-U
    • Intel UHD Graphics 620 integrada
    • Sistema operativo: Debian GNU/Linux
    • Monitor externo: IProda PD182Kpn (portátil, ideal para complementar el portátil)

    Síntomas observados:

    • Pantalla interna parpadeando constantemente en negro (problema principal)
    • Sistema extremadamente lento, incluso con monitor externo conectado
    • Sesiones gráficas que fallan al arrancar o se cuelgan
    • Interfaz gráfica prácticamente inusable
    • Modo consola funcionando correctamente

    Contexto temporal: El portátil funcionó perfectamente desde 2019 hasta aproximadamente julio-agosto de 2025, cuando los problemas aparecieron súbitamente sin cambios significativos en hardware o software.

    Primera Fase: Diagnóstico y Descarte de Causas Obvias

    Análisis de Logs del Sistema

    El primer paso fue examinar los logs del kernel para identificar la causa raíz:

    sudo dmesg | grep -i "i915"
    

    Los logs revelaron información crítica sobre el controlador de Intel Graphics:

    i915 0000:00:02.0: [drm] Found cometlake/ult (device ID 9b41)
    WARNING: CPU: 0 PID: 176 at drivers/gpu/drm/i915/display/intel_pps.c:974 intel_pps_on_unlocked
    

    Hallazgo clave: Error en la secuencia de encendido del panel (Panel Power Sequence), indicando problemas en la gestión de energía de la pantalla interna.

    Verificación del Estado de las Pantallas

    cat /sys/class/drm/*/status
    # Resultado: 
    # disconnected
    # connected    # Pantalla interna (eDP-1) - causando problemas
    # disconnected  
    # connected    # Monitor externo HDMI-2
    

    Ambas pantallas eran detectadas correctamente por el kernel, pero la interna (eDP-1) estaba causando inestabilidad al sistema completo.

    Análisis de Aceleración Gráfica

    glxinfo | grep -E "(OpenGL renderer|direct rendering)"
    

    En este punto, el sistema mostró renderizado por software (llvmpipe), indicando que la aceleración hardware había fallado, explicando la extrema lentitud del sistema.

    Segunda Fase: Estrategias de Solución Sistemática

    Intento 1: Parámetros del Controlador i915

    Basándome en la investigación sobre problemas conocidos del Intel UHD Graphics 620 en Comet Lake, implementé los primeros parámetros correctivos en GRUB:

    sudo nano /etc/default/grub
    
    # Configuración inicial
    GRUB_CMDLINE_LINUX_DEFAULT="i915.enable_psr=0 i915.enable_rc6=0 i915.enable_guc=2 i915.enable_dc=0"
    
    sudo update-grub && sudo reboot
    

    Explicación de parámetros:

    • enable_psr=0: Desactiva Panel Self Refresh (causa común de parpadeo)
    • enable_rc6=0: Evita estados de bajo consumo problemáticos
    • enable_guc=2: Fuerza carga del firmware GuC/HuC
    • enable_dc=0: Desactiva Display C-states problemáticos en Comet Lake

    Resultado: Mejora marginal, pero el parpadeo de la pantalla interna persistía.

    Intento 2: Gestión de Controladores y Configuración de Xorg

    Cambié del controlador Intel tradicional al controlador modesetting más moderno:

    sudo nano /etc/X11/xorg.conf.d/20-intel.conf
    
    # Configuración
    Section "Device"
        Identifier "Intel Graphics"
        Driver "modesetting"
        Option "AccelMethod" "glamor"
        Option "TearFree" "true"
    EndSection
    

    Resultado: Sin mejoras significativas en la estabilidad.

    Intento 3: Gestión del Gestor de Pantalla

    Los problemas con SDDM llevaron a configurar scripts de inicialización para desactivar automáticamente la pantalla interna:

    sudo nano /usr/share/sddm/scripts/Xsetup
    
    #!/bin/bash
    sleep 3
    xrandr --output eDP-1 --off --output HDMI-2 --auto --primary
    

    Resultado: Mejoras temporales que no persistían entre reinicios, y la pantalla interna seguía parpadeando durante el arranque.

    Tercera Fase: El Breakthrough – Gestión de Energía PCIe y Desactivación a Nivel Kernel

    Identificación del Problema Real

    Un análisis más profundo de los logs reveló errores críticos que habían pasado desapercibidos:

    sudo tail -f /var/log/Xorg.0.log
    
    (WW) modeset(0): hotplug event: connector 106's link-state is BAD, tried resetting the current mode. You may be left with a black screen if this fails...
    

    Este mensaje aparecía repetidamente cada 1-2 segundos, indicando que el problema no era el renderizado gráfico sino la estabilidad de la conexión de los displays.

    La Solución Dual: PCIe ASPM + Desactivación de Pantalla Interna

    La solución final requirió dos enfoques complementarios:

    1. Desactivar la gestión de energía PCIe que causaba inestabilidad
    2. Desactivar completamente la pantalla interna a nivel de kernel para evitar que cause conflictos
    sudo nano /etc/default/grub
    
    # Configuración que solucionó el problema
    GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=igfx_off i915.enable_prs=0 i915.modeset=1 i915.enable_rc6=0 i915.enable_guc=2 i915.enable_dc=0 plymouth.enable=0 i915.enable_fbc=0 video=HDMI-2:1920x1080@60 video=eDP-1:d pcie_aspm=off"
    

    Parámetros clave explicados:

    Gestión de energía y estabilidad:

    • pcie_aspm=off: Crítico – Desactiva Active State Power Management de PCIe, resuelve errores «link-state BAD»
    • intel_iommu=igfx_off: Evita conflictos de mapeo de memoria con gráficos Intel
    • plymouth.enable=0: Desactiva pantalla de arranque problemática

    Configuración del controlador i915:

    • i915.enable_prs=0: Desactiva Panel Self Refresh (parpadeo)
    • i915.enable_dc=0: Desactiva Display C-states problemáticos en Comet Lake
    • i915.enable_rc6=0: Evita estados de bajo consumo problemáticos
    • i915.enable_guc=2: Fuerza carga del firmware GuC/HuC para mejor rendimiento
    • i915.modeset=1: Activa mode setting del kernel
    • i915.enable_fbc=0: Desactiva Frame Buffer Compression

    Configuración de pantallas:

    • video=HDMI-2:1920x1080@60: Fuerza resolución específica para el monitor externo
    • video=eDP-1:d: Desactiva completamente la pantalla interna a nivel de kernel (el parámetro :d significa «disabled»)

    ¿Por qué era Necesaria la Desactivación a Nivel Kernel?

    La pantalla interna parpadeante no solo era molesta visualmente, sino que causaba inestabilidad en todo el subsistema gráfico. Los intentos de desactivarla a nivel de Xorg (xrandr --output eDP-1 --off) llegaban demasiado tarde: el kernel ya había inicializado ambas pantallas y la interna ya había comenzado a causar problemas.

    El parámetro video=eDP-1:d instruye al kernel para que ignore completamente la pantalla interna durante el arranque, evitando que se inicialice y cause conflictos con el controlador de display.

    Cuarta Fase: Verificación del Éxito

    Resultados Inmediatos

    Tras el reinicio con la configuración final:

    # Verificación de aceleración hardware
    glxinfo | grep "OpenGL renderer"
    # Resultado: Mesa Intel(R) UHD Graphics (CML GT2)
    
    # Test de rendimiento
    vblank_mode=0 glxgears
    # Resultado: ~7500 FPS
    
    # Benchmark completo
    glmark2 --fullscreen
    # Puntuación: 590 (excelente para gráficos integrados)
    

    Cambios observados:

    • Pantalla interna completamente silenciosa – sin parpadeos desde el arranque
    • Arranque limpio – sin errores «link-state BAD» en los logs
    • Aceleración hardware restaurada – renderizado por hardware, no software
    • Sistema responsivo – rendimiento normal restaurado

    Resultados Finales

    Estado Actual del Sistema

    Hardware gráfico:

    • Aceleración hardware completamente funcional
    • Intel UHD Graphics 620 operando a pleno rendimiento
    • Monitor externo IProda PD182Kpn funcionando a 1920×1080@60Hz estable
    • Pantalla interna completamente desactivada – sin parpadeos

    Rendimiento del sistema:

    • Entorno de escritorio: Cinnamon con efectos activados
    • Rendimiento gráfico: 590 puntos en glmark2
    • Estabilidad: Sin errores «link-state BAD» en más de una semana de uso intensivo
    • Arranque limpio sin interferencias de la pantalla problemática

    Funcionalidades restauradas:

    • Sesiones gráficas estables
    • Reproducción de video fluida
    • Navegación web sin problemas
    • Capacidad para ejecutar entornos de escritorio modernos

    Validación de la Solución

    El sistema ahora supera las expectativas iniciales:

    # Test de texto 2D (relevante para trabajo de oficina)
    x11perf -aa10text
    # Resultado: 11M caracteres/segundo
    
    # Test de renderizado 3D básico
    glxgears (con vsync)
    # Resultado: 60 FPS estables sin caídas
    
    # Test sin vsync (rendimiento real)
    vblank_mode=0 glxgears  
    # Resultado: 7500+ FPS
    

    Lecciones Técnicas Aprendidas

    1. Los Síntomas Pueden Engañar

    Los síntomas (pantalla parpadeando, sistema lento) apuntaban a fallo de hardware gráfico. La realidad era un problema de gestión de energía PCIe que afectaba la estabilidad de las conexiones de display, más una pantalla interna defectuosa que interfería con todo el subsistema.

    2. La Importancia del Diagnóstico Profundo

    El error crítico «connector link-state BAD» solo era visible en logs específicos de Xorg, no en los logs generales del kernel. El diagnóstico superficial habría llevado a conclusiones erróneas.

    3. Soluciones Múltiples vs Solución Única

    El problema requería dos soluciones complementarias:

    • Estabilizar las conexiones PCIe (pcie_aspm=off)
    • Eliminar la fuente de conflictos (video=eDP-1:d)

    Una sola no era suficiente.

    4. Nivel de Intervención Importante

    Desactivar la pantalla a nivel de aplicación (xrandr) llegaba tarde. Era necesario intervenir a nivel de kernel para evitar que el problema se manifestara desde el inicio.

    Metodología de Diagnóstico Replicable

    Para técnicos que enfrenten problemas similares:

    Paso 1: Recolección de Información

    # Información del hardware
    lspci | grep VGA
    dmidecode -s system-manufacturer
    dmidecode -s bios-version
    
    # Estado de displays
    cat /sys/class/drm/*/status
    xrandr (si es accesible)
    
    # Logs críticos
    dmesg | grep -i "drm\|i915"
    journalctl -xe | grep -i "graphics\|display"
    tail -f /var/log/Xorg.0.log | grep -i "hotplug\|link-state"
    

    Paso 2: Identificación de Patrones

    • Parpadeo constante de pantalla = problema hardware específico de esa pantalla
    • Errores «link-state BAD» repetitivos = problema de gestión de energía PCIe
    • «llvmpipe» en renderizado = falta aceleración hardware (consecuencia)
    • Errores al inicializar sesión gráfica = inestabilidad del controlador de display

    Paso 3: Soluciones Incrementales

    1. Parámetros básicos del controlador i915
    2. Configuración de Xorg optimizada
    3. Gestión de energía PCIe (crítico)
    4. Desactivación de hardware problemático a nivel kernel
    5. Optimización específica por hardware

    Reflexiones sobre la Persistencia Técnica

    Este caso demuestra que el diagnóstico «hardware muerto» debe cuestionarse sistemáticamente. La tendencia a descartar hardware aparentemente fallido puede llevar a:

    • Pérdida económica innecesaria: Un portátil de €500 salvado vs €1000+ en reemplazo
    • Impacto ambiental: Evitar desecho prematuro de hardware funcional
    • Pérdida de datos y configuraciones: Mantener el entorno de trabajo existente

    Cuándo Persistir vs Cuándo Rendirse

    Indicadores para continuar el diagnóstico:

    • Hardware con historial de funcionamiento estable
    • Fallo súbito sin causa aparente
    • Funcionalidad parcial (consola funcionando)
    • Errores específicos en logs (no fallos aleatorios)
    • Un solo componente problemático identificable

    Indicadores para considerar reemplazo:

    • Múltiples componentes fallando simultáneamente
    • Errores de memoria física o CPU
    • Fallos intermitentes sin patrón reproducible
    • Costo de reparación > 60% del valor del equipo

    Configuración del Monitor Externo IProda PD182Kpn

    Una nota específica sobre el monitor portátil utilizado: el IProda PD182Kpn demostró ser un excelente compañero para el portátil reparado:

    Especificaciones relevantes:

    • Panel IPS de 18.5″ Full HD (1920×1080)
    • Conexión HDMI estable con el controlador Intel UHD 620
    • Alimentación via USB-C (compatible con puertos del Slimbook)
    • Perfil delgado ideal para trabajar en movilidad

    Configuración óptima:

    # Forzar resolución y frecuencia específicas
    xrandr --output HDMI-2 --mode 1920x1080 --rate 60
    
    # Configuración permanente en GRUB
    video=HDMI-2:1920x1080@60
    

    Este monitor demostró ser ideal para validar la solución, ya que requiere una señal HDMI completamente estable – cualquier inestabilidad en el controlador gráfico se manifestaría inmediatamente como parpadeos o desconexiones.

    Conclusión: El Valor de la Persistencia Técnica

    Lo que inicialmente parecía un fallo irreversible de hardware se resolvió completamente mediante:

    1. Diagnóstico sistemático en lugar de asunciones basadas en síntomas
    2. Investigación específica sobre el hardware exacto (Comet Lake + UHD 620)
    3. Identificación de componentes problemáticos específicos (pantalla interna)
    4. Soluciones a múltiples niveles (kernel + drivers + gestión de energía)
    5. Documentación detallada de cada intento para evitar repeticiones

    El resultado final supera las expectativas iniciales: un sistema que no solo funciona, sino que rinde mejor de lo esperado para gráficos integrados de 2019. La capacidad de ejecutar Cinnamon con efectos activados demuestra que el hardware tenía potencial que estaba siendo bloqueado por configuraciones subóptimas y un componente específico defectuoso.

    Para cualquier técnico enfrentando problemas similares, el mensaje clave es: antes de declarar hardware muerto, agota las posibilidades de configuración y aísla componentes problemáticos. Los sistemas modernos tienen tantas capas de abstracción (kernel, drivers, gestión de energía, protocolos de display) que los problemas aparentemente de hardware a menudo tienen soluciones de software, especialmente cuando se puede identificar y desactivar el componente específico que causa conflictos.

    La persistencia técnica, combinada con metodología sistemática, puede salvar hardware que de otra manera terminaría prematuramente en el desecho. En un mundo donde la sostenibilidad tecnológica es cada vez más importante, estas victorias tienen valor tanto económico como ambiental.

    El Slimbook Pro 2019 ha vuelto a la vida, demostrando que a veces lo que parece el final es solo un problema esperando la solución correcta – y la determinación para encontrarla.

  • Brief History of Conquer

    Brief History of Conquer

    Conquer: Unix game history

    Conquest begins to be posted on comp.sources.games (October 26, 1987)

    v02i058: conquest – middle earth multi-player game, Part01/05
    http://groups.google.com/group/comp.sources.games/browse_thread/thread/d7cf1d13d3ad2a18/324b78a5bf6ff2ea?lnk=st&q=conquest+barlow&rnum=517#324b78a5bf6ff2ea

    conquest newsletter #2 in rec.games.empire (Nov. 12, 1997)
    http://groups.google.com/group/rec.games.empire/browse_thread/thread/fab56ce19c4b0f90/f9bc206de4016cbe#f9bc206de4016cbe

    Conquest Newsletter #3 in rec.games.empire
    http://groups.google.com/group/rec.games.empire/browse_thread/thread/e62718c10cd8d3d2/957c0bb68ea157fe?lnk=st&q=conquest+barlow&rnum=4#957c0bb68ea157fe

    Conquer 3: v04i042: conquer3 – middle earth multi-player game (V3), Part01/08
    in comp.sources.games (June 16, 1988)
    http://groups.google.com/group/comp.sources.games/browse_thread/thread/23bfc97badb334ba/f1316ffe73640157?lnk=st&q=conquest+barlow&rnum=496#f1316ffe73640157

    Other things…

    Abusing the rules
    http://groups.google.com/group/comp.sources.games.bugs/browse_thread/thread/182e7402b6fdfaa1/17685beba70b796b?lnk=st&q=conquest+barlow&rnum=497#17685beba70

    Bugs were posted in comp.sources.games.bugs
    http://groups.google.com/group/comp.sources.games.bugs/browse_thread/thread/65313fdd9a9d11b5/657e1757d3543427?lnk=st&q=conquest+barlow&rnum=498#657e1757d35

    More bugs, and first message from Adam Bryant on January 23, 1988
    http://groups.google.com/group/rec.games.empire/browse_thread/thread/9d7fcbfe2da74628/ea45e9187af496de?lnk=st&q=conquest+barlow&rnum=500#ea45e9187af496de

    In the year 2006, someone called Vejeta (me) contacts the authors to relicense the code, manages to contact Ed Barlow who gives permission to relicense it.

    http://savannah.gnu.org/task/?5945

    http://lists.debian.org/debian-legal/2006/10/msg00063.html

    On February 23, 2011, vejeta.com receives a message through its contact form. It’s Adam Bryant who has heard news of the request to release the code. He grants permission to release the code under GPL.

    The original code could be extracted and assembled from the original USENET messages with some tools that I don’t remember now.

    Additional notes:

    Asking on barrapunto about how to relicense it:
    https://web.archive.org/web/20180707202804/http://barrapunto.com/~vejeta/journal/22901

    About conquer and dominion:
    https://groups.google.com/group/es.comp.os.unix/browse_thread/thread/808b677b6af29aea/79a5a3abd161f7f1?q=conquer+vejeta+estrategia#79a5a3abd161f7f1

    https://groups.google.com/group/linux.debian.user.spanish/browse_thread/thread/21fc1bf9b912e340/4589e637807bd1ff?q=conquer+vejeta#4589e637807bd1ff

  • Probando juegos de Spectrum en Debian GNU/Linux (spectemu)

    Hay bastantes emuladores para elegir, aunque hoy me voy a centrar en spectemu.

    Lo podemos instalar con:

    apt-get install spectemu-x11

    Y luego podemos ejecutarlo con:

    xspect

    Me decidí a probar uno de los juegos producidos en el 2024 que se están votando ahora mismo en:
    https://spectrumcomputing.co.uk/forums/viewtopic.php?p=160910#p160910

    El juego por el que me decidí es «Cursed Castle 2», del cual hay una demo en:
    https://fransouls.itch.io/cursed-castle-2

    Anteriormente también jugué al «Max Stone»:
    https://flopping.itch.io/max-stone-el-secreto-de-la-gran-piramide
    el cual me lo pasé con algun truco de vidas infinitas

    Pero bueno, el motivo de esta publicación es para guardar una chuleta sobre el «spectemu», este emulador es tan antiguo que intenta encontrar el dispositivo «/dev/dsp», el cual ya no existe en los Linux actuales, y falla.

    Sin embargo, podemos ejecutarlo así:

    padsp xspect Demo.Cursed.Castle.2.tap

    Para que pulseaudio se encargue de simular el dispositivo para xspect.

    Y a partir de aquí: LOAD «» dentro del emulador de Spectrum.

    Y Ctrl-P, Ctrl-S para simular PLAY y PAUSE de la cinta.

    A disfrutar.

  • Raising Money for CliniClowns

    On September 9, 2023 I will participate in the Alpine tour for CliniClowns. They can ensure that more people with disabilities or dementia feel seen and understood. Will you also help and sponsor me? Thank you very much in advance.

    En Septiembre de 2023 participaré en un evento, un tour donde se recogen donaciones para CliniClowns. CliniClowns es una ONG donde se atiende a personas con demencia o distintas capacidades. Si quieres colaborar con una donación:

    https://www.alpentocht.nl/2023/deelnemers/A01027

  • Configurar el toque con dos dedos en el panel táctil (Debian)

    Vamos con otra chuleta para Debian.

    Últimamente estoy usando KDE/Plasma(X11) en mi Debian GNU/Linux y me dí cuenta que el púntero no desplazaba (scroll) el contenido arriba o abajo en las ventanas al usar dos dedos en el panel táctil.

    En mi caso, fue instalar éste módulo lo que solucionó el problema:

    sudo apt install xserver-xorg-input-multitouch

    Por último, reiniciar el escritorio para que hiciera efecto.


    (Enable Multi Touch in Debian with KDE and Plasma)

  • Instalar GNU/Linux en un Windows 10

    Tengo un Windows 10 en la partición de un portátil antiguo.

    El requisito para ejecutar una distribución embebida de GNU/Linux es: Instalar el Subsistema de Windows para Linux

    Te recomiendo seguir este artículo donde explica los prerequisitos.
    https://docs.microsoft.com/es-es/windows/wsl/install-win10

    Uno de ellos es pertenecer al Insider Program de Windows. Si no puedes hacerlo desde la configuración, puede que lo más rápido sea bajarte la ISO, montarla, y ejecutar el Setup:

    https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewadvanced

    Caveat: He leído que esto activa la telemetría de información hacia Microsoft.

Creative Commons License
Except where otherwise noted, the content on this site is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.