Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configure WiFi options from the UI - Menu #131

Closed
6 tasks done
mtlynch opened this issue Aug 14, 2020 · 17 comments
Closed
6 tasks done

Configure WiFi options from the UI - Menu #131

mtlynch opened this issue Aug 14, 2020 · 17 comments
Assignees
Labels
enhancement New feature or request large

Comments

@mtlynch
Copy link
Contributor

mtlynch commented Aug 14, 2020

TinyPilot users can currently configure their devices for WiFi via the command-line, but it would be good if we offered a path to do it right from the web UI.

Tasks

@mtlynch
Copy link
Contributor Author

mtlynch commented Oct 31, 2023

Bumping priority as I recently received a request to enable this.

@scott-tp scott-tp changed the title Configure WiFi options from the UI Configure WiFi options from the UI - Menu May 21, 2024
@scott-tp
Copy link

This will likely be a popup that allows the user to input the needed information.

@scott-tp scott-tp added the enhancement New feature or request label May 21, 2024
@jotaen4tinypilot jotaen4tinypilot self-assigned this Jun 7, 2024
@jotaen4tinypilot
Copy link
Contributor

Just a quick question as I’m starting to look into this: we want this to be a Community feature, right, not a Pro-exclusive one?

@scott-tp
Copy link

scott-tp commented Jun 7, 2024

@jotaen4tinypilot That's a good question!

Let's make it a Community feature as I think a UI change like this makes sense to go across both versions. It isn't really a new "feature" that we would want to wall off.

@jotaen4tinypilot
Copy link
Contributor

jotaen4tinypilot commented Jun 11, 2024

I’ve started to look into this ticket and wanted to discuss some initial thoughts, to make sure this is going into the right direction.

UI

Here are some mockups of how the UI of the WiFi dialog could look. The mockups are not meant to be pixel-perfect, but they should rather give an initial impression of the overall look-and-feel of the feature.

Initial/Empty state

When the user didn’t have a previous WiFi config.

Screenshot 2024-06-11 at 20 43 40

Invalid credentials / unsuccessful connection

When the user entered a WiFi config, but the device wasn’t able to connect – e.g., due to invalid credentials, or the wireless network being unreachable.

Screenshot 2024-06-11 at 21 03 40

Edit/Connected state

When the user entered a WiFi config, and the device is currently using it.

Screenshot 2024-06-11 at 21 46 45

Technical considerations

Reboot

It seems that the default way to effectuate WiFi settings on a RaspberryPi device requires a system reboot. While we already know how to implement that (e.g., in the “Hostname” dialog), we typically try to avoid reboots: they are inconvenient for the user as they take a while (like 20–30 seconds), and they also always carry the subtle risk that something goes wrong – e.g. that the UI cannot re-establish the connection to the backend automatically, which either results in an error message, or in an eternal loading spinner.

There seem to be alternative options to apply WiFi settings programmatically on the RaspberryPi which don’t require a system reboot, so I suggest to research this and see whether we find a good way that’s reliable enough for our purposes.

Potential error scenarios

It currently looks like there are no major error scenarios that we have to consider. So far, I can think of the following:

  • Invalid WiFi Credentials: Fortunately, it seems that the operating system is fault-tolerant in cases where e.g. the WiFi credentials are incorrect or the desired WiFi network is not reachable. In these cases, the OS automatically falls back to using the wired Ethernet connection, so the user doesn’t lose access to their device. This eliminates a lot of complexity.
  • Side-Effects: I’m not 100% certain whether configuring WiFi could have any potential side effects with other networking features. I’m thinking of the “Static IP” feature in particular, because I remember that there might have been some sort of implication there with regards to wireless connections. I could well be mistaken here, though. I was hoping to briefly discuss this in our Dev Meeting tomorrow, as I think Jason should know about this. (I’ve already put it on the agenda.)

Configuring WiFi programmatically

I’m not sure whether using the raspi-config nonint command (as suggested in our FAQ) is the best way for us to read or edit the WiFi settings programmatically. It seems that the raspi-config command (even in the nonint “non-interactive” version) is primarily meant to be invoked by humans, and it might not be powerful enough to support all operations we need. It might be better for us to go via the /etc/wpa_supplicant/wpa_supplicant.conf file directly, which is where the OS stores the WiFi settings.

