Skip to content

Commit

Permalink
Wifi network config works, needs restart
Browse files Browse the repository at this point in the history
  • Loading branch information
brickbots committed Dec 2, 2023
1 parent 40945fc commit 01fd41a
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 124 deletions.
28 changes: 23 additions & 5 deletions python/PiFinder/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def home():
return template(
"index",
software_version=software_version,
wifi_mode="AP" if self.network.wifi_mode() == "AP" else "Client",
wifi_mode=self.network.wifi_mode(),
ip=self.network.local_ip(),
network_name=self.network.get_connected_ssid(),
gps_icon=gps_icon,
Expand Down Expand Up @@ -116,14 +116,32 @@ def network_page():
show_new_form=show_new_form,
)

@app.route("/network/delete/<network_id>")
@app.route("/network/add", method="post")
def network_update():
ssid = request.forms.get("ssid")
psk = request.forms.get("psk")
if len(psk) < 8:
key_mgmt = "NONE"
else:
key_mgmt = "WPA-PSK"

self.network.add_wifi_network(ssid, key_mgmt, psk)
return network_page()

@app.route("/network/delete/<network_id:int>")
def network_delete(network_id):
self.network.delete_wifi_network(network_id)
return network_page()

@app.route("/network/undelete/<network_id>")
def network_undelete(network_id):
self.network.undelete_wifi_network(network_id)
@app.route("/network/update", method="post")
def network_update():
wifi_mode = request.forms.get("wifi_mode")
ap_name = request.forms.get("ap_name")
host_name = request.forms.get("host_name")

self.network.set_wifi_mode(wifi_mode)
self.network.set_ap_name(ap_name)
self.network.set_host_name(host_name)
return network_page()

@app.route("/key_callback", method="POST")
Expand Down
154 changes: 80 additions & 74 deletions python/PiFinder/sys_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,100 +18,85 @@ def __init__(self):

def populate_wifi_networks(self):
"""
Uses wpa_cli to get current network config
Parses wpa_supplicant.conf to get current config
"""
self._wifi_networks = []

_net_list = wpa_cli("list_networks").split("\n")

