Jump to content

Using a Raspberry Pi Zero W to turn on a PC by pinging it's IP address

Go to solution Solved by Datrat,

This is an explanation in case anyone else has this issue.

I ended up using a 470 Ohm resistor tied to the middle stem which was soldered into GPIO pin 24, with a red LED soldered to GPIO 18 pin and the ground next to it, tied the emitter pin (Leftmost with the flat facing you) to ground on the pi and the pc using the USB 2.0 pins and a ground pin header from an old xp machine, and used another of those headers to connect the Collector side (Rightmost one with the flat facing you) to the Left Pwr Sw header, (it was marked + on my motherboard).

 

I have a micro usb cable plugged into a scavenged USB 3.0 port from my windows 7 machine that is inside the case, which is plugged into the Pi Zero W, you can set the python script to run on reboot, but I am having some issue with the computer hardware so I did not, but you would simply enter




And this is the code you input, I have it in /code/ping.py, with a log file "/code/log.txt", and another for troubleshooting in "/code/gpioactivity.txt", but you can do whatever.

 

And a last note, this was mostly written in sporadic stages through BingGPT, I am not saying this is the best way to do it, but it seems to work great, just have other issues outside of this in the way.

 

import subprocess
import RPi.GPIO as GPIO
import time
from datetime import datetime, timedelta

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
GPIO.setup(24, GPIO.OUT)

"""
18 is LED, 24 is the added gpio that actually operates the power button.
"""

last_time = datetime.now()
offline_time = None
last_flush_time = datetime.now()
offline_count = 0

print()
print('This code is running 30sec pings when device is online, and 15sec pings when offline, not final 180 second sleep!')
print()

# CHANGE WHAT THIS PRINTS OR REMOVE IT BY MAKING IT A COMMENT

def is_device_online(ip_address):
    # This function checks if a device with the given IP address is online by pinging it once
    try:
        output = subprocess.check_output(['ping', '-c', '1', ip_address])
        print(output.decode('utf-8'))
# Make the line above a comment if you do not want to see it in the console
        return True
    except subprocess.CalledProcessError as e:
        print(e.output.decode('utf-8'))
# Make the line above a comment if you do not want to see it in the console
        return False

with open('log.txt', 'a') as f:
    with open('/code/gpioactivity.txt', 'a') as g:
        while True:
            if is_device_online('192.168.0.127'):
                # If the device is online, check if it was previously offline and log the duration of offline time
                if offline_time:
                    online_time = datetime.now()
                    duration = online_time - offline_time
                    f.write(f'{online_time} - Device is back online after {duration}\n')
                    if (online_time - last_flush_time) > timedelta(weeks=1):
                        f.flush()
                        last_flush_time = online_time
                    offline_time = None
                    offline_count = 0
                sleep_time = 30
                print()
                print(f'***WARNING*** Ping command set to sleep for {sleep_time} seconds ***WARNING***')
                print()
                time.sleep(sleep_time)
            else:
                # If the device is offline, log the time and use GPIO to restart it after 3 consecutive checks
                print('Device is offline')
                current_time = datetime.now()
                if (current_time - last_time).seconds >= 180:
                    if not offline_time:
                        offline_time = current_time
                        f.write(f'{offline_time} - Device is offline\n')
                        if (offline_time - last_flush_time) > timedelta(weeks=1):
                            f.flush()
                            last_flush_time = offline_time
                    offline_count += 1
                    if offline_count >= 3:
                        GPIO.output(18, GPIO.HIGH)
                        GPIO.output(24, GPIO.HIGH)
                        time.sleep(10)
                        g.write(f'{datetime.now()} - GPIO used for 10 seconds\n')
                        print('\nGPIO used for 10 seconds\n')
# This is how long it holds the hard shutdown input
                        GPIO.output(18, GPIO.LOW)
                        GPIO.output(24, GPIO.LOW)
                    else:
                        GPIO.output(18, GPIO.HIGH)
                        GPIO.output(24, GPIO.HIGH)
                        time.sleep(1)
                        g.write(f'{datetime.now()} - GPIO used for 1 second\n')
                        print('\nGPIO used for 1 second\n')
# This is how long the normal startup output is held
                        GPIO.output(18, GPIO.LOW)
                        GPIO.output(24, GPIO.LOW)
                time.sleep(15)

# This makes the code pause before repeating the pings, I accidentally removed this from the code in copying back and forth from the console.

 

I have a concerning thing with a truenas scale server that is shutting down kinda randomly, and as a band aid fix I was hoping to use a pi zero w to short the pwr switch pins to turn it back on.

 

