DIY Smart Wifi USB with Pi Zero W and a Captive Portal

by CPunch

raspberrypi nodejs

Recently I made a post about how to SSH into a Pi Zero over USB. The Raspberry Pi Zero W lets us create some amazing USB projects. Today I'm going to share a project I made over the summer that uses the Pi Zero W and really takes advantage of it's small form-factor, and cool USB capabilities. It's a smart-USB storage device! This allows you to plug into any usb port (TV, Laptop, etc.) and wirelessly transfer files to a virtual USB Flash drive. This lets you play videos from your phone on your TV, upload your favorite photos and share with others. You can also download uploaded data from the captive portal, delete files to make more space, or even tell others to connect to it so they can download data. I made this using NodeJS, and while the frontend (and possibly the backend too :eyes:) might not look the best, it's a very practical project that was exciting to create!


The repository with all the code like always, is here.



What you need

  • Raspberry Pi Zero W
  • USB Cable (with data pins!) plugged into the "USB" port or a USB Dongle case like the one I have in the picture above.
  • Latest Raspbian already flashed on a MicroSD card and in your Pi Zero W


Installation


Before installing, make sure everything is up-to-date

sudo apt update
sudo apt upgrade -y


Enable USB Driver (Skip this if you followed my SSH over USB post)


Modify /boot/config.txt and add

dtoverlay=dwc2

Append this to /etc/modules & reboot to load the module

dwc2


Make USB Container File


Make a 2GB bin file. You can change the ammount of MB by changing the count (this may take a while)

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

Format the bin as FAT32

sudo mkdosfs /piusb.bin -F 32 -I


Mount container


Make the directory we'll be using to mount too

sudo mkdir /mnt/usb_share

Append this to /etc/fstab

/piusb.bin  /mnt/usb_share  vfat    users,umask=00  0   02

This will mount the driver automatically and allow for error-checking on boot.


Install NodeJS


Download the binaries (Check for latest version here)

wget https://nodejs.org/dist/v10.16.3/node-v10.16.3-linux-armv6l.tar.xz

Extract the tar file

tar xf node-v10.15.3-linux-armv6l.tar.xz

Install Node and NPM

cd node-v10.15.3-linux-armv6l/
sudo cp -R * /usr/local/

Verify the installation by

npm -v
node -v

Go back to your home directory

cd ~


Install PiStick


Make sure git is installed

sudo apt install git -y

Clone this repository

git clone https://github.com/CPunch/PiStick.git

Install Dependencies

cd PiStick/PiStick-WebServer
sudo chmod +x install.sh
./install.sh

Test and make sure WebServer is running

sudo node start.js

Now we need to make sure it starts when booting, edit /etc/rc.local and put this right before exit 0

cd /home/pi/PiStick/PiStick-WebServer
node start.js &


Install HostAPD and make the Captive Portal

Make sure to do this step LAST. After running an accesspoint you will NOT be able to access the internet from your pi after reboot unless you stop the HostAPD service yourself.


Install dnsmasq and hostapd

sudo apt-get install dnsmasq hostapd

Setup static address in dhcpcd, append this to /etc/dhcpcd.conf

interface wlan0
    static ip_address=192.168.4.1/24
    nohook wpa_supplicant

Setup DNSMASQ, move conf file and make a new one.

sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig  
sudo nano /etc/dnsmasq.conf

Type or copy this into the file

interface=wlan0      # Use the require wireless interface - usually wlan0
  dhcp-range=192.168.4.2,192.168.4.20,255.255.255.0,24h
address=/#/192.168.4.1 # redirect to our captive portal

That configures the addresses to lease and the lease time. It also redirects all traffic to our captive portal!

Now, configure hostapd located at /etc/hostapd/hostapd.conf

interface=wlan0
driver=nl80211
ssid=pistick
country_code=US
hw_mode=g
channel=7
wmm_enabled=0
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=Pi_Stick
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP

Defaults: SSID: pistick Passphrase: Pi_Stick

Feel free to change this!


Now we need to tell hostapd where to find that file, edit /etc/default/hostapd and add this at the top

DAEMON_CONF="/etc/hostapd/hostapd.conf"

Now you need to reload the services.

sudo systemctl enable dnsmasq
sudo systemctl enable hostapd


NOTE if you get an error about hostapd.service being masked, run this:

sudo systemctl unmask hostapd
sudo systemctl daemon-reload
sudo systemctl start hostapd
sudo systemctl enable hostapd


Now the installation is done, reboot!

sudo reboot


Plug your Pi into your computer. Wait for it to boot and a USB mass storage device will show up! You can now go on your phone, go to wifi and try to connect to 'pistick' (or whatever you renamed the SSID to). It'll open the captive portal where you can upload your files!


Aug 29, 2019 by CPunch
Sep 18, 2019 by sankar

Hi thank you I will do it and update you soon...

Sep 17, 2019 by CPunch

hi sankar, I had the same problem, unfortunately I couldn't read the new file contents of the mounted drive through the nodejs app, so I made the drive read only to prevent conflict. You can enable the writing by removing ro=1 from the mount script (https://github.com/CPunch/PiStick/blob/master/PiStick-WebServer/shell_scripts/mount.sh) This Stackoverflow question explains why it's difficult to achieve this functionality https://raspberrypi.stackexchange.com/questions/90823/using-a-rpi-zero-to-build-a-wifi-usb-stick-with-modprobe-g-mass-storage

Sep 17, 2019 by sankar

Hi thank you so much for providing such great tutorial on raspberry pi zero as USB stick I tried this it is working fine but am unable to write data to USB stick through USB not wifi ,it is asking write permissions please give me solution how to make write permission to our USB stick through PC. Thank you.