Punto de carga para vehículo eléctrico (protocolo OCPP)

Hola,

Un tema más en modo discusión en primer lugar para tomar la temperatura: ¿le interesaría a alguien una integración « Punto de carga de vehículos »?

Varias preguntas surgen luego de este proyecto:

  • ¿Pero para qué? En primer lugar, creo que sería principalmente para el « consumo » de datos… pero tal vez no sea suficiente?
  • ¿Pero qué tipo de integración?
    • Completamente integrada a Gladys: Gladys lleva el código de su lado… no estoy seguro de que sea una excelente idea, pero ¿por qué no en absoluto? Tal vez sea el más integrado al final?
    • En modo ocpp2mqtt: un poco como zigbee y zwave: nos apoyamos en otro proyecto que actúa como CSMS y publica los mensajes en un broker MQTT. El Broker también puede servir para enviar comandos al punto de carga. En este modo, el punto de carga ya no se comunica con el servidor en la nube nativo del punto de carga
    • En modo Relay 2 mqtt: en este modo, un programa actúa como intermediario para transmitir los mensajes en el broker MQTT mientras deja pasar los mensajes a la nube nativa. Gladys solo puede, en principio, recibir mensajes, no enviarlos al punto de carga (en absoluto sí, pero desincronizado con el CSMS en la nube… no estoy seguro de los impactos).
    • ¿A través de node-red? En cuyo caso no hay nada que hacer realmente en Gladys, más una cuestión de tutorial? (Acabo de pensar en esta solución mientras escribía el mensaje, lo reconozco)

He comenzado algunas primeras investigaciones, aún tengo un poco de dificultad para identificar todo lo que podríamos hacer con el protocolo (sabiendo que existen 2/3 versiones de este). Recibir datos, parece más o menos bien. Es más en el envío de comandos donde no he profundizado en lo que se puede hacer, pero en la idea, ¿por qué no? De ahí este post en realidad: ¿están interesadas las personas? ¿Qué información se puede subir? ¿Para enviar qué comandos?

Para las diferentes opciones, hay más o menos diferentes maneras de proceder:

Eso es todo, no tengo respuestas, no tengo una solución completamente clara aún… vengo a tomar la temperatura para ver si hay interés o no.

¡Hola @Sescandell!
Estoy seguro de que esto le interesaría a mucha gente, y creo que es un excelente candidato para futuras integraciones externas en Gladys :blush:

Hola,

Vamos a por ello con la idea de probar este enfoque. Incluso en un simple POC en un primer momento.

Tengo un dispositivo disponible… Voy a empezar a explorar lo que es factible fuera de todo Gladys en un primer momento para familiarizarme con todo esto.

Si alguien tiene conocimiento de este protocolo, hacedme una señal, estoy interesado :wink:

Esa es una idea valiosa. En lugar de integrarla completamente en Gladys de inmediato, conectarse mediante OCPP-to-MQTT podría ser más práctico; facilita las pruebas y permite la implementación inicial de funciones como el estado de carga, la potencia de salida, los niveles de energía y el control de inicio/parada.

Se puede considerar una integración nativa más profunda una vez que se aclaren los requisitos de uso específicos.

Pequeño estado de avance (voy con cuidado con esto, no tengo muchas ganas de quemar el cargador… ni el coche… y mucho menos la casa :smiley: )

De momento, tengo un bucle relativamente simple, fuera de Gladys. Pero gracias al proyecto GitHub - gyzod/ocpp2mqtt: OCPP <==> MQTT Gateway · GitHub & GitHub - ocpp-balanz/ocpp-2w-proxy: A 2 way OCPP proxy · GitHub he podido montar una interfaz web capaz de mostrarme en tiempo real el estado de mi cargador.
La idea del proyecto ocpp-2w-proxy es, como su nombre indica, interponerse como proxy (una especie de hombre en el medio) entre el cargador y el servidor en la nube nativo.

Esto permite conservar el control mediante la aplicación nativa. En mi caso, he comprobado que mi aplicación Autel Charger sigue siendo 100% funcional (de lo que he podido probar hasta ahora…). Mi MQTT también recibe todos los mensajes. Esto permite actualizar una interfaz web falsa por el momento.

