Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Mark should add a readme here

TODO

## Raspberry Pi OS configuration

This setup focuses on getting the network configured properly.
Assuming the Scoreboard hardware is pluged in correctly, the scoreboard app
built from this repo should "just work".

I'll need to redo these steps again on a clean image to verify, but this is close enough.

- I used the January 11th 2021 release of the Raspberry Pi OS Lite
- Modify `/boot/config.txt` to contain `enable_uart=1` if you want to use the serial port console.
- enable ssh and rsync
- `sudo systemctl enable ssh`
- `sudo systemctl start ssh`
- `sudo systemctl enable rsync`
- `sudo systemctl start rsync`
- make the scoreboard directory & copy over config files
- `mkdir /var/lib/scoreboard`
- `chown pi /var/lib/scorboard`
- copy over `secrets.txt`, `scoreboard_settings.json`, and `environment.conf`.
- `environment.conf` contains two lines `RUST_LOG="debug"` and `RUST_BACKTRACE=full`
- run the installer in this repo to copy over the scoreboard binary
- `ln -s /var/lib/scoreboard/scoreboard /usr/local/bin/scoreboard`
- Unblock built-in wlan `rfkill unblock wlan`
- Follow this guide: [https://www.raspberrypi.org/documentation/configuration/wireless/access-point-routed.md](https://www.raspberrypi.org/documentation/configuration/wireless/access-point-routed.md)
- Skip the Enable routing and IP masquerading section
- Substitute your own IP addresses for the Access point
- Use wlan1 as access point
- Use wlan0 as internet connection
- Modify the wpa systemctl service such that wpa_supplicant will actually get wlan0 to connect to the internet.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you not have to install drivers for the dongle?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope! Works without installing anything.

- Change the exec line to specifiy the drivers, the interface, and the wpa_supplicant.conf file to use
- `/etc/systemd/system/dbus-fi.w1.wpa_supplicant1.service`
- `ExecStart=/sbin/wpa_supplicant -u -D wext -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf -s -O /run/wpa_supplicant`
8 changes: 5 additions & 3 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,18 @@ pub fn color_from_string(s: &str) -> Result<rpi_led_matrix::LedColor, Box<dyn Er
}

pub fn is_connected() -> bool {
let response = ureq::get("http://clients3.google.com/generate_204").call();
info!("Checking connection, status is {:?}", response.status());
response.status() == 204
true
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stonks. It’s able to connect to AWS to get scores, I assume?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, works fine

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you try running this just before or after getting scores?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wack, still returning 400s on startup. Maybe the scoreboard service is running too early, before other networking things are fully up.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get 204s if I start the scoreboard app manually, so I don't think its the endpoint.

//let response = ureq::get("http://clients3.google.com/generate_204").call();
//info!("Checking connection, status is {:?}", response.status());
//response.status() == 204
}

pub fn get_ip_address() -> Option<Ipv4Addr> {
match Command::new("hostname").arg("-I").output() {
Ok(output) if output.status.success() => {
let string = std::str::from_utf8(&output.stdout).expect("Failed to parse hostname");
let mut ips = string.split(" ");
info!("hostname we got: {}", string);
match ips.next() {
Some(ip) => Some(ip.parse().unwrap()),
None => None,
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.unwrap();

if matches.is_present("wait") {
info!("Waiting 90 seconds");
sleep(Duration::from_secs(90));
info!("Waiting 5 seconds");
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figure a short delay might be useful? I tried this to see if the is_connected() function would work again. No change, is_connected() is still broke.

sleep(Duration::from_secs(5));
} else {
info!("Starting up now");
}
Expand Down
52 changes: 28 additions & 24 deletions src/shell_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::sync::mpsc;
use std::thread;
use std::time::Duration;
extern crate system_shutdown;
use std::thread::sleep;

use system_shutdown::reboot;
use users::{get_current_uid, get_user_by_uid};
Expand Down Expand Up @@ -35,18 +36,29 @@ impl CommandExecutor {
self.matrix_sender.send(response).unwrap();
}

fn set_interface(self: &Self, interface: &str, enable: bool) -> ExitStatus {
// DHCPCD configures the `wlan0` or `wlan1` interfaces
// See /etc/dhcpcd.conf
// However, DHCPCD requires a "carrier" to actually use the interface for anything
// WPA_SUPPLICANT is for the usual wifi where you are a client connecting to another access point to get internet access
// HOSTAPD is for when you are hosting the wifi access point
fn carrier_control(self: &Self, enable: bool, service: &str) -> ExitStatus {
self.execute(
"sudo",
&[
"ip",
"link",
"set",
interface,
if enable { "up" } else { "down" },
"systemctl",
if enable { "restart" } else { "stop" },
service,
],
)
.expect("Failed to run set interfaces")
.expect("Failed to run systemctl on service")
}

fn set_wifi(self: &Self, enable: bool) -> ExitStatus {
self.carrier_control(enable, "wpa_supplicant.service")
}

fn set_access_point(self: &Self, enable: bool) -> ExitStatus {
self.carrier_control(enable, "hostapd.service")
}

fn execute(self: &Self, command: &str, args: &[&str]) -> io::Result<ExitStatus> {
Expand Down Expand Up @@ -78,19 +90,11 @@ network={{
info!("Attempting to connect with supplicant:\n{}\n", supplicant);
fs::write("/etc/wpa_supplicant/wpa_supplicant.conf", supplicant)?;

let daemon_reload = self.execute("systemctl", &["daemon-reload"])?;
if !daemon_reload.success() {
error!("Failed to systemctl daemon reload");
return Ok(daemon_reload);
}

self.execute("sudo", &["dhclient", "-r", "wlan0"])?;

self.execute("sudo", &["ifdown", "wlan0"])?;

self.execute("sudo", &["ifup", "wlan0"])?;
let output = self.set_wifi(true);

let output = self.execute("sudo", &["dhclient", "-v", "wlan0"])?;
info!("Sleeping to allow wpa_supplicant to catch up after being restarted");
sleep(Duration::from_secs(10));
info!("Done waiting for wpa_supplicant to catch up");
Ok(output)
}

Expand Down Expand Up @@ -121,7 +125,7 @@ network={{
from_webserver,
} => {
// Enable wifi hotspot
let status = self.set_interface("wlan1", true);
let status = self.set_access_point(true);
if status.success() {
info!("Successfully enabled hotspot");
} else {
Expand All @@ -136,7 +140,7 @@ network={{
thread::sleep(Duration::from_secs(1));
info!("Resetting wifi");
// Just disable wlan0
let status = self.set_interface("wlan0", false);
let status = self.set_wifi(false);
if status.success() {
info!("Successfully disabled primary nic");
} else {
Expand All @@ -152,7 +156,7 @@ network={{
}
}
common::ShellCommand::SetHotspot(on) => {
let status = self.set_interface("wlan1", on);
let status = self.set_access_point(on);
if status.success() {
info!("Successfully set hotspot {}", on);
} else {
Expand Down Expand Up @@ -184,7 +188,7 @@ network={{

if success {
// If we've successfully connected, disable the hotspot
let hotspot_result = self.set_interface("wlan1", false);
let hotspot_result = self.set_access_point(false);
if hotspot_result.success() {
info!("Successfully disabled hotspot");
} else {
Expand All @@ -200,7 +204,7 @@ network={{
}

if !success {
self.set_interface("wlan1", true);
self.set_access_point(true);
}

self.send_matrix_response(common::MatrixCommand::FinishedWifiConnection(
Expand Down