@madpilot makes

Upgrading a Kegerator

A mate of mine gave me a Keg Master Series 3 Kegerator that he was no longer using, which was a stroke of luck. Just before we moved house in 2023, I turned off my old kegerator.

A Keg Master Series 3 Kegerator

A kegerator is just a fridge with beer taps attached, in which you can store beer kegs.

That kegerator was a home-build - a bar fridge that I drilled some holes in. One of the holes was quite large and exposed the inner foam of the fridge. The inner foam, it turns out, is a great place for mould to grow, particularly when wet and warm which coincidently happens when you turn off a fridge.

Anyway, I was now no longer kegerator-less.

However, there were a couple of issues:

  1. The seven-segment display was missing a couple of segments. I pulled it apart and fixed a couple of dry joints.
  2. If it lost power it would revert to a very low Fahrenheit temperature; which would have just been annoying, except:
  3. It would freeze everything kept in it. Even setting the temperature controller to 3 or 4 degrees. After losing a 19L batch of beer, I decided to replace the faulty temperature controller.

Does your kegerator need to be on the Internet?

No. And it’s technically not - it’s on my Intranet (or local cloud as marketing people would call it).

I decided that this project needed to tick the following boxes:

  1. Minimise the number of modifications to the existing hardware. I wanted to include a display and I wanted the buttons to function.
  2. I wanted to be able to monitor the temperature in Home Assistant, so I could add alarms if something weird happened
  3. It should remember the last temperature settings and default back to the last state.
  4. I’d like it to keep the temperature within 1 degree of the set-point

I was clearly going to replace the control board, but I wanted to reuse the existing connectors. The seven segment display can go - LCDs are dirt cheap, and can convey more information.

First step: design a new circuit. There are three unknowns to solve: the temperature sensor, the relay that drives the compressor and the buttons.

The buttons

The buttons turned out to be pretty easy, there are five pins: one is common and three of the other ones are wired to the buttons. A few minutes with a multimeter mapped them out.

Driving the relay

The relay was only marginally tricker. The kegerator has a schematic stuck on the back, which suggested there was a daughter board with a relay on it. I pulled the back off and found the board and pulled it out to inspect it.

This board must be used in other products as it has provisions for a second relay - perhaps for a heater in a fermentation chamber?

The relay is driven by a transistor, which presented a small problem.

I had a bunch of ESP32-S2-WROOMs in stock, so I decided to use that as the brains. However, they can only source 3.3V. The existing controller is all 5V logic.

Given the transistor is a current-driven device I just needed to find a resistor that matched the current flowing through a 2.2k resistor that was driving the base of the transistor.

Measuring the voltage drop across the resistor:

$$V_{drop} = 4.3V$$

$$4.3V/2200\Omega = 0.00195A$$

$$3.3V-(5V-4.3V) = 2.6V$$

$$2.6V/0.00195A = 1,333.333\Omega$$

So, something close to a 1.3k resistor. I tried it out on a breadboard, and it all worked perfectly.

Reading the temperature

Finally, I need to work out what to do about the thermistor. The current one was unmarked, but was probably a k-type? Given I wanted to make this fridge more accurate, trying to calibrate an unknown thermistor didn’t seem like a great idea. Not to mention there was a bunch of other circuitry that would need to be designed and sourced. Also: a had a bunch of Dallas DS18B20 lying about.

The next problem: the wiring to the thermistor has just two wires and the DS18B20 is a three-wire device. The existing wire is lodged in the case of the fridge and seemingly glued in, so replacing it wasn’t really an option.

Luckily, it is possible to run the DS18B20 using just two wires. By grounding the VCC pin, the chip will go into parasitic power mode, where a capacitor charges while the data line is high, which gives it enough power to read its internal ADC, convert the number to a temperature, and spit it back over the i2c bus.

Hilariously, I burnt an hour or two trying to get this to work. It turns out the cheap DS18B20s I bought off Aliexpress were knock-offs. After switching them out for some other ones (which were also fakes, but ones that seem to support parasitic power), we were good to go.

Test results from the counterfit test - fake!

The old sensor was terminated with a connector, so I just cut the end and wired in the new temperature sensor with some heat-shrink to cover my sins.

The heat-shrunk temperature sensor

You can download the KiCad files on my GitHub.