Mi problema está en el inicio de una carga. El cambio de configuración, el apagado, el refresco: todo funciona. Pero iniciar una recarga, por el momento estoy bloqueado.

Quizás un primer paso será ver el estado del cargador. Podremos investigar después qué falla.

Donde también tengo algunas reservas es que ha sido necesario modificar el código fuente de los proyectos referenciados para que funcione. Voy a volver a verificar este punto, puede que sea un error por mi parte.

Nada relacionado con Gladys por el momento, pero una vez que estoy seguro de que está bien: ¡vamos con el plugin! :wink:

Si yo fuera tú, lanzaría a Claude sobre el tema con toda la información de este post :slight_smile:

En 30 minutos tienes una integración externa Gladys que tiene muchas posibilidades de funcionar desde el primer intento, probable en 1 clic en Gladys, y puedes iterar a partir de ahí.

De principio a fin, creo que hoy en día una integración externa es menos de una hora de trabajo, sin necesidad de entrar en la API ni en el código.

Por mi parte, los resultados que obtengo son realmente limpios, a menudo superiores al trabajo que habría hecho un desarrollador humano, ya que todos los casos extremos están bien gestionados, vale la pena intentarlo :smiley:

No es tanto un problema de rapidez o de manejo de las APIs: aún no es ese paso (ese punto no me preocupa, será tratado rápidamente por IA).

El tema aquí es entender bien la herramienta que ponemos alrededor y entender/controlar lo que se hace: las capacidades y la organización entre occp-2w-prxy y ocpp-2mqtt (¿y si son las herramientas adecuadas, por cierto? Por ejemplo, la limitación de inicio, me pregunto si el plugin nativo de HA tiene el mismo problema o no: lbbrhzn/ocpp: Integración de Home Assistant para cargadores de vehículos eléctricos que soportan el Protocolo de Punto de Carga Abierto (OCPP).)

Eso es lo primero. Una vez que todo esto esté claro, creo el plugin Gladys, creo que irá rápido :wink:

@Sescandell ¿Por qué usar ocpp-2w-prxy y ocpp-2mqtt?

¿No podría la IA reescribir directamente toda esta pila en la integración de Gladys? :slightly_smiling_face: Así evitaríamos depender de estos proyectos externos, manteniendo el control de la implementación, las actualizaciones y las correcciones de errores. También ofrecería más flexibilidad a largo plazo, ¿no?

Era una de las pistas posibles también mencionadas en el post inicial. ¿Estamos de acuerdo en que cuando dices « toda esta pila en Gladys » seguimos en la idea de un « plugin externo a través de la API »?

La pregunta se reduce a por qué buscar rediseñar algo que ya existe. Exagero, pero en resumen, preguntas: ¿por qué elegir zigbee2mqtt en lugar de rediseñarlo? Si hay soluciones en el mercado que hacen el trabajo, ¿por qué querer reimplementarlas? ¿Interpreto mal la pregunta?

Si estos dos proyectos hacen el trabajo, mejor no privarse de ellos. Si son limitantes, miraré para una implementación casera. En absoluto, casi tengo ganas de decir, como « plugin externo » es un « detalle de implementación »?

Todavía no tengo una opinión clara sobre la cuestión. En lo que a mí respecta, sigo en fase de exploración sobre el campo de lo posible. Creo que este fin de semana me pondré a trabajar en este punto para impulsar una integración.

Sí, esa es la pregunta. :slightly_smiling_face: Pero justo cuando miro ocpp-2mqtt, veo un proyecto relativamente simple y que evoluciona poco.

El repositorio tiene solo 90 commits, y una gran parte son actualizaciones de documentación o de CI. Al final, no hay mucha lógica de negocio.

ocpp-2w-proxy es aún peor, solo 19 commits, última actualización hace 5 meses.

Es típicamente el tipo de proyecto que una IA puede reescribir hoy en unos treinta minutos. Así nos evitamos una dependencia de un proyecto externo que evoluciona poco, manteniendo el control del código y la posibilidad de hacerlo evolucionar o corregir rápidamente los errores.

