# Apagado Seguro de Instalacion Este proyecto pretende brindar las herramientas para poder ejecutar un apagado ordenado y seguro de una instalacion basandose en la monitorizacion de la red de alimentacion y el estado de una bateria de respaldo, a traves de la informacion que transmite el Cerbo GX de Victron Energy y con HomeAssistant como coordinador. ## Resumen del proceso de apagado y encendido Desde homeassistant se monitoriza los datos que brinda el Cerbo y el Multiplus (inversor) de Victron. Principalmente fijandose en 2 datos concretos, la carga de la bateria y el estado de la red de alimentacion. La automatizacion de apagado tiene 2 fases. En la primera, la raspi se encarga de apagar los datalogger, equipos de servicio secundarios como raspis de dinamica, NVR o similar y parar la base de datos. Esto permite que la sincronizacion con nuestro servidor no se rompa de forma inesperada. Esta primera fase se dispara cuando se cumplan las siguientes condiciones simultaneamente: - No hay alimentacion - La carga de la bateria esta por debajo del primer umbral Tras esta primera fase, la raspi de estatica, que es la que gestiona todo, se mantiene encendida mientras la bateria no baje de un segundo umbral. Esto da la opcion de reencender el sistema si vuelve la tension. De esta forma cuando la bateria vuelva a un nivel estable se ejecutaria una automatizacion de encendido. Empezando por la base de datos, seguido de volver a dar tension al resto de equipos encendiendo los Shellys. En caso de que la carga siguiese bajando, al llegar a un segundo umbral, se dispararia la segunda fase. El objetivo principal de esta es apagar la raspi de estatica de forma segura. Para ello el homeassistant dispara un script de apagado que revisa que se haya ejecutado la fase 1 (si no lo ha hecho lo hace ahora), sincroniza los discos y ordena el poweroff del sistema. A parte de eso, el Cerbo GX cortocircuita su rele 1, que controla el Shelly que corta la alimentacion de la Raspi, con un delay de 60s para dar tiempo a la automatizacion de homeassistant a completarse. De forma similar a como lo haria la raspi, el Cerbo desactivara el rele una vez la bateria vuelva a tener carga suficiente; cerrando de nuevo el Shelly, dando alimentacion a la raspi y disparando la automatizacion de encendido. ![Esquema de fases](/docs/images/esquema_eventos.png) ## Descripcion detallada del proyecto ### Arquitectura ![Esquema de Arquitectura](/docs/images/esquema_arquitectura_instalacion.png) ### Fase 1 - Apagado de dataloggers, equipos de servicio y BDD El objetivo principal de esta primera fase es apagar todos los equipos que escriban en la base de datos y cerrar la misma de forma segura para evitar fallos de sincronizacion. Una vez superado el umbral se ejecuta la autoamtizacion `apagado ordenado` de homeassistant. El proceso es el siguiente: 1. Homeassistant apaga los relés Shelly que controlan la alimentacion de los arduinos. 2. Homeassistant lanza el comando `touch /shutdown-signal/apagar` que crea el archivo `apagar` en la ruta `/shutdown-signal/` del contenedor que está vinculada con la ruta `/opt/shutdown-signal/` del host. Este archivo funciona como flag o señal para iniciar el proceso de apagado en el host. 3. En el host está el script [shutdown-watcher.sh](/scripts/shutdown-watcher.sh) corriendo como servicio. Este script monitoriza la ruta donde homeassistant genera el archivo de señal y en funcion del nombre del archivo generado ejecuta un script u otro. 4. La creacion del archivo `apagar` desencadena la ejecucion del script [orchestrate-shutdown.sh](/scripts/orchestrate-shutdown.sh) 5. Este script empieza ejecutando un segundo script [service-nodes-shutdown.sh](/scripts/services-nodes-shutdown.sh) encargado de conectarse a una lista de equipos de servicio por ssh y ejecutar un poweroff en estos. 6. Despues se ejecuta el script [mariadb-shutdown.sh](/scripts/mariadb-shutdown.sh) que para el contenedor de `mariadb`, es decir la base de datos. Esto asegura que los procesos de la misma se finalizan y la sincro se pausa sin errores. 7. Despues de 30s se corta la alimentacion de los equipos de servicios apagando los Shellys correspondientes. > [!NOTE] Todos los script tienen una funcion de log que permite ver si se han > ejecutado correctamente. > El archivo de log esta en la ruta `/var/log/safe-shutdown.log` Con eso acabaria la primera fase de apagado. Mientras no se sobrepase el segundo umbral la Raspi y el homeassistant se mantendra encendido monitorizando la alimentacion para poder reiniciar todos los equipos si se volviese a un estado estable por encima del primer umbral. ### Fase 2 - Apagado total Esta fase es practicamente un clon de la primera (se reejecuta todo por si no se hubiese ejecutado previamente) con el añadido de parar el homeassistant, sincronizar los discos de la raspi y apagar la misma. Para poder cortar la alimentacion de la Raspi una vez esta ya está apagada haremos uso de la funcion de control de generador de respaldo del Cerbo GX de Victron. Con esta podremos controlar un relé que mande una señal de apagado al Shelly que corta la alimentacion de la Raspi con un retardo de 60s para asegurar que el script de apagado ya haya finalizado. De esta forma el proceso seria el siguiente: 1. Homeassistant apaga los relés de los arduinos. 2. Homeassistant crea el archivo `apagado_total`. 3. Se ejecuta el script [orchestrate-total-shutdown.sh](/scripts/orchestrate-total-shutdown.sh) 4. Este ejecuta [service-nodes-shutdown.sh](/scripts/service-nodes-shutdown.sh) y [mariadb-shutdown.sh](/scripts/mariadb-shutdown.sh) 5. Para el homeassistant, sincroniza los discos y ordena el poweroff. 6. El Cerbo GX cuando detecta la bajada de bateria espera 60s y cortocircuita el relé 1 cuya salida normalmente abierta (NA) esta conectada a la entrada del Shelly que controla la alimentacion. La salida del Shelly estará invertida respecto a su entrada de forma que cuando reciba una señal positiva se apague. Hecho esto la reinicializacion dependerá integramente del Cerbo GX que desactivara la salida del rele 1 una vez la bateria vuelva a un nivel estable. Esto encendera la raspi, la cual a su vez iniciara el proceso de encendido ordenado ya que la bateria deberia estar por encima del primer umbral. ### Encendido Ordenado De forma similar al resto esta es una automatizacion que se ejecuta una vez la bateria supera el umbral establecido para el encendido, en este caso en sentido positivo. De nuevo se crea un archivo de señal con el nombre de `encender` que desencadena la ejecucion del script [orchestrate-startup.sh](/scripts/orchestrate-startup.sh). El proceso quedaria asi: 1. Homeassistant crea el archivo `encender`. 2. Se ejecuta [orchestrate-startup.sh](/scripts/orchestrate-startup.sh) que comprueba el estado de la base de datos iniciandola si no lo está. 3. Pasados 30s se encienden los Shellys de la instalacion devolviendo la alimentacion tanto a los equipos de servicio como a los arduinos. El encendido de estos deberia ser automático. Este encendido ordenado permite que la base de datos ya este activa antes de que el resto de equipos empiece a enviar datos evitando la perdida de la primera lectura. ## Despliegue ### Requisitos Software para el control y monitorizacion de procesos: - Systemd - Docker - Homeassistant - inotify-tools - Scripts del proyecto Para la conexion entre nodos: - Clave SSH sin passphrase generada en el nodo principal (raspi estatica) con su respectiva clave publica autorizada en cada nodo de servicio. Hardware: - Sistema de baterias de Victron con inversor y Cerbo - Relés con integracion en homeassistant (Shellys) ### Instalación > [!NOTE] > Comprobacion rapida de los archivos con sus permisos correspondientes: > ```bash > ls -l /usr/local/sbin/db-clean-stop.sh \ > /usr/local/sbin/shutdown-service-nodes.sh \ > /usr/local/sbin/orchestrate-shutdown.sh \ > /usr/local/sbin/orchestrate-startup.sh \ > /usr/local/sbin/orchestrate-full-shutdown.sh \ > /usr/local/sbin/shutdown-watcher.sh > ls -l /etc/systemd/system/shutdown-watcher.service > which inotifywait || sudo apt install inotify-tools > ``` #### Scripts Todos los scripts deben ir instalados en la carpeta `/usr/local/sbin/` con permisos de ejecucion. En caso de que los scripts no esten ya instalados podremos instalarlos copiandolos a la maquina y lanzando el siguiente comando: ```bash sudo install -m 755 /usr/local/sbin/ ``` #### Clave SSH El script de `service-nodes-shutdown.sh` se conecta por SSH sin contraseña a los distintos equipos de servicio. Para ello hace falta generar una clave SSH en el nodo principal (raspi de estatica) e instalar la clave publica correspondiente en cada nodo de servicio. Generar clave SSH en el nodo principal: ```bash sudo ssh-keygen -t ed25519 -f /root/.ssh/id_shutdown -N "" -C "shutdown-orchestrator" sudo ls -l /root/.ssh/id_shutdown # debe ser -rw------- (600), propietario root ``` Instalar clave publica en un nodo (desde el principal): ```bash sudo ssh-copy-id -i /root/.ssh/id_shutdown.pub USER_DEL_NODO@IP_DEL_NODO ``` Comprobacion (debe devolver el hostname del nodo de servicio): ```bash sudo ssh -i /root/.ssh/id_shutdown shutdown-user@IP_DEL_NODO 'hostname' ``` #### Carpeta de señal y volumen de Docker Los archivos de señal se generan en la carpeta `/opt/shutdown-signal`, sino existe hay que crearla: ```bash sudo mkdir -p /opt/shutdown-signal ``` Para que homeassistant pueda escribir en ella hay que montarla como volumen del contenedor en el `compose.yaml` ```yaml homeassistant: ... volumes: - ... - /opt/shutdown-signal:/shutdown-signal ``` Despues de añadirlo recrea el volumen: ```bash docker compose up -d homeassistant # debe decir "Recreating" ``` #### Shell Commands de Homeassistant Los comandos de shell que crean los archivos que sirven como señal para el watcher se definen en la configuracion de homeassistant: ```yaml # configuration.yaml shell_command: trigger_shutdown: touch /shutdown-signal/apagar trigger_total_shutdown: touch /shutdown-signal/apagado_total trigger_startup: touch /shutdown-signal/encender ``` #### Activar el Watcher El servicio del watcher `shutdown-watcher.service` debe ir con permisos de lectura y escritura en la carpeta de systemd `/etc/systemd/system/`. Si no esta instalado instalar: ```bash sudo install -m 644 shutdown-watcher.service /etc/systemd/system/shutdown-watcher.service ``` Para activarlo en systemd: ```bash sudo systemctl daemon-reload sudo systemctl enable --now shutdown-watcher.service sudo systemctl status shutdown-watcher.service # debe salir "active (running)" ``` #### Estructura final de archivos De esta forma los archivos correspondientes a este proyecto quedarian de la siguiente forma: ```bash # Servicio del watcher /etc/systemd/system/ └── shutdown-watcher.service # Carpeta que monitoriza el watcher /opt/shutdown-signal/ # Homeassistant /.../servidor-campo/ ├── compose.yaml └── homeassistant/ └── config_ha/ └── configuration.yaml # Clave SSH /root/.ssh/ ├── id_shutdown └── id_shutdown.pub # Scripts /usr/local/sbin/ ├── mariadb-shutdown.sh ├── orchestrate-shutdown.sh ├── orchestrate-startup.sh ├── orchestrate-total-shutdown.sh ├── service-nodes-shutdown.sh └── shutdown-watcher.sh ``` ### Configuracion Una vez este todo instalado hay distintas configuraciones a realizar en funcion de la instalacion. #### Automatizaciones Homeassistant Como minimo habra que configurar los reles a apagar o encender. Tambien pueden variar los umbrales, triggers y delays. Todo esto se puede configurar desde la seccion de `/configuracion/automatizaciones_y_escenas/` de la web de Homeassistant. Ejemplos - [apagado_ordenado_fase1](/docs/examples/apagado_ordenado_fase1.yaml.example) - [apagado_total_fase2](/docs/examples/apagado_total_fase2.yaml.example) - [encendido_ordenado](/docs/examples/encendido_ordenado.yaml.example) #### IP-s nodos de servicio - service-nodes-shutdown.sh En la cabecera de [service-nodes-shutdown.sh](/scripts/service-nodes-shutdown.sh) en el array `NODES` se definen el usuario, IP y comando para el apagado de los distintos nodos de servicio con el siguiente formato: `user@IP|command` ```bash # service-nodes-shutdown.sh NODES=( "pi@192.168.1.219|sudo /usr/sbin/poweroff" # Raspi Dinamica "root@192.168.1.50|/sbin/poweroff" # NVR ) ``` #### Cerbo y Shelly del nodo principal Para el apagado completo debemos encender y configurar la funcion de `Arranque/parada del generador` del rele 1 del Cerbo GX. Desde su interfaz remota: - Habilitar: `/Ajustes/Integraciones/Reles/Funcion (Rele 1)/Arranque/parada del generador` ![Configuracion Cerbo GX](/docs/images/ConfigCerbo.png) - Configurar: `/Ajustes/Dispositivos/Grupo Electrogeno/` - Funcion de arranque automatico -> ON - Ajustes/Condiciones/Estado de carga de la bateria -> Definir umbrales y retardos ![Umbrales Cerbo GX](/docs/images/UmbralesCerbo.png) > [!WARNING] > Esta funcion controlara la alimentacion del nodo principal cortando cualquier > proceso que se pueda estar ejecutando en el mismo. Conviene definir un > retardo suficientemente amplio para que el proceso de apagado total finalice > correctamente. Una vez cofigurado esto debemos conectar la salida NA del rele 1 del Cerbo a una entrada del Shelly y configurar la accion de la misma en este: - OUT Input/Output settings: - Input mode -> Switch - Output type -> Toggle - IN Invert -> ON > [!CAUTION] > La funcion de Arranque/Parada del generador de Cerbo esta pensada para encender un > generador cuando la bateria baje de un umbral pero nosotros lo usamos justamente > para lo contrario, apagar el nodo principal, es por esto que la entrada del > Shelly se invierte.