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 (~120s) 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.
Descripcion detallada del proyecto
Arquitectura
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 automatización
apagado ordenado de homeassistant. El proceso es el siguiente:
- Homeassistant apaga los relés Shelly que controlan la alimentacion de los arduinos.
- Homeassistant lanza el comando
touch /shutdown-signal/apagarque crea el archivoapagaren 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. - En el host está el script 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.
- La creacion del archivo
apagardesencadena la ejecucion del script orchestrate-shutdown.sh - Este script empieza ejecutando un segundo script service-nodes-shutdown.sh encargado de conectarse a una lista de equipos de servicio por ssh y ejecutar un poweroff en estos.
- Despues se ejecuta el script 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. - Despues de un retardo (~60s) homeassistant 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 (~120s) para asegurar que el script de apagado ya haya finalizado. De esta forma el proceso seria el siguiente:
- Homeassistant apaga los relés de los arduinos.
- Homeassistant crea el archivo
apagado_total. - Se ejecuta el script orchestrate-total-shutdown.sh
- Este ejecuta service-nodes-shutdown.sh y mariadb-shutdown.sh
- Para el homeassistant, sincroniza los discos y ordena el poweroff.
- El Cerbo GX cuando detecta la bajada de bateria espera dando tiempo al nodo principal a apagarse (~120s) 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.
El proceso quedaria asi:
- Homeassistant crea el archivo
encender. - Se ejecuta orchestrate-startup.sh que comprueba el estado de la base de datos iniciandola si no lo está.
- Pasados 30s homeassistant enciende 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:
ls -l /usr/local/sbin/mariadb-shutdown.sh \ /usr/local/sbin/service-nodes-shutdown.sh \ /usr/local/sbin/orchestrate-shutdown.sh \ /usr/local/sbin/orchestrate-startup.sh \ /usr/local/sbin/orchestrate-total-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:
sudo install -m 755 <script-path> /usr/local/sbin/<script.sh>
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:
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):
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):
sudo ssh -i /root/.ssh/id_shutdown USER_DEL_NODO@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:
sudo mkdir -p /opt/shutdown-signal
Para que homeassistant pueda escribir en ella hay que montarla como volumen
del contenedor en el compose.yaml
homeassistant:
...
volumes:
- ...
- /opt/shutdown-signal:/shutdown-signal
Despues de añadirlo recrea el volumen:
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:
# 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:
sudo install -m 644 shutdown-watcher.service /etc/systemd/system/shutdown-watcher.service
Para activarlo en systemd:
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:
# 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
IP-s nodos de servicio - service-nodes-shutdown.sh
En la cabecera de 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
# 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
- Configurar:
/Ajustes/Dispositivos/Grupo Electrogeno/
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
Note
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.