En contraste, Zigbee2MQTT es una escala completamente diferente: más de 6.400 commits, cientos de contribuyentes y un desarrollo muy activo. Aquí hay una verdadera experiencia acumulada y una enorme base de compatibilidad con los dispositivos Zigbee. En este caso, es mucho más pertinente apoyarse en su trabajo en lugar de querer reimplementar todo.

No he descartado esa posibilidad. Lo pensaba en modo fork, pero se puede imaginar en modo « desde cero ».
Estoy probando la solución HA, para ver si el problema que identifico es propio de mi terminal o de la librería, y lo vemos :+1: :+1: :+1:

El sistema está tomando forma

Pero tengo que revisar el funcionamiento y la gestión de la configuración.
Voy a avanzar en esto durante el fin de semana :wink:

¿Así que te has pasado al modo contenedor adicional? Francamente, creo que es claramente exagerado, podrías haberlo hecho de forma nativa, es una pena tener una dependencia :slight_smile:

También me hubiera gustado no necesitarlo. Pero, o me estoy perdiendo algo en la documentación, o no estás completamente al tanto de cómo funciona OCPP.
Para la integración de OCPP, necesitamos que haya disponible un nuevo Websocket. Los cargadores se conectan a este Websocket. La idea de la integración aquí es actuar como un Man In The Middle para poder ver qué está pasando. Si no: es un completo misterio.

De la documentación, leo tres cosas:

  • los campos del manifiesto: que no hablan de capacidad de exposición de puertos
  • el modelo de seguridad que explica que el Docker vive en una red aislada
  • los contenedores acompañantes: que están ahí para poder (entre otras cosas) hacer los puentes de protocolo… para mí estamos típicamente en este caso

Por lo tanto, o me estoy perdiendo una información, el contenedor principal puede abrir perfectamente puertos y hacerlos disponibles en la red, y en ese caso te sigo, dime cómo hacerlo y lo modifico sin ningún problema. O no es posible y, por lo tanto, no es exagerado :wink:

Tienes razón, he dicho una tontería :smiley:

He revisado la especificación: el contenedor principal de una integración externa no tiene intencionalmente ningún puerto publicado, su único canal de entrada es el WebSocket saliente hacia Gladys. Los puertos publicados solo existen en los subcontenedores declarados en containers[]. Por lo tanto, para OCPP, donde es la estación de carga la que se conecta como cliente WS, el contenedor compañero es la única opción hoy en día. ¡Nada exagerado entonces :smiley:

Después, no te obliga a usar una imagen de terceros en el subcontenedor, containers[].docker_image también acepta la tuya. ¡Puedes declarar un subcontenedor que ejecute tu propio servidor OCPP si alguna vez quieres limitar las dependencias externas!

Efectivamente, es lo que he implementado: GitHub - sescandell/gladys-ocpp-integration: Gladys OCPP EV Charger External integration. · GitHub

¡Perfecto! :raising_hands:

Si alguna vez notas limitaciones en el sistema actual, no dudes en decírmelo, todo puede evolucionar :slight_smile:

Hola @pierre-gilles, tengo una pregunta/observación,

Estoy « limitado » en la capacidad de integración de la funcionalidad a través del SDK. Y la experiencia del usuario podría no ser completamente satisfactoria.

Mi problema está en la parte de « Descubrimiento » / « Configuración » / « Acciones ».

Pequeña explicación sobre el funcionamiento de OCPP: los usuarios deben modificar la URL a la que se conecta su estación de carga (desde su aplicación nativa en la nube de la plataforma). Al hacerlo, la estación espera naturalmente una respuesta del endpoint al que se conecta. El objetivo de la integración es que la aplicación nativa del usuario siga siendo utilizable. La integración actúa como un RELAY. Observa lo que pasa, transmite la información útil a Gladys, y reenvía el mensaje al servidor en la nube original.