Let’s get cooking

It’s been a while since I’ve done SMDs and I stupidly didn’t order a stencil. Free handing solder paste is not fun.

But, I eventually got the board up. After a few minutes in the toaster oven (and a couple of fixes with the hot air gun) we were ready to roll.

Components and board laid out ready for placement

Placed, and ready for baking

Reflow time!

Bodge wires

Everything worked perfectly first time.

Kidding. Of course, it didn’t.

The biggest issue was some idiot (me) didn’t read the data sheet correctly and failed to realise that pin 26 is internally reserved for use by SRAM. My original schematic has this as the GPIO that turned on the cooling. Kinda important.

Thankfully I had designed the board to break out the unused heater wire in the wiring harness. The heater was routed to a usable pin, so swapping the wires in the connector and a quick firmware reconfiguration got me out of trouble.

The second issue was the pin I originally selected for the temperature up button was also internally connected to something. Whatever it was had just enough resistance to stop the button from triggering.

I added a couple of bodge wires to move the button to a different GPIO. Since the original cooling pin was no longer in use I could use it as a solder point and I could flip sides to make the wiring a bit neater.

Hopefully future Myles will appreciate the note

Firmware

I’m just using esphome for this stuff now - it has all the sensors, a PID implementation, can render stuff to displays and has over-the-air updates.

At the time of writing this is the YAML:

esphome:
  name: kegerator

esp32:
  board: esp32-s2-saola-1

i2c:
  sda: GPIO17
  scl: GPIO16

font:
  - file: "gfonts://Roboto"
    id: font_large
    size: 18
  - file: "gfonts://Roboto"
    id: font_small
    size: 8

display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x32"
    lambda: |-
      float current_temperature = id(kegerator_pid).current_temperature;
      float target_temperature = id(kegerator_pid).target_temperature;

      if(id(kegerator_pid).mode == CLIMATE_MODE_COOL) {
        if(!std::isnan(current_temperature)) {
          it.printf(64, 0, id(font_large), TextAlign::TOP_CENTER, "%.1f°C", current_temperature);
        } else {
          it.printf(64, 0, id(font_large), TextAlign::TOP_CENTER, "--°C");
        }
      } else {
          it.printf(64, 0, id(font_large), TextAlign::TOP_CENTER, "Off");
      } 

      if(!std::isnan(target_temperature)) {
        it.printf(64, 32, id(font_small), TextAlign::BOTTOM_CENTER, "%.1f°C", target_temperature);
      } else {
        it.printf(64, 32, id(font_small), TextAlign::BOTTOM_CENTER, "--°C");
      }

one_wire:
  - platform: gpio
    pin: GPIO15

sensor:
  - platform: dallas_temp
    id: temperature
    name: "Temperature"
    update_interval: 1s
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    filters:
      - exponential_moving_average:
          alpha: 0.8
          send_every: 30

binary_sensor:
  - platform: gpio
    id: btn_temp_up
    pin:
      number: GPIO14
      inverted: true
      mode:
        input: true
        pullup: true
    filters:
      autorepeat:
        - delay: 1s
          time_off: 100ms
          time_on: 100ms

    on_click:
      lambda: |-
        float target_temperature = id(kegerator_pid).target_temperature;
        auto call = id(kegerator_pid).make_call();
        call.set_target_temperature(target_temperature + 0.1);
        call.perform();

  - platform: gpio
    id: btn_temp_down
    pin:
      number: GPIO21
      inverted: true
      mode:
        input: true
        pullup: true
    filters:
      autorepeat:
        - delay: 1s
          time_off: 100ms
          time_on: 100ms
    on_click:
      lambda: |-
        float target_temperature = id(kegerator_pid).target_temperature;
        auto call = id(kegerator_pid).make_call();
        call.set_target_temperature(target_temperature - 0.1);
        call.perform();

  - platform: gpio
    id: btn_units
    pin:
      number: GPIO20
      inverted: true
      mode:
        input: true
        pullup: true
    on_click:
      then:
        lambda: |-
          auto call = id(kegerator_pid).make_call();
          if(id(kegerator_pid).mode == CLIMATE_MODE_COOL) {
            call.set_mode("OFF");
          } else {
            call.set_mode("COOL");
          }
          call.perform();

