# Background script for Raspberry Pi and UPSPlus (52pi) for automatic shutdown, UPS status to MQTT, fan control
Runs in the background, launched as cronjob at boot time.
Checks UPS and battery status. Shuts down the Raspberry Pi when battery voltage is under configured threshold.
Can control a fan via a GPIO pin using PWM, depending on CPU temperature.
Can publish UPS status and fan status data to a MQTT broker.
Can send UPS status data to the manufacturer's IOT platform.
a Geekpi UPSPlus EP-0136 (52pi)
python3
additional modules: RPi.GPIO, smbus2, pi-ina219, paho-mqtt, requests
Install python3 if it isn't already installed.
Install additional modules via: pip3 install module-name
Copy fanShutDownUps.py, fanShutDownUps.ini, launcher.sh into a folder (we use ~/scripts in our example)
wget https://raw.githubusercontent.com/frtz13/UPSPlus_mqtt/master/fanShutDownUps.py
etc. for the other files.
Create a folder ~/logs
Configure your options in fanShutDownUps.ini (please see below for details)
When ready, install to crontab:
crontab -e
then add the line:
@reboot sh /home/pi/scripts/launcher.sh >/home/pi/logs/cronlog 2>&1
If you want to use this option, please read Andreas Spiess' excellent article SensorsIOT: Variable cooling fan for Raspberry Pi about how to assemble the required hardware. The script can also send the fan speed percentage to your MQTT broker (default topic: home/rpi/fanspeed
)
Configuration parameters:
GPIO_FAN: GPIO pin number to control the fan. Set to -1 to disable fan control completely.
FAN_LOOP_TIME_s: recommended value: 5. Interval for fan speed calculation.
DESIRED_CPU_TEMP_degC: the fan control will start to work at this temperature and try to maintain this CPU temperature. This parameter is re-read at runtime with the BATTERY_CHECK_LOOP_TIME_s
interval, so you can change this value on the fly, to check if fan control is working properly.
At startup, the script will check if it can detect the UPS at the expected address on the i2c-bus, and deactivate communication with the UPS if the UPS does not respond.
SEND_STATUS_TO_UPSPLUS_IOT_PLATFORM: setting this to 1 will do the same job as the upsplus_iot.py script in https://github.com/geeekpi/upsplus. Set to 0 to avoid sending the data.
UPSPLUS_IOT_PLATFORM_URL: lets you specify the feed URL. If you don't, https://api.52pi.com/feed will be used.
BATTERY_CHECK_LOOP_TIME_s: recommended value: 60. Interval for battery check and transmission of the UPS status to the MQTT broker.
SHUTDOWN_TIMEOUT_s: recommended value: 30 or 60, depending on how much time your Raspberry Pi needs to safely shut down.
PROTECTION_VOLTAGE_MARGIN_mV: recommended value: 200. Shutdown will be triggered when the battery voltage is lower than the sum of the UPS-Plus protection voltage and this value.
Later you may want to adjust the INA_219_SHUNT... parameters to calibrate the current readings. I did this by measuring the USB charger current while the batteries are fully charged, and assuming some reasonable efficiency factor for the UPS circuits.
Configuration parameters for the MQTT broker should be self-explaining. If you do not want to use this feature, set BROKER to an empty value.
I decided to write a script running continuously in the background to avoid having crontab messages every minute or so in my syslog. Putting all the functions into one script will also ensure that i2c registers will not be accessed concurrently.
When the UPS Plus is on battery, a message is written every minute to the syslog, containing the current battery voltage and the critical limit. "On battery" status is assumed when the average battery discharge current is greater than 500mA. Because of the use of the average current, status changes will be recognized with some delay.
When the measured battery voltage goes under the critical value while the UPS is on battery, the shutdown is triggered: the UPSPlus Back-To-AC-auto-power-up parameter is set, the UPSPlus shutdown countdown is started, and the Raspberry Pi is told to shut down. Thus, the Raspberry Pi should restart once AC power is back and the batteries charge again.
At startup, the script will not check the battery voltage during the first five minutes, to avoid another immediate shutdown if AC power comes back with some instability.
In addition, MQTT data will not be published during this time to leave time for the MQTT broker to start up if it runs on the same Raspberry Pi. That said, the script is supposed to reconnect to the MQTT broker in case the latter stops and restarts.
Therefore, in a worst case scenario where cron starts the script at boot time, if erroneous values are read from the UPS Plus, or something else is wrong with the script, you should have enough time to kill the script before it attempts to shut down your Raspberry Pi.
Fan data is published to the broker with the topic home/rpi/fanspeed
(depending on your configuration). Fan PWM ratio in percent is sent every 5 seconds (by default), but only when its value changes. It is sent with the "retain" flag set.
UPS data is published to the broker with the topic home/rpi/ups
. It is sent as a json string. Included values are:
UsbC_V,
UsbMicro_V,
OnBattery (boolean; true
when average discharging current is greater than 500mA; false
otherwise),
BatteryVoltage_V (as measured by the INA219 sensor at i2c address 0x45),
BatteryCurrent_A (positive value: discharging, negative value: charging)
BatteryCurrent_avg_A,
BatteryPower_avg_W,
BatteryCharging (boolean, true
if BatteryCurrent_avg_A is negative)
BatteryRemainingCapacity_percent,
BatteryTemperature_degC,
OutputVoltage_V (as measured by the INA219 sensor at i2c address 0x40),
OutputVoltage_mini_V (minimum value during the preceding time interval of BATTERY_CHECK_LOOP_TIME_s)
OutputCurrent_A,
OutputCurrent_avg_A,
OutputPower_avg_W,
OutputCurrent_peak_mA (peak value during the preceding time interval of BATTERY_CHECK_LOOP_TIME_s)
Measurements are averaged over a time interval twice as long as BATTERY_CHECK_LOOP_TIME_s.
As an example, if you want to get your data into Home Assistant, you can define sensors in the Home Assistant configuration file:
sensor:
- platform: mqtt
name: "UPS average battery current"
device_class: current
state_topic: "home/rpi/ups"
value_template: '{{ value_json["BatteryCurrent_avg_A"] }}'
unit_of_measurement: "A"
availability:
- topic: "home/rpi/LWT"
payload_available: "online"
payload_not_available: "offline"
or
binary_sensor:
- platform: mqtt
name: "UPS on Battery"
state_topic: "home/rpi/ups"
value_template: '{{ value_json["OnBattery"] }}'
payload_on: "True"
payload_off: "False"
availability:
- topic: "home/rpi/LWT"
payload_available: "online"
payload_not_available: "offline"
You'll find more sensor definitions in the HA_config_ups_fan.yaml
file.
For a first try, you may want to start the script with the --notimerbias
command line argument. Alternatively, you can set the following parameter in your configuration file, [ups] section: TIMER_BIAS_AT_STARTUP = 0
. This will instruct the script to start the UPS probing immediately, without waiting for five minutes.
Start the script: python3 fanShutDownUps.py
If any dependencies are missing, you will get corresponding error messages.
You can stop the script with ctrl-C.
If you do not get any error messages, switch off AC power for the UPS and have a look at the syslog (journalctl -f
). After a minute or two, you should get a message that the UPS is on battery.
If you configured a connection to an MQTT broker, start up an MQTT client and have it listen to the home/rpi/#
topic.
If you want to simulate a shutdown at low battery voltage, do the following in order to avoid to have to wait for a low battery situation:
Be sure to have AC power for the UPS switched on. Start the script with the --shutdowntest
argument (or set the following parameter in your configuration file, [ups] section: SHUTDOWN_IMMEDIATELY_WHEN_ON_BATTERY = 1
), and restart the script. This will instruct the script to start a shutdown sequence immediately, as soon as the UPS is on battery. Once the shutdown sequence completed and the UPS shut down power for the Raspberry Pi, you can restore AC power. The UPS should switch on, and the Raspberry Pi should start.
Once you are done with testing, comment out the TIMER_BIAS_AT_STARTUP
and SHUTDOWN_IMMEDIATELY_WHEN_ON_BATTERY
parameters in the configuration file if you used them for testing, configure crontab to start the script at boot time and restart your Raspberry Pi.
With the v10 firmware of the UPS, you will get syslog messages such as "Error getting data from UPS...Remote I/O error" from time to time. Don't worry about these, as long you do not get more than a couple of them per hour.
UPS Plus SKU: EP-0136 - 52Pi Wiki
https://github.com/geeekpi/upsplus
https://www.sensorsiot.org/variable-speed-cooling-fan-for-raspberry-pi-using-pwm-video138/
http://www.steves-internet-guide.com/into-mqtt-python-client/