How can I set up an auto-hotspot in DietPi when Wi-Fi is unavailable?

Hi everyone,
I’m trying to configure my DietPi system so that it automatically starts a Wi-Fi hotspot when it cannot connect to my regular Wi-Fi network.

My questions are:

Is there a built-in feature in DietPi that supports automatic hotspot fallback?

If yes, how exactly can I set it up?

Is there an official guide or recommended steps for enabling this?

Any help or links to documentation would be greatly appreciated.
Thanks!

There is no guide, it is not as trivial as it looks.

You would need to drop-in-configs, on for the client mode and one for the AP mode, but only one can be activate at the time.
Then you create a script which scans for your regular wifi network, if it’s not active switch the configs, bring down wpa_supplicant and start the services for the hotspot.

Vice verca if you want to go back.
Are you familiar with bash scripting? :sweat_smile:

as already said by @Jappe , DietPi don’t has such an option. You would need to create this on our own. We had a similar request years ago.But there was no solution found

Would this bash script work or do I need to do anything else

#!/bin/bash

PING_TARGET="8.8.8.8"

ping -c 1 -W 2 $PING_TARGET > /dev/null 2>&1
if [ $? -eq 0 ]; then
    echo "Internet available — no hotspot needed."
    exit 0
fi

echo "No Internet — starting hotspot services..."

# Bring up wlan0
ifup wlan0 --interfaces=/usr/local/etc/wlan0-hotspot.conf

# Start hostapd
systemctl start hostapd

# Start DHCP server
systemctl start isc-dhcp-server

exit 0

And start is as a service

I don’t understand your usecase, if you have no internet why woud you want a hotspot, also without internet?
I thought more like, if the regular wifi has no connection, start the hotspot. And the SBC has an ethernet connection so you have internet access via the hotspot?!

The problem with your script is, there is still the wlan0 block in your /etc/network/interfaces.

I would do it this way:

  • 2 drop-in-configs, symlink the one you need to /etc/network/interfaces.d
  • A script which checks which config is currently in use and also a check, if your regular wifi has connection / or if internet access is available (depending on what you actually want to achieve)
  • If your client config is currently active: bring wpa_supplicant service down, switch the drop-in-configs via symlink, start the services necessary for the hotspot
  • if the hotspot config is active and there is regular wifi / internet access available again: bring down the hotspot services, switch the configs, start wpa_supplicant

With this config you can not use dietpi-config anymore to change wifi settings, because then you will have multiple wlan0 blocks in you interface config. So if something changes you need to change your drop-in-configs manually

Here an idea how it could look like, you also need to run this script periodically so it checks e.g. every minute or so, via cron job or the more modern solution, via a systemd timer:

#!/bin/bash
# wlan_mode_switch.sh
# Symlink-based switch between Client and Hotspot mode

# --- config ---
WLAN_INTERFACE="wlan0"
CLIENT_SSID="myWiFi"  # SSID you wanna check if connection is available
INTERFACES_DIR="/etc/network/interfaces.modes"
ACTIVE_LINK="/etc/network/interfaces.d/active-wlan0"

# --- check if wifi is available ---
wifi_available() {
    iw dev "$WLAN_INTERFACE" scan 2>/dev/null | awk -v ssid="$CLIENT_SSID" '
        $1=="SSID:" && $2==ssid { exit 0 }
        END { exit 1 }'
}

# --- check which config is currently active ---
CURRENT_TARGET=$(readlink -f "$ACTIVE_LINK")

# --- Determine desired config ---
if wifi_available; then
    DESIRED_TARGET="$INTERFACES_DIR/wlan0-client"
else
    DESIRED_TARGET="$INTERFACES_DIR/wlan0-ap"
fi

# --- check if a switch of config is necessary---
if [[ "$CURRENT_TARGET" == "$DESIRED_TARGET" ]]; then
   # echo "$(date) - desired mode already active, no switch necessary"
    exit 0
fi

# --- switch mode ---
if [[ "$DESIRED_TARGET" == "$INTERFACES_DIR/wlan0-client" ]]; then
    #echo "$(date) - WiFi $CLIENT_SSID available → activate client mode"
    systemctl stop hostapd isc-dhcp-server
    systemctl stop wpa_supplicant

    ln -sf "$DESIRED_TARGET" "$ACTIVE_LINK"

    ifdown "$WLAN_INTERFACE" 2>/dev/null || true
    ifup "$WLAN_INTERFACE"

    systemctl start wpa_supplicant

elif [[ "$DESIRED_TARGET" == "$INTERFACES_DIR/wlan0-ap" ]]; then
    #echo "$(date) - WLAN $CLIENT_SSID not reachable→ activate hotspot"
    systemctl stop wpa_supplicant
    systemctl stop hostapd isc-dhcp-server

    ln -sf "$DESIRED_TARGET" "$ACTIVE_LINK"

    ifdown "$WLAN_INTERFACE" 2>/dev/null || true
    ifup "$WLAN_INTERFACE"

    systemctl start hostapd isc-dhcp-server
fi

# echo "$(date) - changed mode to $(basename "$DESIRED_TARGET")"

