release v1.0
This commit is contained in:
@@ -1,3 +1,335 @@
|
||||
# apagado_seguro
|
||||
# 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.
|
||||
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user