ParadoxAlarmInterface / ParadoxAlarmInterface/pai

[Bug] ValueError: hour must be in 0-23 range in adapters.py v3.7.0 - Spectra/Magellan parsing

Open
#554 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug mg protocol to be confirmed
Dominant language
Python
Stars
424
Forks
118
PR merge metrics
No merged PRs in 30d

Description

GitHub Issue Report: PAI Paradox Alarm Interface - ValueError en parsing de fecha/hora

🐛 Descripción del Bug

PAI versión 3.7.0 está generando errores de ValueError al intentar parsear mensajes de eventos en vivo del panel Paradox, específicamente cuando intenta crear objetos datetime con valores de hora inválidos.

📋 Información del Entorno

Sistema Home Assistant
  • Método de instalación: Home Assistant OS
  • Core: 2025.7.1
  • Supervisor: 2025.06.2
  • Operating System: 15.2
  • Frontend: 20250702.1
PAI Configuration
  • Versión PAI: 3.7.0 (actualizado recientemente)
  • Panel: Paradox Spectra/Magellan (basado en el stack trace)
  • Conexión: [NECESITA CONFIRMACIÓN - Serial/IP/Ethernet]

🔥 Error Completo

2025-07-09 16:41:30,494 - ERROR    - PAI.paradox.hardware.spectra_magellan.panel - Exception parsing message: b'e219070910280011000000000000476172616a652031372020202020202000000000001a20'
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/paradox/hardware/spectra_magellan/panel.py", line 173, in parse_message
    return parsers.LiveEvent.parse(message)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 308, in parse
    return self.parse_stream(io.BytesIO(data), **contextkw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 320, in parse_stream
    return self._parsereport(stream, context, "(parsing)")
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 332, in _parsereport
    obj = self._parse(stream, context, path)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 2000, in _parse
    subobj = sc._parsereport(stream, context, path)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 332, in _parsereport
    obj = self._parse(stream, context, path)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 2489, in _parse
    return self.subcon._parsereport(stream, context, path)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 332, in _parsereport
    obj = self._parse(stream, context, path)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 4368, in _parse
    obj = self.subcon._parsereport(stream, context, path)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 332, in _parsereport
    obj = self._parse(stream, context, path)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 2000, in _parse
    subobj = sc._parsereport(stream, context, path)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 332, in _parsereport
    obj = self._parse(stream, context, path)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 2489, in _parse
    return self.subcon._parsereport(stream, context, path)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 332, in _parsereport
    obj = self._parse(stream, context, path)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/construct/core.py", line 719, in _parse
    return self._decode(obj, context, path)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/paradox/hardware/spectra_magellan/adapters.py", line 9, in _decode
    return datetime.datetime(obj[0] * 100 + obj[1], obj[2], obj[3], obj[4], obj[5])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: hour must be in 0..

🔍 Análisis del Error

Mensaje Raw Parseado
b'e219070910280011000000000000476172616a652031372020202020202000000000001a20'
Ubicación del Error
  • Archivo: /usr/local/lib/python3.11/site-packages/paradox/hardware/spectra_magellan/adapters.py
  • Línea: 9
  • Función: _decode()
Problema Identificado

El error ocurre cuando PAI intenta crear un objeto datetime.datetime() en la línea:

return datetime.datetime(obj[0] * 100 + obj[1], obj[2], obj[3], obj[4], obj[5])

Los valores extraídos del mensaje del panel están produciendo un valor de hora (obj[4]) que es ≥ 24, lo cual es inválido para datetime.datetime().

🔄 Reproducibilidad

  • Frecuencia: Ocurre de forma intermitente
  • Desencadenante: Eventos de alarma del panel Paradox
  • Momento: Aparentemente cuando el panel envía eventos en vivo
  • Versión anterior: El problema comenzó después de actualizar a PAI 3.7.0

💡 Posibles Causas

  1. Configuración de hora en panel: El panel podría estar configurado en formato 12h y enviando valores AM/PM que PAI interpreta incorrectamente
  2. Zona horaria: Problemas de conversión de zona horaria
  3. Parsing de formato: Cambios en el protocolo de parsing en v3.7.0
  4. Bug de regresión: Nuevo bug introducido en la versión 3.7.0

🛠️ Solución Temporal Sugerida

Validación en adapters.py
def _decode(self, obj, context, path):
    # Validar y limitar valores antes de crear datetime
    year = obj[0] * 100 + obj[1] if obj[0] < 100 else obj[0]
    month = max(1, min(12, obj[2]))
    day = max(1, min(31, obj[3]))
    hour = max(0, min(23, obj[4]))  # Limitar hora a 0-23
    minute = max(0, min(59, obj[5]))  # Limitar minutos a 0-59
    
    return datetime.datetime(year, month, day, hour, minute)

📊 Información Adicional Necesaria

Para ayudar en el diagnóstico, por favor proporciona:

  1. Modelo exacto del panel Paradox
  2. Configuración de fecha/hora del panel (12h/24h, zona horaria)
  3. Método de conexión (Serial, IP, etc.)
  4. Configuración PAI (archivo de configuración relevante)
  5. ¿Funcionaba correctamente en versión anterior? (¿cuál?)

🎯 Comportamiento Esperado

PAI debería:

  1. Parsear correctamente todos los mensajes de eventos del panel
  2. Manejar graciosamente valores de fecha/hora inválidos
  3. Registrar warnings en lugar de errores fatales para parsing fallido
  4. Continuar operando sin interrupciones

📋 Checklist para Desarrolladores

  • Revisar cambios en adapters.py entre v3.6.x y v3.7.0
  • Añadir validación de valores de fecha/hora antes de crear datetime
  • Implementar logging detallado del parsing de mensajes
  • Considerar modo de compatibilidad para paneles antiguos
  • Añadir tests unitarios para casos de valores extremos

🔗 Enlaces Relevantes

#v3.7.0

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with paradox/hardware/spectra_magellan/adapters.py and the _decode() function at line 9, then compare the date/time parsing changes between v3.6.x and v3.7.0. Reproduce the failure with the reported raw message and verify the panel protocol before deciding how invalid values should be handled. Done means live event parsing no longer raises this ValueError and extreme date/time cases have regression coverage.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.