button:
  - platform: template
    name: "Kegerator PID Climate Autotune"
    on_press:
      - climate.pid.autotune: kegerator_pid

output:
  id: compressor
  platform: slow_pwm
  pin: GPIO18
  period: 1200s

climate:
  - platform: pid
    id: kegerator_pid
    name: "Kegerator"
    sensor: temperature
    default_target_temperature: 7°C
    cool_output: compressor
    visual:
      min_temperature: -7
      max_temperature: 32
      temperature_step: 0.1
    control_parameters:
      kp: 0.19714
      ki: 0.00028
      kd: 34.89431

logger:

api:
  password: ""

ota:
  - platform: esphome
    password: ""

wifi:
  ssid: !secret iot_wifi_ssid
  password: !secret iot_wifi_password

  ap:
    ssid: "Kegerator"
    password: ""

The latest version can be found on my GitHub.

Breaking is down, temperature reading is done by the one_wire and sensor sections. I’m using an exponential moving average filter to clean up the readings. Exponential moving average filters are memory efficient, as you only need to store the last value. The new value is found by the following formula:

$$T_0 = x_0$$

$$T_{t} = \alpha x_{t} + (1 - \alpha)T_{t-1}, t > 0$$

This is just a fancy way of saying “The new temperature is the new reading times a weighting, plus the last temperature times the inverse weighting”. I picked a weight of 0.8, so the temperature is biased towards the new reading.

The climate section is the PID controller. You will note the default_target_temperature setting. From the esphome documentation:

The default target temperature (setpoint) for the control algorithm. This can be dynamically set in the frontend later.

If it’s never been set, it’ll use the value 7, but the frontend will automatically set it to the previous value. I have verified this recently, as a contractor killed the power (including from the battery), and the kegerator reverted to the last set-point. Goal #3 achieved!

The output section defines the pin that the drives the compressor. I’m using the slow_pwm setting, which the esphome docs do a better job of explaining it than I can:

Similar to PWM, the Slow PWM Output platform allows you to control GPIO pins by pulsing them on/off over a longer time period. It could be used to control a heating element through a relay where a fast PWM update cycle would not be appropriate.

The buttons are defined in the binary_sensor section. I’m using the internal pull-ups saving me 4 resistors. I also added an auto-repeat filter, which will increase or decrease the set-point faster if you hold the buttons down for 1s. Using the existing buttons: Goal #1 achieved!

The i2c, display and font section drive the display. Esphome is pretty clever - it can automatically download, and convert fonts to embed and display. The heavy lifting is done in the lambda block. The code is straight up C++. If the kegerator is in cooling mode, it displays the current temperature. Otherwise, it just displays the word “Off” on the first line. It also displays the target set-point on the second line.

