Raspberry Pi Zero W As WiFi USB Media Device

by Martí Curie in Circuits > Raspberry Pi

7568 Views, 10 Favorites, 0 Comments

Raspberry Pi Zero W As WiFi USB Media Device

Elegoo Pi as smart usb.png

In this tutorial I will explain how to convert a Raspberry pi Zero W into a USB Drive emulator that can be accessed within a local network. This can be useful to transfer files into devices that have a USB connection but not a WiFi or any internet connectivity.

The main scope of this tutorial is to provide a working guide for this process because the tutorials that I have followed did not work for several reasons.

I am by no means an expert and the following tutorial is not guaranteed to work, if you find any errors I will be happy to correct them :)

These are the sources I have used:

https://www.instructables.com/The-Ultimate-Headles...

https://magpi.raspberrypi.org/articles/pi-zero-w-s...

1.Setting Up Raspberry Pi OS

Hardwarewise, we need a Raspberry Pi Zero W, a USB to micro USB cable and a micro SD Card.

First you need to download the Raspberry Pi OS via your preferred etching method. I use the Rarpberry Pi imager because it is an all in one solution that englobes disk imaging and OS writting and verification.

We will also need to install Putty to access the raspberry pi over ssh.

We will install the Raspberri Pi OS Lite to lower power consumption. To do so, we launch Rarpberry Pi imager and on OS select Raspberry Pi OS (other) → Raspberry Pi OS Lite. We then choose the storage medium (we need a micro SD card when using a Raspberry pi Zero W).

Afterwards we need to enable ssh and the WiFi connection for our Raspberry Pi. For that we need to paste the attached files on the newly formatted micro SD Card. (you will have to disconnect and reconnect it, because the Raspberry Pi Imager automatically expells the micro SD Card).

Now we open the file we have pasted called wpa_supplicant.conf with a text editor like sublime text (try to use a text editor that does not add formatting to the text, avoid word and such).

country= INSERT YOUR COUNTRY CODE HERE
update_config=1
ctrl_interface=/var/run/wpa_supplicant

network={
 scan_ssid=1
 ssid="WIFI SSID HERE"
 psk="WIFI PASSWORD HERE"
}<br>

You can searh your coutry code here. The wifi SSID and the password must be within quotes "like this", the country code must not.

Now your raspberry pi should be able to connect to your WiFi.

To check safely eject the Micro SD card, place it on your Raspberry Pi and power it on by connecting the micro USB cable to your computer (use the PWR Port of the Raspberry Pi for this). Then acces your router and check if there is any new device connected to it. If there is take note of the IP address (we will need it later), if there isn't there is something wrong with your network connection or with the credentials you placed on the wpa_supplicant.conf file.

2.Enable the USB Driver

Next, we need to enable the USB driver which provides the gadget modes, by editing two configuration files.

sudo nano /boot/config.txt

Scroll to the bottom with the arrowr and append the line below:

dtoverlay=dwc2

Press CTRL+X to quit, press Y to save the changes and press Enter to save them on the current file.

We also need to change the modules file:

sudo nano /etc/modules

And on the end of the file we paste the following:

dwc2

Again we press CTRL+X to quit, press Y to save the changes and press Enter to save them on the current file.

Finally we need to make sure the Raspberry Pi enables the USB driver on boot so we go to the following file:

sudo nano /boot/cmdline.txt

We need to be very careful every command that will be executed is on the only line there is and needs a space after and before the next command. There should be a space also on the end, and make sure there is an empty second line in the file. On the end of the first line add:

 modules-load=dwc2 

With a space before and after and making sure there is always a second line.

Finally Stop the Raspberry Pi with:

sudo halt

3.Switch to USB Power

photo6023978622810960629.jpg
photo6023978622810960630.jpg
photo6023978622810960627.jpg
photo6023978622810960628.jpg

Now change the cable connection from the PWR port to the USB port in the Raspberry Pi. And connect it to your computer. It will most likely not recognize it at first or recognize it as an Unknown USB device. Do not worry, we will fix it.

In case you want to use this on a device that powers on and off you might want to use a sligtly modified cable for the data transmission to prevent any damage to the Raspberry Pi because of different 5V sources going in your Raspberry Pi. To make such a cable you can either cut open a micro USB cable and cut the red cable within the cable. Or you can go the non destructive approach, which is to attach some scotch tape to the rightmost connector on the USB A side of the cable to prevent the 5V contact from electrically connecting to the socket.

