Monday, October 24, 2016

How to power off Raspberry Pi 3 USB or Ethernet ports

Hardware: Raspberry Pi 3 Model B

Software: Windows 10 / 2016-09-23 Raspbian Jessie Lite (minimal)

I was mildly annoyed searching for how to turn the power for USB ports on/off.  The official documentation doesn't include it and the instructions online are out of date and/or incomplete.  So here it is from scratch!  Essentially, you're going to install an additional Linux module, download a third party app's source (https://github.com/codazoda/hub-ctrl.c), compile it and then run it.

These instructions assume a base install of Raspbian as indicated above and a default configuration.


So to get started, log in to your RPi via SSH (http://www.putty.org/or a local connection and then type in:

   sudo apt-get update
   sudo apt-get install libusb-dev
   git clone https://github.com/codazoda/hub-ctrl.c
   cd hub-ctrl.c
   gcc -o hub-ctrl hub-ctrl.c -lusb
   cp hub-ctrl ..
   cd ..

At this point you're back where you started in the root but hub-ctrl will now function and can turn off your USB and Ethernet port.  For a detailed walk through of what the commands above do:
  • Update the list of what Linux updates/versions exist and where they are located
  • Install the current version of libusb-dev
  • Copy the source code of hub-ctrl.c to your machine
  • Change into the directory where the hub-ctrl.c code was copied
  • Compile it into an executable named hub-ctrl (note the lack of a .c)
  • Copy the compiled exectuable to the root directory
  • Change back into the root directory
Now it all comes down to running commands against your newly compiled hub-ctrl command.

To jump right into it, here are some examples:
  • Turn off Ethernet Port:   sudo ./hub-ctrl -h 0 -P 1 -p 0
  • Turn on Ethernet Port:   sudo ./hub-ctrl -h 0 -P 1 -p 1
  • Turn off all USB Ports:   sudo ./hub-ctrl -h 0 -P 2 -p 0
  • Turn on all USB Ports:   sudo ./hub-ctrl -h 0 -P 2 -p 1 
Essentially the number after the -P determines the port while the number after the -p (case matters in Linux don't you know) determines the state (0 = off, 1 = on).

Now, the information elsewhere refers to shutting down individual ports and using values of -P to do it.  They claim a -P 3 would shut down an individual port.  My own experience is...no.  While it did not throw an error, no USB devices shut down when attempting individual control.  It only worked when I shut all USB ports down.

So to do a full USB reset via power-off/on you could munge together a command like this:

   sudo ./hub-ctrl -h 0 -P 2 -p 0 ; sleep 5; sudo ./hub-ctrl -h 0 -P 2 -p 1;

This would bounce all USB devices via a power off, wait 5 seconds, then power them all back on.

32 comments:

  1. Thank you for this good guide. However, After following all the steps, I get an error message when I enter the command:
    sudo ./hub-ctrl -h 0 -P 4 -p 0

    The message says:
    sudo: ./hub-ctrl: command not found

    How come?
    Thanks, Mehdi

    ReplyDelete
  2. (Might be important, I'm using a Pi 2 with Rapsbian Wheezy)

    ReplyDelete
  3. I would probably guess that you're running into a pathing issue. Easiest method to test is to see if the application exists after you compiled it. Try using "ls" to see if the application exists. If you copy/paste the directory contents you're looking at that would give me an idea of what's going sideways.

    Also note that the different Pi boards seem to give different results with this command. Therefore, the Pi2 might allow you to power down particular ports individually.

    ReplyDelete
    Replies
    1. This is what I am looking at. It seems that the application exists, so I don't get why I cannot use ./hub-ctrl

      pi@pi2-1 ~ $ cd hub-ctrl.c
      pi@pi2-1 ~/hub-ctrl.c $ gcc -o hub-ctrl hub-ctrl.c -lusb
      pi@pi2-1 ~/hub-ctrl.c $ ls
      hub-ctrl hub-ctrl.c README.md
      pi@pi2-1 ~/hub-ctrl.c $ cd ~
      pi@pi2-1 ~ $ ls
      Desktop hub-ctrl.c python_games stream stream.org tools
      pi@pi2-1 ~ $ sudo ./hub-ctrl -h 0 -P 4 -p 0
      sudo: unable to resolve host pi2-1
      sudo: ./hub-ctrl: command not found

      Delete
    2. (ignore the "unable to resolve host pi2-1", I just changed the name of my pi)

      Delete
    3. Looks like the executable is in the subdirectory vs. in the root. I'll check the instructions to ensure I've got the walkthrough correct, but near term you should be able to do:

      sudo ./hub-ctrl.c/hub-ctrl -h 0 -P 4 -p 0

      Alternatively, you could copy it to the root:

      mv ./hub-ctrl.c/hub-ctrl ./hub-ctrl

      Then the original command should work.

      Delete
    4. The first command worked when trying to turn all USB off, not individual ports (just like you said in your original article).
      Thanks a lot for your help!

      Delete
  4. Thanks for this post - I was having similar issues. And with the pathing fix from the comments it worked fine. As you say - it powers all USB ports on/off rather than individual.

    I need to power on and off a single USB device whilst keeping another permanently on. Do you think it is possible to adapt the ethernet port to provide power to a USB device (with some kind of adapter) to separate the two devices? Then I could use the hub ctrl system to power P 1 on and off but keep P 2 on all the time?

    ReplyDelete
    Replies
    1. I haven't looked down to a lower level on this at this point. You might hit up Joel Dare who is the author of the third party app I linked to above (https://github.com/codazoda). He might have an idea on exactly what the issue is, but I would guess it has to do with what the USB hub supports code-wise.

      If I were punting and didn't feel like googling other possibilities, I might go looking at putting an additional item inline between the USB port and the device that you can control. I of course have a couple of MediaTek 7688 Duo's sitting around here I could throw at the problem that would probably work in such a scenario but I'm sure there are other methods.

      Delete
    2. And I did a quick search to see if anyone else had worked along this kind of issue and hit this post that was pretty informative:

      https://befinitiv.wordpress.com/2014/02/02/hacking-per-port-power-switching-to-an-usb-hub-2/

      Delete
  5. When I try "sudo ./hub-ctrl -h 0 -P 2 -p 0"
    I get

    failed to control.
    : Invalid argument

    I have an Pi3. Any suggestions?

    ReplyDelete
    Replies
    1. There are some notes per shutting down USB ports failing on various Linux versions/releases and different hardware.

      I just re-tested this w/ the 2017-01-11 version of Raspbian Jessie and the RPi3 model B hardware and it was successful. Are you using Raspbian? If so/not, what version?

      Delete
  6. Correction:
    sudo ./hub-ctrl.c -h 0 -P 2 -p 0

    ReplyDelete
    Replies
    1. Not clear on what you're stating here pepe. If you compiled the application using gcc slightly differently than I did, then I *believe* you could have compiled it so that the executable was named "hub-ctrl.c". So then the command you have listed would be accurate.

      But that is confusing for folks as the .c (or .cpp, etc.) generally designates source vs. executables.

      If I've got an error in my instructions though then please give me a bit more info and I'll fix it ASAP.

      Delete
  7. Thanks for sharing this! I tested all of this and it works perfectly on Raspberry pi 3. My only concern is that when you turn of the Ethernet somehow it even turns of the wifi. Whats your take on that.

    ReplyDelete
    Replies
    1. Hmmm...the full power down supposedly is shutting down the USB chipset. Off the top of my head I would guess that the chip is either paired with or fully includes the WiFi chipset. First though, I'll do a test w/ it to verify.

      Delete
  8. Works well on RPi3/OSMC, well made post, sir!

    I have a related question, though. I have an external HDD enclosure with 2.5' HDD inside that works over USB 2. It does not have any feature to turn off or spin down when not being used, i.e. it keeps on working all the time it is powered. It simply wasn't intended to be plugged-in all the time.

    Now, I'd like to have it plugged-in to my RPi all the time, yet use the above hub-ctrl to turn it off when the drive is not being used (I'd have to figure out how to determine if the drive has to be used). Do you think that this method is safe for the drive? Or should I also unmount/eject the drive each time before setting USB off?

    Cheers!

    ReplyDelete
    Replies
    1. I'd probably do a software unmount before I powered it down if I didn't control everything else about what was going on w/ the drive (e.g. apps/usage/cache). Assuming again that you're reliably figuring out when/how the drive is used, then this isn't really difficult.

      If I were to assume you're thinking "media server" and wanting to put some archives on here and only spin up the drive when the archive is accessed, then a little reading on whatever app you're using is applicable.

      What you'd really want is something that when you want to access the library via your application (e.g. Myth, Plex, etc.), that your app has a configurable script that can be run at that moment, then it runs your code to spin up the drive, mount, etc.

      Delete
    2. Great, thanks. That's roughly what I am planning to do. Nothing to add, really, as you have explained it completely :) My regards!

      Delete
  9. how can i use these commands in my python code?
    these commands work fine for me one the terminal, but when i use it with os.system("sudo ./hub-ctrl -h 0 -P 2 -p 1") and os.system ("sudo ./hub-ctrl -h 0 -P 2 -p 0") for power on and off respectively my python code becomes unstable. Could you tell me a solution for this??
    Hoping for a quick response.
    Thanks & Regards
    Sameena Shaikh

    ReplyDelete
    Replies
    1. Can you define "unstable"? Without a code snippet it is unlikely I will take a look at this today. Just to confirm, is this python 2 or 3?

      Delete
    2. And since I am lying here arguing with myself of whether I get up and go code or continue not sleeping and depressing myself by reading the news, I did a quick search on how I might approach the problem. That landed me at a discussion which I think might give you a better way to call this within python:

      https://stackoverflow.com/questions/89228/calling-an-external-command-in-python

      Delete
    3. unstable means sometimes it does do both powering off and then power on when i run my code. Sometimes it just powers off and doesn't power back on.

      What i am trying to do
      I need to power off the usb so that i can click pictures from my camera and i click pictures once its powered off and then power on back the usb so that i can access the images on my raspberry pi. But these commands when used in code aren't working.

      I have tried using subprocess calls too as shown in the thread you sent

      Delete
    4. Twice or thrice it does happen, but then after some runs it doesn't

      Delete
  10. Replies
    1. as i'm using dronekit i have to use python 2

      Delete
  11. I then have to reboot as all my usbs have powered off

    ReplyDelete
  12. This is kind my sample code i'm trying to work on, if this works i can add the things i want. But this needs to work first. And in my all in one code, it's mostly not working.
    But this doesn't work. Like it does work sometimes, sometimes doesn't. and when its not working every part of my code works except the powering back on

    import signal, os, subprocess, sys
    import time
    import RPi.GPIO as GPIO
    from subprocess import call

    GPIO.setmode(GPIO.BOARD)
    GPIO.setwarnings(False)
    GPIO.setup(12, GPIO.OUT)

    i=0
    call(["sudo", "./hub-ctrl", "-h", "0", "-P", "2", "-p", "0"])
    time.sleep(2)
    while i<5:
    print("triggered")
    GPIO.output(12, True)
    time.sleep(1)
    GPIO.output(12, False)
    time.sleep(1)
    print("done")
    i=i+1
    print i

    print("enabling usb")
    #os.system("sudo ./uhubctl -a 1 -p 2 -R")
    call(["sudo", "./hub-ctrl", "-h", "0", "-P", "2", "-p", "1"])
    time.sleep(2)


    I've tried with os.system as well as subprocess.Popen
    None of them have given me stability and has ran properly always

    ReplyDelete
    Replies
    1. Hey There have you found a solution to your issue.

      Delete
  13. Good! All work! I copy hub-ctrl to /mnt/hubctrl and do:

    sudo /mnt/hubctrl/hub-ctrl -h 0 -P 2 -p 0 for USB off
    and
    sudo /mnt/hubctrl/hub-ctrl -h 0 -P 2 -p 1 for USB on

    ReplyDelete