Then you need to set up the config files
/etc/network/interfaces.modes/wlan0-client
and
/etc/network/interfaces.modes/wlan0-ap

best would be you set up your regular wifi connection (this will also set up the wpa_supplicant.conf) and then copy the config from /etc/network/interfaces to the wlan0-client file.
Then you set up the hotspot and do the same for the wlan0-ap file. (This will also generate dhcpd and hostapd config)
Then you remove the wlan0 block from /etc/network/interfaces and don’t touch it again :smiley:

And last but not least, set up cron or systemd timer to let the script run periodically. The simplest solution would be a cron job, but if you want loggin via journalctl, you would need to set up a service and a timer for systemd.

1 Like

The use case is simple my family wants to use birdnet.go to see the birds but the wifi connection is very weak therefore I want to automatically check wifi connection if not open a hotspot and restart birdnet.go so birds can be checked via hotspot IP if available simple check via WLAN ip

Alright, so actual internet connection is not a concern, but if the WiFi is available and connected. So the method on my script idea does exactly this: check if the wifi is reachable and if not, start the hotspot!?

1 Like

Is there a best practice for

/etc/network/interfaces.modes/wlan0-client

and

/etc/network/interfaces.modes/wlan0-ap

Just copy the existing wlan0 config from your /etc/network/interfaces in there.
Beforehand create the directory:

sudo mkdir -p /etc/network/interfaces.modes

I’ll also test it on my Raspberry Pi 3B tonight.

TLDR;

I did not think about an important part:
You can not scan for networks when in AP / hotspot mode. Switching back would always require a manual trigger. Or you connect a wifi dongle, which can be used for scanning networks.


So here the steps I did for testing:

On a fresh system:

  1. activate onboard-wifi and reboot.
  2. scan for wifi and connect to it via dietpi-config. Set it also to a static address
  3. copy the wlan0 block from /etc/network/interfaces to the drop-in config /etc/network/interfaces.modes/wlan0-client
  4. install wifi hotspot, I got an error, because the static IP was still assigned to the interface. I did sudo ip addr flush dev wlan0, then started the hotspot again, successfully this time
  5. copy the new wlan0 block from /etc/network/interfaces to the drop-in config /etc/network/interfaces.modes/wlan0-ap
  6. create the symlink sudo ln -s /etc/network/interfaces.modes/wlan0-ap /etc/network/interfaces.d/active-wlan0
  7. remove the wlan0 block from /etc/network/interfaces
  8. restart the hotspot sudo systemctl restart isc-dhcp-server

the hotspot is now active, there is no wlan0 block in /etc/network/interfaces, so the symlink seems to work. I will now create the script (see post above) and make it executable, for testing I have it just in my root dir

chmod +x ~/wlan_mode_switch.sh

I will also change the SSID inside the script to a non-existing to trigger the switch.

OK I did not work, something is wrong with the logic. I tricked it tho, and the switch triggered nethertheless. So the device is now connected also via WiFi, I connected via Wifi and SSH for testing. It’s working, yay :smiley:

Also when I switch it back (with some trickery inside the script), the hotspot is visible on my phone, so this is also working, yay! :smiley:

But there is another problem I did not think about:
You can not scan for networks when you are in AP mode. We could split the script, one part runs every minute or so and checks for the wifi, if it’s gone we go into hotspot mode.
And then we create another script which we need to execute manually - to switch back to client mode.

Or you could connect a wifi dongle, so you’re always able to scan.

But if I first gone out of the ap mode and do than the scan why it should not work than?

Like this

#!/bin/bash
# wlan_mode_switch.sh
# Symlink-based switch between Client and Hotspot mode

# --- config ---
WLAN_INTERFACE="wlan0"
CLIENT_SSID="myWiFi"  # SSID you wanna check if connection is available
INTERFACES_DIR="/etc/network/interfaces.modes"
ACTIVE_LINK="/etc/network/interfaces.d/active-wlan0"

# --- check if wifi is available (with AP services stopped first) ---
wifi_available() {

    # Stop hotspot services to allow scanning
    systemctl stop hostapd isc-dhcp-server 2>/dev/null || true

    # Small delay to ensure interface is released
    sleep 1

    iw dev "$WLAN_INTERFACE" scan 2>/dev/null | awk -v ssid="$CLIENT_SSID" '
        $1=="SSID:" && $2==ssid { exit 0 }
        END { exit 1 }'
}

# --- check which config is currently active ---
CURRENT_TARGET=$(readlink -f "$ACTIVE_LINK")

# --- Determine desired config ---
if wifi_available; then
    DESIRED_TARGET="$INTERFACES_DIR/wlan0-client"
else
    DESIRED_TARGET="$INTERFACES_DIR/wlan0-ap"
fi

# --- check if a switch of config is necessary ---
if [[ "$CURRENT_TARGET" == "$DESIRED_TARGET" ]]; then
    exit 0
fi