(see pictures).

4.Create the USB File

First we need to create a file that will hold our files within the SD card. To do so we will use the dd command native to linux. This file will emulate the USB flash drive that your device will be seing.

The command below will create an empty 2GB binary file (change the count=2048 parameter if you want a different size). Please note that this will be limited by the available free space on your SD card (check the Avail column in df -h), and it may take a few minutes to complete the setup:

sudo dd bs=1M if=/dev/zero of=/piusb.bin count=2048 

We now need to format the file as a FAT32 file system so that the TV can understand it. Enter the command below:

sudo mkdosfs /piusb.bin -F 32 -I

5.Mount USB File

First, we create a folder where we can mount the USB:

sudo mkdir /mnt/usb_share 

We add the folder to fstab, the configuration file that records our available disk partitions:

sudo nano /etc/fstab 

To add the folder we need to append this line to the end of the file:

/piusb.bin /mnt/usb_share vfat users,umask=000 0 2 

Press CTRL+X to quit, press Y to save the changes and press Enter to save them on the current file.

The line we added to fstab allows the USB file system to be error-checked and mounted automatically at boot time. Instead of rebooting, we can manually reload fstab with the command below:

sudo mount -a

Finally we need to remount this partition after every boot. To do so we have to go into "rc.local" and add some lines to re-activate our USB devices:

sudo nano /etc/rc.local

Copy the following just on the line above the line that says "exit 0" so that "exit 0" remains the last line of the file:

/bin/sleep 5
/sbin/modprobe g_multi file=/piusb.bin stall=0 removable=1
sudo mount -o ro /piusb.bin /mnt/usb_share

The above lines make the thumb drive read only for Linux and write/read for Windows. If you want this to be the other way around, use this instead: (basically remove ro from the bottom and add ro=1 to the middle line)

/bin/sleep 5
/sbin/modprobe g_multi file=/piusb.bin stall=0 removable=1 ro=1
sudo mount -o /piusb.bin /mnt/usb_share

6.Test USB Mounting and Unmounting

Now we will test the connection and disconnection of the USB drive. To do so you need to have it plugged in on any PC to see when it is "inserted" and "removed" from the PC. (It is not removed nor inserted for real but with the following commands we emulate that behaviour).

Connect via ssh to the Raspberry Pi and execute the following commands:

To "Insert" the USB drive:

sudo /sbin/modprobe g_multi file=/piusb.bin stall=0 removable=1

To "Remove" the USB drive:

sudo /sbin/modprobe g_multi -r

If you see the USB drive appear and disappear on your PC we are on the right track. (Otherwise try to check the device manager or the disk manager to see if your device is propperly recognized).

7.Install and Configure Samba for Remote File Acess

Now we will provede network access to the /mnt/usb_share folder so that it can be accessed remotely. For that we just need to install the Samba packages with the following commands:

sudo apt-get update
sudo apt-get install samba winbind -y

When the installation is complete, we need to configure a Samba network share. If you want to add a password or some other protection measurements you can go to wiki.samba.org for further information. We proceed without password because we are in a local network which is not exposed to the internet. To configure the share we acess the samba configuration file with the following command:

sudo nano /etc/samba/smb.conf

Go down to the end of the file with the arrow keys and paste the lines below:

[usb]
browseable = yes
path = /mnt/usb_share guest ok = yes<br>read only = no create mask = 777

Press CTRL+X to quit, press Y to save the changes and press Enter to save them on the current file.

We have to restart the Samba service for the changes to take place:

sudo systemctl restart smbd.service

8.Access the Shared Folder

Now we will try to access the shared folder remotely via the Raspberry Pi IP Adress. To do so we need to use the IP Address you have responsably written down in step 1. Otherwise you can either acess your router and search for the Raspberry Pi IP address, or use an application like Angry IP Scanner.