Tasks

Based on the discussion above, I’d suggest the following task break down:

  • Research options to apply WiFi settings without reboot
    • We should do this first, because it would affect the subsequent tasks
  • Find most suitable way to access and alter the WiFi configuration programmatically
    • This potentially includes adding new privileged scripts to bundle the commands we have to invoke.
  • Implement backend HTTP endpoints and configuration logic
  • Implement frontend

All in all, I’d estimate this feature as “large”, and I currently wouldn’t expect any major complications.

@jdeanwallace
Copy link
Contributor

@jotaen4tinypilot - RE:

Find most suitable way to access and alter the WiFi configuration programmatically

We have 2 existing scripts that enable/disable the WiFi access point, namely:

From what I can see, they might not require a reboot (haven't tested).

I’m not 100% certain whether configuring WiFi could have any potential side effects with other networking features. I’m thinking of the “Static IP” feature in particular, because I remember that there might have been some sort of implication there with regards to wireless connections.

Yes, currently enabling/disabling the WiFi using the above scripts nukes any Static IP config too:

Note: Running this script will clear any potentially existing custom static IP
configuration that might have been added previously by the set-static-ip
script.

@jotaen4tinypilot
Copy link
Contributor

@jdeanwallace thanks for chiming in! Wouldn’t configuring the device to act as WiFi access point be something slightly different from this task, though? My reading was that this task is about configuring the device so that it connects wirelessly to an existing WiFi network, whereas setting up a WiFi access point would be about configuring the device so that it broadcasts it’s own private WiFi network, independent of any existing WiFi network.

For just storing the WiFi connection parameters, I think we primarily have to touch /etc/wpa_supplicant/wpa_supplicant.conf, but e.g. we don’t have to touch /etc/dhcpcd.conf, so I’m not sure yet whether we would really conflict with the Static IP feature here. I haven’t fully reproduced what the raspi-config tool is doing, though, so I’m not 100% certain here yet.

@scott-tp
Copy link

We had a bit of discussion related to wifi and static ips recently here: https://github.com/tiny-pilot/tinypilot-pro/issues/1340

Yes, this is more about getting to a dual NIC setup (Wi-Fi and wired at this point)

@jdeanwallace
Copy link
Contributor

jdeanwallace commented Jun 12, 2024

Wouldn’t configuring the device to act as WiFi access point be something slightly different from this task, though?

Oh yes, you're right. I didn't register the "access point" part. My mistake.

@jotaen4tinypilot
Copy link
Contributor

Okay, I’ve added a task list to the initial ticket description, which we can update as we move along.

@jotaen4tinypilot
Copy link
Contributor

Brief intermediate update: regarding sub-tasks (a) and (b), I’ve set up a draft PR containing two privileged scripts that would seem viable and that would address both requirements at once. I’ve asked Charles for some initial feedback, to validate/double-check the basic approach.

@jotaen4tinypilot
Copy link
Contributor

Re the “Potential error scenarios”, I realized that there is an additional error scenario: if the user is on a WiFi connection and no Ethernet cable is plugged in, and the user then either changes or disables the WiFi configuration, they’d effectively lose access to their device. The “fix” would be to plug in an Ethernet cable again, and change or reenable the WiFi configuration.

We already had a similar problem with the “Static IP” feature, where the device theoretically could have lost network access if the router didn’t accept the desired static IP. Our solution there was to have a device-side logic, that would check whether the device has become unreachable, and then automatically revert the static IP settings. We can do something similar for WiFi, although I’m not sure we really need that – my thinking is this:

  • Plugging in an Ethernet cable is a relatively cheap and obvious solution for users. That’s different from static IP, where the manual fix would be much more complicated to carry out.
  • We can display a warning inside the WiFi dialog if the user is currently exclusively on a WiFi connection without an Ethernet fallback.
  • Implementing the timed auto-revert mechanism like in static IP would require significant extra effort. That doesn’t mean we shouldn’t do it, but it may be worth to consider whether there are better alternatives in case of WiFi.

So my suggestion would be to go with the warning for now. If we’d see that this becomes an issue frequently, we could still consider a more sophisticated prevention mechanism, and add that later on.

@scott-tp
Copy link

@cghague @db39 FYI about the fallback scenario upon first feature release. (see the recent comment)

@jotaen4tinypilot
Copy link
Contributor

Just a quick work-in-progress update: I’ve created a draft PR stack (for the underlying commands, the backend logic, and the new dialog in the UI). The code/work of the PRs is not complete yet, but I was already able to successfully verify the entire flow of the WiFi feature on my device.

Screen.Recording.2024-06-25.at.20.59.51.mov

@jotaen4tinypilot
Copy link
Contributor

I’ve split out subtask (f) to its own ticket, so that we can prioritize it separately (or defer it for now).

jotaen4tinypilot added a commit that referenced this issue Jul 4, 2024
Related #131, subtask (g).

As the WiFi-AP scripts [overwrite the `wpa_supplicant.conf`
file](https://github.com/tiny-pilot/tinypilot/blob/6f37e68acbb729d82b76ed0dad0f67763926f29d/debian-pkg/opt/tinypilot-privileged/scripts/enable-wifi-ap#L160-L172),
we have to extend the note in the help text that running the scripts
will clear any WiFi settings.
<a data-ca-tag
href="https://codeapprove.com/pr/tiny-pilot/tinypilot/1817"><img
src="https://codeapprove.com/external/github-tag-allbg.png" alt="Review
on CodeApprove" /></a>

Co-authored-by: Jan Heuermann <[email protected]>
jotaen4tinypilot added a commit that referenced this issue Jul 5, 2024
Related #131, parts (a)
and (b).

This PR adds two scripts for enabling and disabling the WiFi network
interface on the device, so that you can also access TinyPilot through a
wireless network connection.

I already discussed the basic approach last week with Charles (see
comment and discussion below), because of his familiarity with
networking/WiFi. Since then, I did more testing in various scenarios,
and also already opened two subsequent draft PRs for the
[backend](#1805) and
[frontend](#1810). They are
WIP still, but they may give a rough impression of how the WiFi feature
will look in its entirety. Overall, it seems to be looking good, so I
thought it might make sense to already start the review process.

A few notes on the implementation:

- We write into the `wpa_supplicants.conf` file directly to configure
the WiFi connection, and we use the marker-section mechanism to manage
the TinyPilot-specific part of the configuration. Depending on whether
the WiFi network is password-protected or not, we either use the
`wpa_passphrase` command, or we generate the config section manually.
- I’m not sure it’s worth to validate the `--country` input value in the
`enable-wifi` script: I’d plan to do validation in the backend later on,
and the network service seems to behave graceful against invalid country
codes. For the `--psk` flag, we have to do a basic length validation,
because otherwise the `wpa_passphrase` command would fail.
- For testing on device, you can use the `ifconfig` command to check
whether the `wlan` network interface is up and active. (I.e., whether
`ifconfig` outputs a `wlan` block, and whether that has a `inet`/`inet6`
address assigned to it.)

---

### Original draft PR comment (2024-06-13)

This PR is a draft for now, because I wanted to evaluate the technical
approach of the underlying WiFi-related logic first, before investing
time into the implementation of the application logic (i.e., the Python
part and the UI).

I saw that you @cghague have been involved into [our WiFi FAQ
document](https://github.com/tiny-pilot/tinypilotkvm.com/blob/46696cc1698e1eb73051616423ab3c6b09a4f5e1/content/faq/enable-wifi/index.md),
so I was hoping that you are maybe familiar with the technical domain.
Could you look over the privileged scripts of this PR and give me some
initial, high-level feedback about whether the proposed approach seems
sensible to you? At this point, I’d mainly like to avoid going into a
wrong direction, or to miss any potential caveats or other issues I may
have forgotten to consider.

A few notes on the implementation:

- For the purposes of
#131, we need to fully
automate the logic for enabling and disabling WiFi, so that we can
invoke both procedures from the Python backend programmatically. The
`enable-wifi` script obviously would have to parse CLI arguments to
parametrize the SSID, PSK, and country code. The `disable-wifi` script
wouldn’t take any arguments.
- I’ve successfully tested the scripts on my device, and so far they
appear to work fine. By issuing `rfkill unblock wifi` and `wpa_cli -i
wlan0 reconfigure`, it seems to be possible to effectuate the changes
and activate WiFi without having to reboot the device. This would make
things easier for us in the UI, but it would also be more convenient and
snappier for the end-user.
- My thinking was that it doesn’t make sense to use the `raspi-config`
tool in the scripts, because that seems to be too limited. For example,
we don’t want to just keep adding new WiFi configs to the
`wpa_supplicant.conf` file, but we basically want to maintain *one*
“TinyPilot-owned” custom WiFi config, which we then also can delete or
modify in a targeted way. For this, it seemed more sensible to me to
write into the `wpa_supplicant.conf` file directly, using the
[marker-section
technique](https://github.com/tiny-pilot/tinypilot/blob/9bbc056c6e4dcec1804b99b3cdcbd0bcdf1ca0dc/debian-pkg/opt/tinypilot-privileged/scripts/lib/markers.sh)
that we already employ elsewhere. The downside is that this requires
more low-levelled logic on our side.

If you’d generally agree with the proposed approach and underlying
reasoning, I’d proceed to wrap up this PR and to build the surrounding
application logic.
<a data-ca-tag
href="https://codeapprove.com/pr/tiny-pilot/tinypilot/1804"><img
src="https://codeapprove.com/external/github-tag-allbg.png" alt="Review
on CodeApprove" /></a>

---------

Co-authored-by: Jan Heuermann <[email protected]>
jotaen4tinypilot added a commit that referenced this issue Jul 5, 2024
Related #131, part (b).
Stacked on #1804.

I realized that we need to add another privileged script for reading
files with marker sections, because we are unable to read those directly
via the Python process in case those files are owned by the `root` user.

Usage is demonstrated in [the subsequent backend
PR](#1812); it’s basically …

```bash
/opt/tinypilot-privileged/scripts/print-marker-sections /path/to/file.txt
```

… where the entire invocation has to be unblocked in the sudoers file.

<a data-ca-tag
href="https://codeapprove.com/pr/tiny-pilot/tinypilot/1811"><img
src="https://codeapprove.com/external/github-tag-allbg.png" alt="Review
on CodeApprove" /></a>

---------

Co-authored-by: Jan Heuermann <[email protected]>
jotaen4tinypilot added a commit that referenced this issue Jul 5, 2024
Related #131, part (c).
Stacked on #1811.

This PR adds the backend logic and endpoints that we need for the WiFi
dialog.

- There are endpoints for reading, writing, and deleting the WiFi
configuration. There is also one endpoint for checking the status of the
network connectivity, which allows us to display warnings or status
indicators in the frontend.
- As [mentioned in the code
comment](https://github.com/tiny-pilot/tinypilot/pull/1812/files#diff-43d8494a595e7d1f838bc01d5f2c6b18eebf61ca63bc3bbf2837dbcb27a8e109R62-R63),
we cannot read the `wpa_supplicant.conf` file directly due to file
ownership. Therefore, we use the [new `print-marker-sections` privileged
script](#1811) from the
previous PR.
- The scripts for enabling and disabling are executed in a “fire and
forget” manner, otherwise it may happen that the frontend requests hang
due to e.g. a change/interruption in the network (which would result in
an eternal loading spinner). As we only write a config file and trigger
service/daemon restarts, we wouldn’t get direct feedback about errors
anyway, but we’d have to poll for the resulting status, which can take
quite long, though.
- Note that we also can’t really verify the WiFi credentials, because
the desired WiFi might not be reachable at the time where the user wants
to enter the settings (e.g., because they want to enter the config ahead
of time).
- The validation of the incoming request data is relatively important,
because we will show the error messages in the frontend for input
validation. So we need to make sure that we detect all relevant
potential issues. The validation errors would be user-facing.

This PR can probably be tested best via the [subsequent frontend
PR](#1813) – that one isn’t
100% code-complete yet, but it’s pretty close in terms of functionality.
<a data-ca-tag
href="https://codeapprove.com/pr/tiny-pilot/tinypilot/1812"><img
src="https://codeapprove.com/external/github-tag-allbg.png" alt="Review
on CodeApprove" /></a>

---------

Co-authored-by: Jan Heuermann <[email protected]>
@jotaen4tinypilot
Copy link
Contributor

fyi, as we are closed to finishing the feature, I’ve already merged the bottom of the PR stack with the backend changes, to contain the scope of pending changes.

jotaen4tinypilot added a commit that referenced this issue Jul 16, 2024
Related #131, part (d).
Stacked on #1812.

This PR adds a new dialog “Wi-Fi” to the “System→Network” menu, which
makes the Wi-Fi feature available to end-users.

Summary of the discussion below:

- We made the wording so that it’s clear that we only store the WiFi
credentials, but we don’t verify whether they are actually accepted by
the WiFi router, or whether the WiFi is reachable at all. For further
clarification, we also added a success state to the dialog.
- In a subsequent PR, we’ll turn the “country code” free text field into
a dropdown, to make it easier for users to enter their correct and
applicable value.

<a data-ca-tag
href="https://codeapprove.com/pr/tiny-pilot/tinypilot/1813"><img
src="https://codeapprove.com/external/github-tag-allbg.png" alt="Review
on CodeApprove" /></a>

---------

Co-authored-by: Jan Heuermann <[email protected]>
jotaen4tinypilot added a commit that referenced this issue Jul 16, 2024
Related #131, part (h).
Stacked on #1813.

We didn’t have a `<select>` field in the style guide yet, and we also
were missing the general CSS for it. We’ll need this for [turning the
“Country Code” input field into a
select-field](#1820), as
[discussed in the previous
PR](#1813 (comment)).

Once we merged this into Pro, we can also refactor [the inlined CSS of
the `<select>` field in the static IP
dialog](https://github.com/tiny-pilot/tinypilot-pro/blob/f806639d5124e7edad8b9a44a727ecf49f73ed54/app/templates/custom-elements/static-ip-dialog.html#L38-L46).

<img width="840" alt="Screenshot 2024-07-05 at 08 34 39"
src="https://github.com/tiny-pilot/tinypilot/assets/83721279/c49b6a94-d114-495b-9dcb-ba32eb30029d">

<a data-ca-tag
href="https://codeapprove.com/pr/tiny-pilot/tinypilot/1819"><img
src="https://codeapprove.com/external/github-tag-allbg.png" alt="Review
on CodeApprove" /></a>

---------

Co-authored-by: Jan Heuermann <[email protected]>
jotaen4tinypilot added a commit that referenced this issue Jul 16, 2024
Related #131, part (h).
Stacked on #1819.

This PR turns the free text input field for the country code in the WiFi
dialog into a `<select>` dropdown, to make it easier for users to choose
their correct and applicable country code value.

<img width="811" alt="Screenshot 2024-07-05 at 08 21 33"
src="https://github.com/tiny-pilot/tinypilot/assets/83721279/34b6469b-3681-4545-af26-1e6a567c4756">

A few notes:

- I thought the simplest approach to retrieve the available country
codes was by copying them over from the
`/usr/share/zoneinfo/iso3166.tab` file. An alternative would be to parse
the file in the backend, and retrieve the list dynamically via an API
endpoint. That would then also allow us to validate the input value
against this list in the request parser. However, I think the
cost<>benefit ratio of such an implementation would be questionable,
especially considering that [the ISO definitions don’t seem to change
very often](http://www.statoids.com/w3166his.html).
- I adjusted the input field label from “Country Code” to “Country”. I
still suggest to display the country codes in the options (e.g., `United
States (US)`) for informational reasons, to satisfy both technical and
non-technical users.
- I removed the `size` attribute of the `<input>` field in favor of a
`width`, to make the sizing match the one of the `<select>` field. The
latter has slightly different box sizing behaviour, so it’s width
differs by `1em`.
<a data-ca-tag
href="https://codeapprove.com/pr/tiny-pilot/tinypilot/1820"><img
src="https://codeapprove.com/external/github-tag-allbg.png" alt="Review
on CodeApprove" /></a>

---------

Co-authored-by: Jan Heuermann <[email protected]>
@jotaen4tinypilot
Copy link
Contributor

This feature is completed now. Sub-task (f), the connection indicator, is tracked in its own ticket.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request large
Projects
None yet
Development

No branches or pull requests

4 participants