336 lines
14 KiB
Markdown
336 lines
14 KiB
Markdown
# 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:
|
|
|
|
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/service-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 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:
|
|
|
|
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 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](/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 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:
|
|
> ```bash
|
|
> 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:
|
|
```bash
|
|
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:
|
|
```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 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:
|
|
```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`
|
|

|
|
- Configurar:
|
|
`/Ajustes/Dispositivos/Grupo Electrogeno/`
|
|
- Funcion de arranque automatico -> ON
|
|
- Ajustes/Condiciones/Estado de carga de la bateria -> Definir umbrales y retardos
|
|

|
|
|
|
> [!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.
|