Once you have the IP Address you just need to write on your windows explorer address bar (the one on top of every explorer window (for example C:\User\Programs) the following:

\\your ip address 
for example one could be (\\192.168.1.169)

An alternative that might work if you have no other Raspberry Pi connected to the network is to access it by its host name which should be the following:

\\Your host name

This should bring you to a folder called usb, where you should be able to write and read files.

9.Automate USB Device Reconnect

Now we need to automatically "remove and insert" the USB drive from the device it is connected to every time there is a file change via the network so that the USB updates its files and the device it is connected to can see the new files. To do so first we need to perform an update and install python with the following commands:

sudo apt-get update
sudo apt-get install python-pip

Afterwards we need to install watchdog which will be the library used to check every time there is a file change. Since we are using a raspberry pi it will most likely have an old python version (2.7) so we need to install an old version of watchdog for python 2.7. We do it with the following command:

sudo pip install watchdog==0.10.6

Now that we have all the needed libraries we will make our own python script that will check every time there is a change within the USB folder. This is a slightly modified version of the file published by Russell Barnes in his article about the same topic. To create the new file on the folder usr/local/share we use the following command:

sudo nano /usr/local/share/usbshare.py

Once you have the blank file open you have to copy the following code to it:

#!/usr/bin/python3
import time
import os
from watchdog.observers import Observer
from watchdog.events import *

CMD_MOUNT = "modprobe g_mass_storage file=/piusb.bin stall=0 ro=1"
CMD_UNMOUNT = "modprobe -r g_mass_storage"
CMD_SYNC = "sync"

WATCH_PATH = "/mnt/usb_share"
ACT_EVENTS = [DirDeletedEvent, DirMovedEvent, FileDeletedEvent, FileModifiedEvent, FileMovedEvent]
ACT_TIME_OUT = 30

class DirtyHandler(FileSystemEventHandler):
    def __init__(self):
        self.reset()

    def on_any_event(self, event):
        if type(event) in ACT_EVENTS:
            self._dirty = True
            self._dirty_time = time.time()

    @property
    def dirty(self):
        return self._dirty

    @property
    def dirty_time(self):
        return self._dirty_time

    def reset(self):
        self._dirty = False
        self._dirty_time = 0
        self._path = None


os.system(CMD_MOUNT)

evh = DirtyHandler()
observer = Observer()
observer.schedule(evh, path=WATCH_PATH, recursive=True)
observer.start()

try:
    while True:
        while evh.dirty:
            time_out = time.time() - evh.dirty_time

            if time_out >= ACT_TIME_OUT:
                os.system(CMD_UNMOUNT)
                time.sleep(1)
                os.system(CMD_SYNC)
                time.sleep(1)
                os.system(CMD_MOUNT)
                evh.reset()

            time.sleep(1)

        time.sleep(1)

except KeyboardInterrupt:
    observer.stop()

observer.join() 

Press CTRL+X to quit, press Y to save the changes and press Enter to save them on the current file.

Aftewards we need to prevent the file from being overwritten by making it executable only. To do so we use the following command:

sudo chmod +x /usr/local/share/usbshare.py<br>

​10.Start Script on Boot

Finally we need to make sure that this script runs everytime we boot the raspberry pi. For that we will first create a file where we well define the service we want to run at boot.

First we create the file:

 sudo nano /lib/systemd/system/sample.serviceAdd 

Then we paste the following in the blank file:

[Unit]  Description=My Sample Service  After=multi-user.target
[Service]  Type=idle  ExecStart=/usr/bin/python /home/pi/sample.py
[Install]  WantedBy=multi-user.target

Press CTRL+X to quit, press Y to save the changes and press Enter to save them on the current file.

This defines a new service called “Sample Service” and we are requesting that it is launched once the multi-user environment is available. The “ExecStart” parameter is used to specify the command we want to run. The “Type” is set to “idle” to ensure that the ExecStart command is run only when everything else has loaded. Note that the paths are absolute and define the complete location of Python as well as the location of our Python script.

In order to store the script’s text output in a log file you can change the ExecStart line to:

 ExecStart=/usr/bin/python /home/pi/sample.py > /home/pi/sample.log 2>&1

The permission on the unit file needs to be set to 644 :

 sudo chmod 644 /lib/systemd/system/sample.service

Now the unit file has been defined we can tell systemd to start it during the boot sequence :

sudo systemctl daemon-reload
sudo systemctl enable sample.service

Reboot the Pi and our python script should run automatically from boot:

sudo reboot

Now It Should Work :)

Now it should be working. At first it might give you an error of unrecognized but if you wait for a bit the Raspberry Pi appears as a Flash drive on your device. I have tried and it does not work with every device, I have had it working mainly with computers, but it seemed not to work with my Elegoo Mars Printer.

Hope it was useful :D