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?
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
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
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.
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!?
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:
activate onboard-wifi and reboot.
scan for wifi and connect to it via dietpi-config. Set it also to a static address
copy the wlan0 block from /etc/network/interfaces to the drop-in config /etc/network/interfaces.modes/wlan0-client
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
copy the new wlan0 block from /etc/network/interfaces to the drop-in config /etc/network/interfaces.modes/wlan0-ap
create the symlink sudo ln -s /etc/network/interfaces.modes/wlan0-ap /etc/network/interfaces.d/active-wlan0
remove the wlan0 block from /etc/network/interfaces
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
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!
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.
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
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")"