Tutorial: Dobór zasilacza UPS do Raspberry Pi i konfiguracja automatycznego wyłączenia

Management Summary
Zasilacz bezprzerwowy podtrzymuje pracę Raspberry Pi po zaniku prądu. W domowych serwerach i automatyce daje czas na zamknięcie plików oraz bezpieczne wyłączenie zamiast nagłego przerwania zasilania. Pojemność baterii stanowi tylko część wyboru: urządzenie musi zasilać cały podłączony sprzęt i odpowiednio wcześnie zgłaszać awarię. Ważny jest również ponowny start, ponieważ powrót prądu nie zawsze uruchamia wyłączone Raspberry Pi, jeśli nadal podłączone jest zasilanie bateryjne.
Spis treści
Zasilacz bezprzerwowy (UPS) musi zasilać Raspberry Pi pod obciążeniem, zgłaszać zanik sieci i zachować energię na uporządkowane zamknięcie systemu. Sama pojemność akumulatora nie odpowiada na żadne z tych trzech wymagań. Znaczenie mają energia dostępna na wyjściu, dopuszczalny prąd szczytowy oraz współpraca UPS z systemem operacyjnym.
Poniższe obliczenie jest przykładem projektowym. Logika wyłączenia wymaga udokumentowanego, zgodnego z Pi zasilacza UPS z sygnałem zaniku sieci zwieranym do masy. Pakiet, ładowarka i układ ochronny muszą odpowiadać konfiguracji dopuszczonej przez producenta.