Y ese es el tema. Necesito un medio para, desde la interfaz de integración, poder decir « Esta estación de carga debe apuntar a este servicio en la nube ». Lo que hago hoy es que la integración muestra la URL a ingresar en la aplicación para que la estación apunte a Gladys. Responde con datos « ficticios » para que la estación siga conectada. Así, la integración « conoce la identidad de la estación de carga ».

La idea sería poder configurar esta estación conectada (definir la URL en la nube desde Gladys). Excepto que, a menos que me falte información en la documentación, no tengo ningún medio de « presentar las estaciones descubiertas y actuar sobre las configuraciones ».

Hoy, lo único que puedo hacer es una Acción que solicita el ID de la estación + URL en la nube. Pero no está vinculado a las « estaciones identificadas ». Es estático. Funciona… pero no es lo ideal. El ID debe buscarse en los registros del contenedor compañero. No es lo más sencillo (aunque tengo en mente la información de los IDs disponibles). ¿Entiendes lo que estoy tratando de explicar?

¿Crees que podríamos trabajar en este punto (puedo imaginar una V1 del plugin - sujeto a fusionar también la PR dedicada en el núcleo sobre las nuevas CATEGORÍAS y TIPOS) con un modo de configuración « por acciones », pero claramente hay algo que hacer, diría.

¿Alguna opinión al respecto?

Si no soy claro, dime, reformularé con diagramas :slight_smile:

¡Gracias!

Hola @Sescandell,

Gracias por este retorno detallado, es exactamente el tipo de caso concreto que nos ayuda a hacer evolucionar el SDK.

Por otro lado, creo que hay un malentendido sobre lo que el SDK ya permite, porque tu caso normalmente está cubierto sin tener que leer los logs del contenedor:

1. En el momento en que un terminal se conecta a tu servidor OCPP, conoces su ID (está en la URL de conexión). En ese instante, puedes publicarlo a través de POST /discovered_device. Aparece entonces en la pestaña « Descubrimiento » de tu integración, con su nombre, y el usuario solo tiene que hacer clic en « Crear ». Es el mismo patrón que las integraciones internas (Zigbee2MQTT, por ejemplo), y tu caso es incluso más simple que un escaneo de red ya que el descubrimiento es entrante: el terminal viene a ti.

2. Para la configuración por terminal (la URL de la nube del fabricante a relajar), puedes declarar una acción en tu manifiesto con un campo select que tiene « source »: « devices ». El formulario se llena automáticamente con los dispositivos de tu integración (label = nombre del terminal), y recibes el external_id elegido como cualquier valor de campo. El usuario elige su terminal en una lista, nunca copia un identificador.

3. Y cuando vuelves a publicar un terminal ya creado con parámetros actualizados (URL relajada, versión de protocolo detectada, etc.), se actualizan silenciosamente en la base de datos sin tocar el nombre ni las características.

Por lo tanto, el flujo V1 completo es: el terminal se conecta a tu relay, lo publicas en descubrimiento, el usuario lo crea desde la UI, luego configura la URL cloud a través de tu acción con el select. Cero consulta de logs.

Punto de atención visto tu arquitectura: si tu servidor OCPP gira en el subcontenedor, es el contenedor principal de la integración el que posee el token para llamar a la API host. Por lo tanto, tu subcontenedor debe subirle la información de conexión (a través de tu red privada) para que publique el descubrimiento.

Donde tienes razón es que hoy falta una configuración persistente y visible por dispositivo: una acción es write-only, el usuario no ve qué URL está configurada para cada terminal. Es una necesidad que ya habíamos identificado para la fase 2 (acciones a nivel del dispositivo, directamente en su ficha), y tu retorno confirma que la necesidad es real. Pero prefiero que avancemos sobre esto una vez que tu V1 esté lanzada con los bloques actuales, para diseñarlo con perspectiva y otros casos de uso además del tuyo.

Si uno de los tres puntos anteriores no funciona en tu caso, dime, eso significaría que hay un bug o un agujero en la documentación del SDK.

Había pasado por alto la noción de dispositivos de origen. Esto mejorará un poco la experiencia, pero creo que aún quedará algo por mejorar. Lo hago y te digo qué tal queda. El resto ya corresponde a lo que está en marcha.

Gracias, te mantendré informado.