Finally, the api, ota and wifi sections allows the kegerator to be controlled by home assistant (Goal #2 achieved!), and allows the firmware to be updated over-the-air.

Tuning the PID

The control parameters are pretty specific, and—shockingly—I didn’t come up with the numbers.

The Esphome PID plugin has an auto-tune function, that is triggered by a button in Home Assistant. It runs an “adaption of the Ziegler-Nichols method with relay autotuning (Åström and Hägglund)”. To autotune the kegerator, I filled a 19L keg with water, and ran the autotune. It took awhile, but it came up with the numbers in the YAML.

[13:21:03][I][pid.autotune:163]:   Calculated PID parameters ("Ziegler-Nichols PID" rule):
[13:21:03][I][pid.autotune:164]:  
[13:21:03][I][pid.autotune:165]:   control_parameters:
[13:21:03][I][pid.autotune:166]:     kp: 0.19714
[13:21:03][I][pid.autotune:167]:     ki: 0.00028
[13:21:03][I][pid.autotune:168]:     kd: 34.89431


[13:21:03][D][pid.autotune:176]:   Alternative Rules:
[13:21:03][D][pid.autotune:208]:     Rule 'Ziegler-Nichols PI':
[13:21:03][D][pid.autotune:209]:       kp: 0.14786, ki: 0.00013, kd: 0.00000
[13:21:03][D][pid.autotune:208]:     Rule 'Pessen Integral PID':
[13:21:03][D][pid.autotune:209]:       kp: 0.23000, ki: 0.00041, kd: 48.85204
[13:21:03][D][pid.autotune:208]:     Rule 'Some Overshoot PID':
[13:21:03][D][pid.autotune:209]:       kp: 0.10941, ki: 0.00015, kd: 51.64358
[13:21:03][D][pid.autotune:208]:     Rule 'No Overshoot PID':
[13:21:03][D][pid.autotune:209]:       kp: 0.06571, ki: 0.00009, kd: 29.07859

So how does it perform? Pretty well. The temperature stays with-in ±1°C of the set point (Goal #4 achieved!), and the duty-cycle seems to hover around 50%, which means the compressor is on for 10-minutes, then off for 10-minutes. Most importantly, none of my drinks have frozen!

A day’s worth of temperature readings

So my coffee grinder has Bluetooth…

The previous owner of our house installed LED strips below the kitchen cabinets. Ever since we had moved in, I had planned on replacing the LED drivers with ZigBee ones, so I could connect them up to Home Assistant.

ZigBee LED Driver

I got a couple of these. These are adjustable constant current drivers - luckily the LED strips had their Watt/metre value printed on them, so it was easy enough to work out what current to set them to.

Now what to do with them…

The one that sits over my coffee machine turned out to be pretty useful, but I was pressing a ZigBee button to turn it on and off like a heathen.

I have a ZigBee energy monitor on my coffee machine, so my first thought was setting up an automation that looked for power usage. Unfortunately, the heater draws more power than the pump, and the heater being on is an indicator that it’s heating up - not that it is in use.

I put that idea to bed and forgot about the automation for a while.

What’s the grinder got to do with this story?

I have a Baratza Sette 270Wi Grinder. It is pretty nifty. It was a built-in scale and will automatically dose exact amounts of coffee straight into the basket. The scale was being a bit funny, so I pulled out the companion app to see what the scales were doing in the background.

The bluetooth scanner in the Sette app, showing my grinder

The app told me there was a firmware upgrade available for the scales, so I ran the updater.

Wait. How did the firmware upgrade?

I’m glad you asked!

It uses Bluetooth.

I had been playing around with esphome recently, and had to connect to some Bluetooth garden sensor - to do that I had to use the ble_scanner function to find them. Would that find the coffee machine?

I knocked up a quick esphome file, and pushed it to an ESP32.

esphome:
  name: "ble-scanner"
  
esp32:
  board: esp32dev

logger:

api:
  password: ""

ota:
  - platform: esphome
    password: ""

esp32_ble_tracker:

text_sensor:
  - platform: ble_scanner
    name: "BLE Devices Scanner"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "ble_scanner"
    password: ""

captive_portal:

And waited for it to scan.

[21:28:17][D][text_sensor:064]: 'BLE Devices Scanner': Sending state '{"timestamp":363078,"address":"4E:E7:9F:30:9D:A4","rssi":-88,"name":""}'
[21:28:18][D][text_sensor:064]: 'BLE Devices Scanner': Sending state '{"timestamp":363078,"address":"40:2F:A2:74:D5:F0","rssi":-76,"name":""}'
[21:28:19][D][text_sensor:064]: 'BLE Devices Scanner': Sending state '{"timestamp":363079,"address":"4E:E7:9F:30:9D:A4","rssi":-76,"name":""}'
[21:28:19][D][text_sensor:064]: 'BLE Devices Scanner': Sending state '{"timestamp":363079,"address":"7C:D3:5B:1A:F5:93","rssi":-59,"name":""}'
[21:28:19][D][text_sensor:064]: 'BLE Devices Scanner': Sending state '{"timestamp":363079,"address":"6C:B7:B7:CA:F8:3D","rssi":-80,"name":""}'
[21:28:20][D][text_sensor:064]: 'BLE Devices Scanner': Sending state '{"timestamp":363080,"address":"40:2F:A2:74:D5:F0","rssi":-92,"name":""}'
[21:28:20][D][text_sensor:064]: 'BLE Devices Scanner': Sending state '{"timestamp":363080,"address":"C8:69:CD:43:6A:B5","rssi":-64,"name":""}'
[21:28:21][D][text_sensor:064]: 'BLE Devices Scanner': Sending state '{"timestamp":363081,"address":"E0:32:32:AD:F7:9D","rssi":-65,"name":""}'
[21:28:22][D][text_sensor:064]: 'BLE Devices Scanner': Sending state '{"timestamp":363082,"address":"7C:D3:5B:1A:F5:93","rssi":-63,"name":""}'
[21:28:22][D][text_sensor:064]: 'BLE Devices Scanner': Sending state '{"timestamp":363082,"address":"6C:B7:B7:CA:F8:3D","rssi":-93,"name":""}'

No dice. But this is actually good! The coffee machine isn’t on yet, so if it was broadcasting now, this process would be a bust.

I turned it on, and tried again…

[21:29:40][D][text_sensor:064]: 'BLE Devices Scanner': Sending state '{"timestamp":363160,"address":"00:1C:97:1C:A3:B3","rssi":-73,"name":"BARW270A3B3"}'

Found it! I grabbed the MAC of the device, and change the esphome YAML file to be:

esphome:
  name: "ble-scanner"
  
esp32:
  board: esp32dev

logger:

api:
  password: ""

ota:
  - platform: esphome
    password: ""

esp32_ble_tracker:

binary_sensor:
  - platform: ble_presence
    mac_address: 00:1C:97:1C:A3:B3
    name: "BARW270A3B3 Power"
    timeout: 30s
sensor:
  - platform: ble_rssi
    mac_address: 00:1C:97:1C:A3:B3 
    name: "BARW270A3B3 RSSI"

wifi:
  ssid: !secret iot_wifi_ssid
  password: !secret iot_wifi_password

  ap:
    ssid: "ble_scanner_poc"
    password: ""

captive_portal:

This creates a binary sensor in home assistant called “BARW270A3B3 Power”, which can be used to trigger an automation to turn on and off the lights!

Running Proxmox backups when the sun is shining

I have a small home lab that runs Proxmox. It runs my Home Assistant instance, as well as MQTT, dnsmasq and a few other services (including this blog!).

While I back up my working data using kopia and Backblaze, I wanted to set up Proxmox Backup Server so I could recover from any VM level issues quickly.

To do that, I recommissioned an old HP ProLiant Microserver that used to run my lab. It has 4 × 3.5″ HDD drive bays, so can provide plenty of storage, and most importantly - I already had one.

After I set everything up, I was looking at my rack power consumption (I have it attached to a Zigbee smart plug which I monitor via Home Assistant), and noticed that the new server draws around 50W. This is 1.2kWh per day, or 36kWh per month! This is around 5% of my total household consumption.

I work for Amber Electric, an electricity retailer that sells electricity at wholesale rates that fluctuate every 30 minutes, so it’s a bit hard to put an exact monthly price on it. But, we can find the average cost for January 2024 pretty easily from the API and some jq magic:

curl 'https://api.amber.com.au/v1/sites/$SITE_ID/prices?startDate=2024-01-01&endDate=2024-02-01&resolution=30' -H 'accept: application/json' -H 'Authorization: Bearer $AUTH_TOKEN' | jq '[.[] | select(.channelType=="general") | .perKwh] | add/length'

For me, that was 18.34 c/kWh, so $6.60 per month, to have a whole server sitting around not doing much for much of the day.

Now, this isn’t totally fair - I have 6.6kW of solar panels and a 9.6kWh battery, so realistically it actually costs me nothing, BUT! having this server chug 5-6% of my usable battery overnight seems kind of silly, especially since I only run one incremental backup per day.

Automations to the rescue!

My goal for this project was to only run the backup server during the day when the sun was shining.

I needed to solve the following problems:

  1. How do I turn the server on?
  2. How do I turn the server off?
  3. How do I work out if there is enough sun?

How do I turn the server on?

This turned out to be a pretty simple problem to solve, given the work of past Myles who must have set up Wake-on-LAN for this machine. Sending the Magic Packet to the network card happily booted it up.

You can easily test this on OSX by installing wakeonlan from brew. and running

wakeonlan -i $BROADCAST_ADDRESS $MAC_ADDRESS

To figure out the $BROADCAST_ADDRESS go to this Broadcast Address Calculator and enter the IP address of the machine you want to wake up. To find the MAC address, you can run

arp $IP_ADDRESS

For simplicity, the rest of these examples will use a server address of 192.168.0.100 and MAC address of 55:99:30:E6:00:3C

Home assistant has a Wake on Lan integration, so we can set up a switch to turn the machine on! Unfortunately, this integration hasn’t been updated for configuration via the UI yet, so you need to jump in to YAML land.

wake_on_lan:

switch:
  - platform: wake_on_lan
    name: "Proxmox Backup Server"
    mac: 55:99:30:E6:00:3C
    broadcast_address: 192.168.0.255
    host: 192.168.0.100

Restart Home Assistant and you should have a new switch.proxmox_backup_server in your entities. Because we set a host, Home Assistant will ping the host IP to check it’s status, and update the switch accordingly.

So, we can now turn the server on…

How do I turn the server off?

Glad you asked. It turns out, it’s only marginally harder than turning it on.

Proxmox Backup Server shares a bunch of features with Proxmox proper, including an API. The API has an endpoint that allows you to shut down the server via a REST command. There is even a facility to generate an API token, so you don’t need to use your username and password combo.

Click on Configuration > Access Control and click the API Token tab. Then click Add.

The API token screen

Select a user to link to the API key, and give the token a name like home-assistant or similar, then hit Add. Make a copy of the generated key, and save it somewhere safe—it’ll disappear once you close the window.

Add an API token

Next, you need to give the API token permissions to manage power settings. Click on the Permissions tab, and click Add, and then API Token Permission. Select /system/status as the path, as well as the token you just created, and set the Role to Admin.

Now that you have a token, you can use the Home assistant RESTful Command integration to set up an action to switch the server off.

rest_command:
  shutdown_proxmox_backup_server:
    url: "https://192.168.0.100:8007/api2/json/nodes/1/status"
    method: post
    payload: "command=shutdown"
    verify_ssl: false
    content_type: "application/x-www-form-urlencoded"
    headers:
      accept: "application/json, text/html"
      authorization: !secret pbs_api_key

In your secrets.yaml file, you need to prepend the API key you generated with PBSAPIToken=$USERNAME!$TOKEN_NAME:, so if you linked the code to root@pam and named the token homeassistant the YAML entry might look something like this:

pbs_api_key: "PBSAPIToken=root@pam!home_assistant:6af64531-ed7f-47e3-a094-b6e60f965760"

So, now we have a new service rest_command.shutdown_proxmox_backup_server that we can call to switch off the server from Home assistant.

We need to tell the power on lan integration to call that service when the switch is toggled off:

switch:
  - platform: wake_on_lan
    name: "Proxmox Backup Server"
    mac: 55:99:30:E6:00:3C
    broadcast_address: 192.168.0.255
    host: 192.168.0.100
    turn_off:
      service: rest_command.shutdown_proxmox_backup_server

How much sun do we think there will be?

My solar system gets curtailed to match my household load if the wholesale price goes negative, so I can’t really monitor exports to the grid, or solar generation.

I use the Forecast.Solar integration in Home Assistant which will predict my solar generation over the day.

I decided to use this as a trigger for the automation. If the integration is predicting more than 500W of solar, the server should turn on. If there is less, turn it off.

I used this forecast rather than actuals to avoid the server shutting down due to solar curtailment. Is it perfect? No, but it’ll be good enough.

I use a choose condition, so I can keep the whole automation in one file. The trigger is sensor.power_production_now, and the action is if sensor.power_production_now is greater than 500, switch on otherwise switch off. Here is the YAML:

alias: Proxmox Backup Server
description: >-
  Turn on on the Backup server if it’s predicted there is more than 500W of
  solar being generated
trigger:
  - platform: state
    entity_id:
      - sensor.power_production_now
condition: []
action:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: sensor.power_production_now
            above: 500
        sequence:
          - service: switch.turn_on
            metadata: {}
            data: {}
            target:
              entity_id: switch.proxmox_backup_server
    default:
      - service: switch.turn_off
        metadata: {}
        data: {}
        target:
          entity_id: switch.proxmox_backup_server
mode: single

Tell Proxmox to run backups during the day

The last thing to set is to kick off Proxmox backups at midday, rather than at 2am - no point trying to connect to a server that is currently sleeping.

Proxmox backup settings

In the Proxmox console, Go to Datacenter > Backups and edit all the schedules to read 12:00.

Update backup schedule

And that’s it! You can see this history snapshot of when the server is on and off.

Power history snapshot of server on and server off.