1. Pomiar całego obciążenia
Moc znamionowa zasilacza określa możliwości dostarczania energii, a nie pobór Pi. Pomiar na wejściu 5 V obejmuje Pi i urządzenia USB zasilane przez to wejście. Miernik musi obsługiwać zastosowane zasilanie USB-C oraz wymagany prąd. Osobno zasilane urządzenia wymagają odrębnego bilansu energii.
Na Pi 5 polecenie vcgencmd pmic_read_adc udostępnia pomiary wewnętrzne. Suma szyn PMIC nie obejmuje jednak poboru USB ani obciążeń podłączonych bezpośrednio do 5 V. Nie jest więc pomiarem całkowitej mocy wejściowej ani ogólną metodą pomiarową dla Pi 4 i Pi 5.
Dobór wymaga pomiaru spoczynku, zwykłej pracy i najwyższego planowanego obciążenia, łącznie z operacjami dyskowymi oraz prądem rozruchowym. Wyjście UPS musi dostarczyć odpowiedni prąd bez niedopuszczalnego spadku napięcia. Duży akumulator nie zastępuje odpowiednio wydajnej przetwornicy.
2. Jawne obliczenie energii i rezerwy
Watogodziny wynikają w przybliżeniu z iloczynu amperogodzin i napięcia znamionowego. Dwa przykładowe ogniwa po 3,4 Ah i 3,7 V dają łącznie 25,16 Wh. Właściwą wartością jest rzeczywiste napięcie znamionowe dopuszczonego pakietu, a nie napięcie końcowe ładowania. Wartość mAh odnosząca się do ogniw nie określa czasu pracy przez USB bez danych o napięciu i przetwarzaniu.
Przykład zakłada 80 procent dostępnej energii ogniw oraz 88 procent sprawności przetwornicy. Pierwszy współczynnik opisuje wybrany przypadek projektowy z uwzględnieniem wieku, temperatury i użytecznego zakresu rozładowania. Żadna z tych wartości nie jest pomiarem uniwersalnym. Dodatkowo 1 Wh na wyjściu pozostaje jako rezerwa na zamknięcie systemu.
E_cells = 2 × 3.4 Ah × 3.7 V = 25.16 Wh
E_output = 25.16 Wh × 0.80 × 0.88 = 17.71264 Wh
E_runtime = 17.71264 Wh − 1 Wh = 16.71264 Wh
t_runtime = E_runtime / P_load| Założone obciążenie | Obliczony czas do rezerwy |
|---|---|
| 6 W | około 2 godz. 47 min |
| 9 W | około 1 godz. 51 min |
| 12 W | około 1 godz. 24 min |
Poziomy mocy są wariantami obliczeń, a nie typowymi konfiguracjami Pi. Przy stałych 12 W energia 1 Wh wystarcza na pięć minut. Założone zamykanie systemu przez 60 sekund zużywa wtedy 0,2 Wh. Rzeczywisty czas wymaga pomiaru z docelowymi usługami, dyskami i możliwymi przekroczeniami czasu oczekiwania.
Użyteczna energia zmierzona już na wyjściu 5 V uwzględnia straty przetwornicy. Ponowne zastosowanie sprawności odjęłoby te same straty drugi raz. Próg zakończenia rozładowania uwzględniony w pomiarze pojemności również nie wymaga kolejnego arbitralnego odliczenia.
3. Zanik sieci i krytyczny stan akumulatora to różne sygnały
Sygnał zaniku sieci pozwala odczekać krótką przerwę. Krytyczny stan akumulatora może natomiast wymagać natychmiastowego zamknięcia systemu. Stałe opóźnienie 60 sekund jest dopuszczalne wyłącznie przy wystarczającej energii na oczekiwanie i zamknięcie, także przy uruchomieniu monitora oraz po kolejnych awariach. Odpowiedni UPS potrzebuje niezależnego układu ochronnego; monitoring właściwy dla urządzenia może zapewniać wcześniejszą ścieżkę awaryjną.
MAX17048 szacuje stan naładowania układu z jednym ogniwem; pokrewny MAX17049 obsługuje dwa ogniwa szeregowe. INA219 mierzy prąd, napięcie i moc, ale sam nie podaje procentowej pojemności akumulatora. Szacowany stan naładowania nie usuwa potrzeby próby pod dużym obciążeniem. Uniwersalny próg 20 procent nie gwarantuje określonego czasu dalszej pracy.
4. Prosty overlay albo monitor z opóźnieniem
Overlay gpio-shutdown generuje zdarzenie wejściowe KEY_POWER. Zamknięcie obsługuje przykładowo systemd-logind. Bez działającego odbiorcy w systemie operacyjnym wyłączenie nie jest gwarantowane, zwłaszcza w każdej fazie rozruchu. Numer GPIO, polaryzacja i połączenie muszą pasować do płytki. Overlay i poniższy monitor nie mogą równocześnie zajmować tej samej linii.
Monitor korzysta z interfejsu Python biblioteki libgpiod 2. Starsza instalacja 1.x nie jest zgodna. Urządzenie GPIO i offset linii wymagają ustalenia za pomocą lokalnych narzędzi GPIO oraz dokumentacji płytki. Fizyczny numer pinu złącza nie jest offsetem linii; gpiochip0 i offset 17 nie są ustawieniami uniwersalnymi.
Założenie elektryczne to udokumentowane wyjście open-drain zgodne z 3,3 V: stan niski oznacza zanik sieci, wysoki obecność sieci, przy wspólnej masie i odpowiednim podciągnięciu. Wyjście open-drain zwiera sygnał do masy albo go zwalnia. Rezystor podciągający utrzymuje zwolniony sygnał na dozwolonym poziomie wysokim. Przerwany przewód może przez podciągnięcie wyglądać jak obecna sieć; przykład nie wykrywa tej awarii. Sygnał 5 V nie może trafić bezpośrednio na GPIO. Inne wyjście wymaga właściwego dopasowania elektrycznego i sprawdzonej logiki.
#!/usr/bin/env python3
import argparse
import math
import subprocess
import time
class OutageTimer:
def __init__(self, delay):
if not math.isfinite(delay) or delay <= 0:
raise ValueError("delay must be positive and finite")
self.delay = delay
self.since = None
self.previous = None
def sample(self, failed, now):
if type(failed) is not bool or not math.isfinite(now):
raise ValueError("invalid sample")
if self.previous is not None and not 0 <= now - self.previous <= 5:
raise RuntimeError("monitoring gap exceeds 5 seconds")
self.previous = now
if not failed:
self.since = None
return False
if self.since is None:
self.since = now
return now - self.since >= self.delay
def monitor(read_failed, delay, action, clock=time.monotonic, sleep=time.sleep):
timer = OutageTimer(delay)
while True:
failed = read_failed() # Read immediately, including at startup.
if timer.sample(failed, clock()):
action()
return
sleep(1)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--chip", required=True)
parser.add_argument("--line", required=True, type=int)
parser.add_argument("--delay", type=float, default=60)
parser.add_argument("--poweroff", action="store_true")
args = parser.parse_args()
OutageTimer(args.delay)
if args.line < 0:
parser.error("line offset must be non-negative")
import gpiod
from gpiod.line import Bias, Direction, Value
settings = gpiod.LineSettings(direction=Direction.INPUT,
active_low=False, bias=Bias.PULL_UP)
with gpiod.request_lines(args.chip, consumer="ups-watch",
config={args.line: settings}) as request:
last = [None]
def read_failed():
value = request.get_value(args.line)
if value not in (Value.ACTIVE, Value.INACTIVE):
raise RuntimeError("unknown GPIO state")
failed = value == Value.INACTIVE # Physical low = mains failure.
if failed != last[0]:
print("UPS mains_failed=" + str(failed), flush=True)
last[0] = failed
return failed
def action():
print("UPS delay reached; poweroff=" + str(args.poweroff), flush=True)
if args.poweroff:
subprocess.run(["/usr/bin/systemctl", "--no-block", "poweroff"],
check=True, timeout=10)
monitor(read_failed, args.delay, action)
if __name__ == "__main__":
main()Pierwszy stan jest odczytywany od razu, więc zanik obecny już przy starcie również uruchamia licznik. Zaobserwowany stan wysoki zeruje czas oczekiwania. Pomiar czasu korzysta z zegara monotonicznego, który mierzy upływ czasu bez skoków wywołanych korektą daty lub godziny systemowej. Odczyty dzieli około sekundy; krótkie zmiany pomiędzy odczytami mogą pozostać niewykryte. Przykład nie dowodzi więc nieprzerwanego zaniku i nie jest zabezpieczeniem czasu rzeczywistego.
Błędy odczytu i zaobserwowane przerwy w próbkowaniu przekraczające pięć sekund kończą proces błędem. Ponowne uruchomienie zeruje licznik, dlatego powtarzające się awarie wymagają alarmu. Bez --poweroff program jedynie zapisuje osiągnięcie progu w dzienniku i kończy działanie. Ten tryb nadaje się do pierwszego kontrolowanego sprawdzenia sygnału, ale nie zleca zamknięcia systemu.
5. Aktywacja usługi po sprawdzeniu sygnału
Sprawdzony skrypt należy zapisać jako /usr/local/lib/ups_watch.py, a poniższą jednostkę jako /etc/systemd/system/ups-watch.service. Plik /etc/ups-watch.conf musi definiować UPS_CHIP ze sprawdzoną ścieżką urządzenia i UPS_LINE ze sprawdzonym offsetem. Zmiany skryptu i konfiguracji powinny wymagać uprawnień administracyjnych. Jednostka jawnie zawiera --poweroff i może wyłączyć komputer.
[Unit]
Description=UPS mains-failure monitor
StartLimitIntervalSec=60
StartLimitBurst=3
[Service]
Type=simple
EnvironmentFile=/etc/ups-watch.conf
ExecStart=/usr/bin/python3 /usr/local/lib/ups_watch.py --chip ${UPS_CHIP} --line ${UPS_LINE} --delay 60 --poweroff
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetSprawdzenie sygnału bez opcji wyłączenia poprzedza ponowne wczytanie konfiguracji systemd i świadomą aktywację usługi. Dodatkowe After=multi-user.target jest tutaj niewłaściwe: wraz z dołączeniem do tego targetu może utworzyć cykl kolejności startu. Ograniczone restarty obsługują błędy przejściowe; trwale niedziałająca usługa wymaga osobnego alarmowania.
6. Wspólna próba zamknięcia i powrotu do pracy
systemctl --no-block poweroff zleca zamknięcie systemu. Wywołanie nie potwierdza zakończenia ani fizycznego odłączenia 5 V. Uzgodnienie wyłączenia pomiędzy UPS a systemem musi pozostawić dostateczny czas. Ustawienia bootloadera zmniejszające pobór po zatrzymaniu nie zastępują tego przebiegu.
PSU_MAX_CURRENT=5000 również nie jest ogólnym ustawieniem UPS. Deklaracja wydajności prądowej nie tworzy zasilania zdolnego dostarczyć 5 A. Zmiany limitu prądu wymagają odpowiednio udokumentowanej konfiguracji sprzętowej.
Próba odbiorcza wymaga sprawdzonej możliwości odtworzenia systemu i kontrolowanego obciążenia. Plan obejmuje krótką i długą przerwę, start bez sieci, niski stan akumulatora, kolejny zanik przed pełnym doładowaniem oraz powrót sieci podczas zamykania i po zamknięciu. Celowa praca produkcyjnego systemu plików aż do zapadnięcia napięcia nie jest potrzebna. Pozostałą energię wyjściową można zmierzyć osobno odpowiednim obciążeniem testowym.
Dzienniki poprzedniego uruchomienia wymagają dostępnej trwałej pamięci. Brak wpisów w journalctl -b -1 nie dowodzi nagłej utraty zasilania; dzienniki przechowywane tylko w pamięci operacyjnej również znikają. Logi, obserwacja zamknięcia i pomiar napięcia wyjściowego wzajemnie uzupełniają dowody.
Starzenie zależy między innymi od chemii ogniwa, temperatury, stanu naładowania i użytkowania. Nie wynika stąd stałe podwojenie trwałości po dowolnym obniżeniu napięcia ładowania. Granice ładowania i rozładowania muszą odpowiadać profilowi dopuszczonemu przez producenta. Powtarzane próby pojemności i zamknięcia w odpowiednim planie konserwacji tworzą podstawę do terminowej wymiany.
Pytania i odpowiedzi
Czy zatrzymane Pi uruchomi się automatycznie po powrocie sieci?
Niekoniecznie. Przy stale aktywnej szynie 5 V nie powstaje nowe zbocze włączenia zasilania. Niezawodny powrót wymaga przewidzianego cyklu wyłączenia i włączenia wyjścia albo zgodnego sterownika wybudzania. Powrót sieci przed odłączeniem wyjścia UPS i po odłączeniu to osobne przypadki testowe.
Czy opóźnienie 60 sekund wystarcza jako ochrona?
Tylko przy potwierdzonej energii na oczekiwanie i pełne zamknięcie systemu. Prawie pusty akumulator może przestać zasilać wcześniej. Układ ochronny, sygnalizacja stanu akumulatora i alarm awarii pozostają potrzebne.
Źródła
- Raspberry Pi: sprzęt, GPIO i układ zasilania PMIC
- Raspberry Pi: konfiguracja
- Raspberry Pi: gpio-shutdown
- libgpiod 2: LineSettings
- libgpiod 2: request_lines
- systemd: kolejność uruchamiania jednostek docelowych
- systemd: przechowywanie dzienników
- Analog Devices: MAX17048 / MAX17049
- Texas Instruments: INA219
- Sandia: akumulatory litowo-jonowe