BingGPT has been helpful and this is the code I have so far (I do not know how to code lol):

import os
import RPi.GPIO as GPIO
import time
import datetime

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)

last_time = datetime.datetime.now()
was_offline = False

while True:
    response = os.system("ping -c 1 192.168.0.127")
    if response == 0:
        if was_offline:
            with open('log.txt', 'a') as f:
                f.write(f'{datetime.datetime.now()} - Device is back online\n')
            was_offline = False
        time.sleep(30)
    else:
        print('Device is offline')
        current_time = datetime.datetime.now()
        if (current_time - last_time).seconds >= 30:
            GPIO.output(18, GPIO.HIGH)
            with open('log.txt', 'a') as f:
                f.write(f'{datetime.datetime.now()} - Device is offline\n')
            time.sleep(2)
            GPIO.output(18, GPIO.LOW)
            last_time = current_time
            was_offline = True

 

It works great, logs correctly, and does indeed hold the gpio pins turning on an led for testing. But I realized this is applying a voltage, and I intended to replace the LED with leads to the power switch, is that an issue applying a voltage there? And if so, how would I go about it, I saw something in a forum post about using a transistor, I currently have 2 2N3904 NPN transistors from a soldering starter project I did when I was younger, if those would work. If that is horrid I would very much appreciate a correction and guidance lol. Also not sure about the length of time needed, if 2 seconds is fine or 1 second, it works for testing but I dont want to fry anything. Thanks so much for any replies 🙂

Link to comment
Share on other sites

Link to post
Share on other sites

The pins are supposed to be shorted together for a short period to turn on motherboard, or short together for at least 5 seconds to shut down.

 