# --- switch mode ---
if [[ "$DESIRED_TARGET" == "$INTERFACES_DIR/wlan0-client" ]]; then

    systemctl stop hostapd isc-dhcp-server
    systemctl stop wpa_supplicant

    ln -sf "$DESIRED_TARGET" "$ACTIVE_LINK"

    ifdown "$WLAN_INTERFACE" 2>/dev/null || true
    ifup "$WLAN_INTERFACE"

    systemctl start wpa_supplicant

elif [[ "$DESIRED_TARGET" == "$INTERFACES_DIR/wlan0-ap" ]]; then

    systemctl stop wpa_supplicant
    systemctl stop hostapd isc-dhcp-server

    ln -sf "$DESIRED_TARGET" "$ACTIVE_LINK"

    ifdown "$WLAN_INTERFACE" 2>/dev/null || true
    ifup "$WLAN_INTERFACE"

    systemctl start hostapd isc-dhcp-server
fi

Yes you can do that, but that brings the AP down, every minute or howoften you wanna scan for the other network

Yes that’s clear but this is the consequence so I will simply do it every 15 or 30 min

So a new problem, you bring the services down for scanning, but if the regular wifi not available they do not come back up, so we need to restart them, if this is the case.

if [[ "$CURRENT_TARGET" == "$DESIRED_TARGET" ]]; then
    echo "$(date) - desired mode already active, no switch necessary"

    # If AP mode, ensure hotspot services are running
    if [[ "$CURRENT_TARGET" == "$INTERFACES_DIR/wlan0-ap" ]]; then
        systemctl start hostapd isc-dhcp-server
    fi

    exit 0
fi

Hm but the scan is not working for me, it can not find my wifi but it’s on. SOmething is wrong with

iw dev "$WLAN_INTERFACE" scan 2>/dev/null | awk -v ssid="$CLIENT_SSID" '
        $1=="SSID:" && $2==ssid { exit 0 }
        END { exit 1 }'
}

Alrighty, the leading spaces of the output were the problem I guess. With the following script I could reliably switch between the modes. I also increased the sleep time and do multiple scans.

#!/bin/bash
# wlan_mode_switch.sh
# Symlink-based switch between Client and Hotspot mode

# --- config ---
WLAN_INTERFACE="wlan0"
CLIENT_SSID="mySSID"  # SSID you wanna check if connection is available
INTERFACES_DIR="/etc/network/interfaces.modes"
ACTIVE_LINK="/etc/network/interfaces.d/active-wlan0"

# --- check if wifi is available ---
wifi_available() {

# Stop hotspot services to allow scanning
systemctl stop isc-dhcp-server
systemctl stop hostapd

# Force interface back to managed mode
ip link set "$WLAN_INTERFACE" down
iw dev "$WLAN_INTERFACE" set type managed
ip link set "$WLAN_INTERFACE" up

sleep 5
echo "stopped hotspot for scanning"

for i in {1..5}; do
    if iw dev "$WLAN_INTERFACE" scan 2>/dev/null | sed 's/^[[:space:]]*//' | grep -Fxq "SSID: $CLIENT_SSID"; then
        return 0
    fi
    sleep 2
done
return 1

}

# --- check which config is currently active ---
CURRENT_TARGET=$(readlink -f "$ACTIVE_LINK")

# --- Determine desired config ---
if wifi_available; then
    DESIRED_TARGET="$INTERFACES_DIR/wlan0-client"
echo "wifi $CLIENT_SSID is available"
else
    DESIRED_TARGET="$INTERFACES_DIR/wlan0-ap"
echo "$CLIENT_SSID is not available"
fi

# --- check if a switch of config is necessary---
if [[ "$CURRENT_TARGET" == "$DESIRED_TARGET" ]]; then
    echo "$(date) - desired mode already active, no switch necessary"

    if [[ "$CURRENT_TARGET" == "$INTERFACES_DIR/wlan0-ap" ]]; then
        systemctl start hostapd
        systemctl start isc-dhcp-server
    fi

    exit 0
fi

# --- switch mode ---
if [[ "$DESIRED_TARGET" == "$INTERFACES_DIR/wlan0-client" ]]; then
    echo "$(date) - WiFi $CLIENT_SSID available → activate client mode"
    systemctl stop isc-dhcp-server
    systemctl stop hostapd

    ln -sf "$DESIRED_TARGET" "$ACTIVE_LINK"

    ifdown "$WLAN_INTERFACE" 2>/dev/null || true
    ifup "$WLAN_INTERFACE"

    systemctl start wpa_supplicant

elif [[ "$DESIRED_TARGET" == "$INTERFACES_DIR/wlan0-ap" ]]; then
    echo "$(date) - WLAN $CLIENT_SSID not reachable→ activate hotspot"
    systemctl stop wpa_supplicant

    ln -sf "$DESIRED_TARGET" "$ACTIVE_LINK"

    ifdown "$WLAN_INTERFACE" 2>/dev/null || true
    ifup "$WLAN_INTERFACE"

    systemctl start hostapd
    systemctl start isc-dhcp-server
fi

echo "$(date) - changed mode to $(basename "$DESIRED_TARGET")"

Cool for helping because I do it right now in my mind only being on a business trip so one more week than I can check

1 Like

This script is running perfectly thanks for the help …

Happy x mas and new year