# skip first two lines
for net in _net_list[2:]:
_net = net.split()
if len(_net) > 2:
self._wifi_networks.append(
{
"id": _net[0],
"ssid": _net[1],
"password": None,
with open("/etc/wpa_supplicant/wpa_supplicant.conf", "r") as wpa_conf:
network_id = 0
in_network_block = False
for l in wpa_conf:
if l.startswith("network={"):
in_network_block = True
network_dict = {
"id": network_id,
"ssid": None,
"psk": None,
"key_mgmt": None,
"status": "saved",
}
)

# need to call wpa_cli for each network to get key type
for net in self._wifi_networks:
_output = wpa_cli("get_network", net["id"], "key_mgmt")
net["key_mgmt"] = _output.split("\n")[-1].strip()
elif l.strip() == "}" and in_network_block:
in_network_block = False
self._wifi_networks.append(network_dict)
network_id += 1

elif in_network_block:
key, value = l.strip().split("=")
network_dict[key] = value.strip('"')

def get_wifi_networks(self):
return self._wifi_networks

def save_wifi_config(self):
def delete_wifi_network(self, network_id):
"""
Iterates through all wifi networks
actions changes indicated
saves config file
reconfigures wpi_supplicatn
Immediately deletes a wifi network
"""
self._wifi_networks.pop(network_id)

with open("/etc/wpa_supplicant/wpa_supplicant.conf", "r") as wpa_conf:
wpa_contents = list(wpa_conf)

with open("/etc/wpa_supplicant/wpa_supplicant.conf", "w") as wpa_conf:
in_networks = False
for l in wpa_contents:
if not in_networks:
if l.startswith("network={"):
in_networks = True
else:
wpa_conf.write(l)

for network in self._wifi_networks:
ssid = network["ssid"]
key_mgmt = network["key_mgmt"]
psk = network["psk"]

# Update networks
for network in self._wifi_networks:
if network["status"] == "deleted":
net_id = network["id"]
wpa_cli("disable_network", net_id)
wpa_cli("remove_network", net_id)

if network["status"] == "new":
new_id = wpa_cli("add_network").split("\n")[1].strip()
wpa_cli("set_network", new_id, "ssid", f'"{network["ssid"]}"')
print(wpa_cli("set_network", new_id, "key_mgmt", network["key_mgmt"]))
if network["key_mgmt"] == "WPA-PSK":
print(
wpa_cli(
"set_network", new_id, "psk", f'"{network["password"]}"'
)
)
wpa_cli("enable_network", new_id)

# Save config
wpa_cli("save_config")

# Reconfigure
wpa_cli("reconfigure")
wpa_conf.write("\nnetwork={\n")
wpa_conf.write(f'\tssid="{ssid}"\n')
if key_mgmt == "WPA-PSK":
wpa_conf.write(f'\tpsk="{psk}"\n')
wpa_conf.write(f"\tkey_mgmt={key_mgmt}\n")

wpa_conf.write("}\n")

self.populate_wifi_networks()

def undelete_wifi_network(self, network_id):
def add_wifi_network(self, ssid, key_mgmt, psk=None):
"""
Marks a wifi network as not deleted!
Add a wifi network
"""
for network in self._wifi_networks:
if int(network["id"]) == int(network_id):
network["status"] = "saved"
with open("/etc/wpa_supplicant/wpa_supplicant.conf", "a") as wpa_conf:
wpa_conf.write("\nnetwork={\n")
wpa_conf.write(f'\tssid="{ssid}"\n')
if key_mgmt == "WPA-PSK":
wpa_conf.write(f'\tpsk="{psk}"\n')
wpa_conf.write(f"\tkey_mgmt={key_mgmt}\n")

def delete_wifi_network(self, network_id):
"""
Marks a wifi network for deletion
Deletion happens on 'save'
"""
for network in self._wifi_networks:
if int(network["id"]) == int(network_id):
network["status"] = "deleted"
wpa_conf.write("}\n")

def add_wifi_network(self, ssid, key_mgmt, password=None):
"""
Add a wifi network to the network dictionary.
Creation happens on 'save'
"""
self._wifi_networks.append(
{
"id": len(self._wifi_networks),
"ssid": ssid,
"key_mgmt": key_mgmt,
"password": password,
"status": "new",
}
)
self.populate_wifi_networks()
if self._wifi_mode == "Client":
# Restart the supplicant
wpa_cli("reconfigure")

def get_ap_name(self):
with open(f"/etc/hostapd/hostapd.conf", "r") as conf:
Expand All @@ -121,6 +106,8 @@ def get_ap_name(self):
return "UNKN"

def set_ap_name(self, ap_name):
if ap_name == self.get_ap_name():
return
with open(f"/tmp/hostapd.conf", "w") as new_conf:
with open(f"/etc/hostapd/hostapd.conf", "r") as conf:
for l in conf:
Expand All @@ -142,11 +129,22 @@ def get_connected_ssid(self):
return _t.split(":")[-1].strip('"')

def set_host_name(self, hostname):
if hostname == self.get_host_name():
return
sh.sudo("hostname", hostname)

def wifi_mode(self):
return self._wifi_mode

def set_wifi_mode(self, mode):
if mode == self._wifi_mode:
return
if mode == "AP":
go_wifi_ap()

if mode == "Client":
go_wifi_cli()

def local_ip(self):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
Expand Down Expand Up @@ -188,6 +186,14 @@ def restart_pifinder():
return True


def restart_system():
"""
Restarts the system
"""
print("SYS: Initiating System Restart")
sh.sudo("shutdown", "-r", "now")


def go_wifi_ap():
print("SYS: Switching to AP")
sh.sudo("/home/pifinder/PiFinder/switch-ap.sh")
Expand Down
6 changes: 4 additions & 2 deletions python/PiFinder/ui/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class UIStatus(UIModule):
"WiFi Mode": {
"type": "enum",
"value": "UNK",
"options": ["AP", "Cli", "CANCEL"],
"options": ["AP", "Client", "CANCEL"],
"callback": "wifi_switch",
},
"Mnt Side": {
Expand Down Expand Up @@ -206,9 +206,11 @@ def wifi_switch(self, option):
self.message("Switch to AP", 10)
sys_utils.go_wifi_ap()
else:
self.message("Switch to Cli", 10)
self.message("Switch to Client", 10)
sys_utils.go_wifi_cli()

sys_utils.restart_system()

def shutdown(self, option):
if option == "System":
self.message("Shutting down", 10)
Expand Down
43 changes: 30 additions & 13 deletions python/views/network.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
</div>
<div class="card grey darken-2">
<div class="card-content">
<form action="/network_update" method="post" id="network_form" class="col s12">
<form action="/network/update" method="post" id="network_form" class="col s12">
<div class="row">
<div class="input-field col s12">
<select>
<option value="ap"
<select name="wifi_mode">
<option value="AP"
% if net.wifi_mode() == "AP":
selected
%end
>Access Point</option>
<option value="cli"
% if net.wifi_mode() == "Cli":
<option value="Client"
% if net.wifi_mode() == "Client":
selected
%end
>Client</option>
Expand All @@ -26,28 +26,41 @@
</div>
<div class="row">
<div class="input-field col s12">
<input placeholder="{{net.get_ap_name()}}" id="ap_name" type="text">
<input value="{{net.get_ap_name()}}" id="ap_name" type="text" name="ap_name">
<label for="host_name">AP Network Name</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input placeholder="{{net.get_host_name()}}" id="host_name" type="text">
<input value="{{net.get_host_name()}}" id="host_name" type="text" name="host_name">
<label for="host_name">Host Name</label>
</div>
</div>
</form>
</div>
<div class="card-action">
<a href="#" class="btn" onClick="document.getElementById('network_form').submit();">Update and Restart</a>
<a href="#modal_restart" class="btn modal-trigger">Update and Restart</a>
</div>
</div>
<div id="modal_restart" class="modal">
<div class="modal-content">
<h4>Save and Restart</h4>
<p>This will update the network settings and restart the PiFinder.
You may have to adjust your network settings to re-connect. Are you sure?</p>
</div>
<div class="modal-footer">
<a href="#" onClick="document.getElementById('network_form').submit();" class="modal-close btn-flat">Do It</a>
<a href="#!" class="modal-close btn-flat">Cancel</a>
</div>
</div>
<div class="row valign-wrapper" style="margin: 0px;">
<div class="col s10">
<h5 class="grey-text">Wifi Networks</h5>
</div>
<div class="col s2">
% if not show_new_form:
<a class="btn-floating btn-small grey" href="/network?add_new=1"><i class="material-icons">add</i></a>
% end
</div>
</div>
<div class="card grey darken-2">
Expand All @@ -59,14 +72,16 @@
<form class="col s12" action="/network/add" method="post" id="new_network_form">
<div class="row">
<div class="input-field col s12">
<input placeholder="SSID" id="ssid" type="text">
<input placeholder="SSID" id="ssid" type="text" name="ssid">
<label for="ssid">Name</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input placeholder="None" id="password" type="text">
<input placeholder="None" id="password" type="text" name="psk" class="validate" pattern=".{8,}">
<label for="password">Password</label>
<span class="helper-text" data-error="Too Short" data-success="">Min 8 Characters or leave None</span>

</div>
</div>
</form>
Expand All @@ -81,15 +96,17 @@
% include("network_item", network=network)
% end
</table>
<div class="card-action">
<a href="/network/save" class="btn">Save Changes</a>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems);
});
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.modal');
var instances = M.Modal.init(elems);
});
</script>

% include("footer.tpl")
Expand Down
Loading

0 comments on commit 01fd41a

Please sign in to comment.