A basic transistor would do the job, connect the pins to collector and emitter ( one of the pins should be tied to ground (use a multimeter to figure that out) so connect that one to emitter.  A small resistor (ex 100 ohm)  to base to protect it (too much current will blow the transistor, too high resistor value means transistor won't open enough) and connect the other resistor to the IO pin

Link to comment
Share on other sites

Link to post
Share on other sites

The voltage would be 3.3V which should be fine - if anything the pull-up on the PWR button pin could be to 5V and may damage the Pi instead, although quite unlikely, could measure it.

 

But you can also avoid it by using the tristate property of the Pi's pin, instead of setting it as an output and toggling it high or low set it low and toggle it being an input and an output. When it's an output it'll pull low, when it's an input it'll be left floating instead of pulling high, just like a switch would.

F@H
Desktop: i9-13900K, ASUS Z790-E, 64GB DDR5-6000 CL36, RTX3080, 2TB MP600 Pro XT, 2TB SX8200Pro, 2x16TB Ironwolf RAID0, Corsair HX1200, Antec Vortex 360 AIO, Thermaltake Versa H25 TG, Samsung 4K curved 49" TV, 23" secondary, Mountain Everest Max

Mobile SFF rig: i9-9900K, Noctua NH-L9i, Asrock Z390 Phantom ITX-AC, 32GB, GTX1070, 2x1TB SX8200Pro RAID0, 2x5TB 2.5" HDD RAID0, Athena 500W Flex (Noctua fan), Custom 4.7l 3D printed case

 

Asus Zenbook UM325UA, Ryzen 7 5700u, 16GB, 1TB, OLED

 

GPD Win 2

Link to comment
Share on other sites

Link to post
Share on other sites

the power switch is essentially 'an input pulled high' and a ground. all the motherboard knows is:

- input pin is pulled high - button is not pressed

- input pin is pulled low - button is pressed

 

but ideally you just use an NPN transistor, put the emitter to the ground pin, the collector to the input pin of the power switch header, and the base (trough a resistior) to your pi's output pin.

this implies that "ground" on the pi is reference to "ground" on the pc.

Link to comment
Share on other sites

Link to post
Share on other sites

It seems I have a lot to learn cause I am clueless what a collector, tristate property, emitter, and probably more are. Time to watch some YouTube tutorials I guess. Thanks for the replies, hopefully I understand everything in a few hours and can implement your suggestions lol

Link to comment
Share on other sites

Link to post
Share on other sites

10 hours ago, manikyath said:

but ideally you just use an NPN transistor, put the emitter to the ground pin, the collector to the input pin of the power switch header, and the base (trough a resistior) to your pi's output pin.

this implies that "ground" on the pi is reference to "ground" on the pc.

From giving bingGPT the link to the kit I had on hand, it said the 470-ohm resistor was the best for the job, which I have connected to the middle "base" pin on the NPN resistor. Am I correctly understanding that I should have the base pin in the GPIO 18 pin, the emitter to the raspberry pi's ground, the power switch ground, and the collector to the correct power switch pin?

Link to comment
Share on other sites

Link to post
Share on other sites

This is an explanation in case anyone else has this issue.

I ended up using a 470 Ohm resistor tied to the middle stem which was soldered into GPIO pin 24, with a red LED soldered to GPIO 18 pin and the ground next to it, tied the emitter pin (Leftmost with the flat facing you) to ground on the pi and the pc using the USB 2.0 pins and a ground pin header from an old xp machine, and used another of those headers to connect the Collector side (Rightmost one with the flat facing you) to the Left Pwr Sw header, (it was marked + on my motherboard).

 

I have a micro usb cable plugged into a scavenged USB 3.0 port from my windows 7 machine that is inside the case, which is plugged into the Pi Zero W, you can set the python script to run on reboot, but I am having some issue with the computer hardware so I did not, but you would simply enter




And this is the code you input, I have it in /code/ping.py, with a log file "/code/log.txt", and another for troubleshooting in "/code/gpioactivity.txt", but you can do whatever.

 

And a last note, this was mostly written in sporadic stages through BingGPT, I am not saying this is the best way to do it, but it seems to work great, just have other issues outside of this in the way.

 

import subprocess
import RPi.GPIO as GPIO
import time
from datetime import datetime, timedelta

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
GPIO.setup(24, GPIO.OUT)

"""
18 is LED, 24 is the added gpio that actually operates the power button.
"""

last_time = datetime.now()
offline_time = None
last_flush_time = datetime.now()
offline_count = 0

print()
print('This code is running 30sec pings when device is online, and 15sec pings when offline, not final 180 second sleep!')
print()

# CHANGE WHAT THIS PRINTS OR REMOVE IT BY MAKING IT A COMMENT

def is_device_online(ip_address):
    # This function checks if a device with the given IP address is online by pinging it once
    try:
        output = subprocess.check_output(['ping', '-c', '1', ip_address])
        print(output.decode('utf-8'))
# Make the line above a comment if you do not want to see it in the console
        return True
    except subprocess.CalledProcessError as e:
        print(e.output.decode('utf-8'))
# Make the line above a comment if you do not want to see it in the console
        return False

with open('log.txt', 'a') as f:
    with open('/code/gpioactivity.txt', 'a') as g:
        while True:
            if is_device_online('192.168.0.127'):
                # If the device is online, check if it was previously offline and log the duration of offline time
                if offline_time:
                    online_time = datetime.now()
                    duration = online_time - offline_time
                    f.write(f'{online_time} - Device is back online after {duration}\n')
                    if (online_time - last_flush_time) > timedelta(weeks=1):
                        f.flush()
                        last_flush_time = online_time
                    offline_time = None
                    offline_count = 0
                sleep_time = 30
                print()
                print(f'***WARNING*** Ping command set to sleep for {sleep_time} seconds ***WARNING***')
                print()
                time.sleep(sleep_time)
            else:
                # If the device is offline, log the time and use GPIO to restart it after 3 consecutive checks
                print('Device is offline')
                current_time = datetime.now()
                if (current_time - last_time).seconds >= 180:
                    if not offline_time:
                        offline_time = current_time
                        f.write(f'{offline_time} - Device is offline\n')
                        if (offline_time - last_flush_time) > timedelta(weeks=1):
                            f.flush()
                            last_flush_time = offline_time
                    offline_count += 1
                    if offline_count >= 3:
                        GPIO.output(18, GPIO.HIGH)
                        GPIO.output(24, GPIO.HIGH)
                        time.sleep(10)
                        g.write(f'{datetime.now()} - GPIO used for 10 seconds\n')
                        print('\nGPIO used for 10 seconds\n')
# This is how long it holds the hard shutdown input
                        GPIO.output(18, GPIO.LOW)
                        GPIO.output(24, GPIO.LOW)
                    else:
                        GPIO.output(18, GPIO.HIGH)
                        GPIO.output(24, GPIO.HIGH)
                        time.sleep(1)
                        g.write(f'{datetime.now()} - GPIO used for 1 second\n')
                        print('\nGPIO used for 1 second\n')
# This is how long the normal startup output is held
                        GPIO.output(18, GPIO.LOW)
                        GPIO.output(24, GPIO.LOW)
                time.sleep(15)

# This makes the code pause before repeating the pings, I accidentally removed this from the code in copying back and forth from the console.

 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×