Wi-Fi Hotspot UI
This commit is contained in:
+7
-6
@@ -19,14 +19,15 @@ add_subdirectory("react")
|
|||||||
|
|
||||||
add_subdirectory("src")
|
add_subdirectory("src")
|
||||||
|
|
||||||
add_subdirectory("NetworkManagerP2P")
|
# Replaced with hotspot.
|
||||||
|
#add_subdirectory("NetworkManagerP2P")
|
||||||
|
|
||||||
|
|
||||||
install (TARGETS pipedal_p2pd DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin
|
# install (TARGETS pipedal_p2pd DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin
|
||||||
)
|
# )
|
||||||
|
|
||||||
install (TARGETS pipedal_nm_p2pd DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin
|
# install (TARGETS pipedal_nm_p2pd DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin
|
||||||
)
|
# )
|
||||||
|
|
||||||
# select LV2 source directory for the current build architecture
|
# select LV2 source directory for the current build architecture
|
||||||
|
|
||||||
@@ -99,7 +100,7 @@ set(CPACK_DEBIAN_PACKAGE_SECTION sound)
|
|||||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE)
|
set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE)
|
||||||
#set(CPACK_DEBIAN_PACKAGE_DEPENDS "jackd2, hostapd, dhcpcd, dnsmasq" )
|
#set(CPACK_DEBIAN_PACKAGE_DEPENDS "jackd2, hostapd, dhcpcd, dnsmasq" )
|
||||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "lv2-dev, hostapd, dhcpcd,dnsmasq, authbind, gpg" )
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS "lv2-dev, hostapd, authbind, gpg" )
|
||||||
#set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64")
|
#set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64")
|
||||||
set(CPACK_PACKAGING_INSTALL_PREFIX /usr)
|
set(CPACK_PACKAGING_INSTALL_PREFIX /usr)
|
||||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||||
|
|||||||
@@ -116,12 +116,6 @@ public:
|
|||||||
|
|
||||||
static std::vector<std::unique_ptr<IDBusLogger>> loggers;
|
static std::vector<std::unique_ptr<IDBusLogger>> loggers;
|
||||||
|
|
||||||
void SetDBusLogger(std::unique_ptr<IDBusLogger> && logger)
|
|
||||||
{
|
|
||||||
loggers.clear();
|
|
||||||
loggers.push_back(std::move(logger));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SetDBusLogLevel(DBusLogLevel level)
|
void SetDBusLogLevel(DBusLogLevel level)
|
||||||
{
|
{
|
||||||
@@ -231,11 +225,17 @@ void LogTrace(const std::string&path,const char*method,const std::string&message
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetDBusLogger(std::unique_ptr<IDBusLogger> && logger)
|
||||||
|
{
|
||||||
|
loggers.clear();
|
||||||
|
loggers.push_back(std::move(logger));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SetDBusConsoleLogger()
|
void SetDBusConsoleLogger()
|
||||||
{
|
{
|
||||||
loggers.clear();
|
SetDBusLogger(std::make_unique<ConsoleDBusLogger>());
|
||||||
loggers.push_back(std::make_unique<ConsoleDBusLogger>());
|
|
||||||
}
|
}
|
||||||
void AddDBusConsoleLogger()
|
void AddDBusConsoleLogger()
|
||||||
{
|
{
|
||||||
@@ -243,13 +243,11 @@ void AddDBusConsoleLogger()
|
|||||||
}
|
}
|
||||||
void SetDBusSystemdLogger()
|
void SetDBusSystemdLogger()
|
||||||
{
|
{
|
||||||
loggers.clear();
|
SetDBusLogger(std::make_unique<SystemdDBusLogger>());
|
||||||
loggers.push_back(std::make_unique<SystemdDBusLogger>());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
void SetDBusFileLogger(const std::filesystem::path &path)
|
void SetDBusFileLogger(const std::filesystem::path &path)
|
||||||
{
|
{
|
||||||
loggers.clear();
|
SetDBusLogger(std::make_unique<FileDBusLogger>(path));
|
||||||
loggers.push_back(std::make_unique<FileDBusLogger>(path));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ void WifiConfigSettings::Load()
|
|||||||
reader.read(this);
|
reader.read(this);
|
||||||
}
|
}
|
||||||
this->countryCode_ = getWifiCountryCode();
|
this->countryCode_ = getWifiCountryCode();
|
||||||
|
this->enable_ = this->autoStartMode_ != (uint16_t)HotspotAutoStartMode::Never;
|
||||||
|
this->mdnsName_ = this->hotspotName_;
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
@@ -143,12 +145,27 @@ static void openWithPerms(
|
|||||||
|
|
||||||
void WifiConfigSettings::Save()
|
void WifiConfigSettings::Save()
|
||||||
{
|
{
|
||||||
|
WifiConfigSettings newSettings {*this};
|
||||||
|
|
||||||
|
// sync legacy settings, just in case i don't know what.
|
||||||
|
newSettings.mdnsName_ = newSettings.hotspotName_;
|
||||||
|
newSettings.enable_ = newSettings.IsEnabled();
|
||||||
|
// fill in the password, if required.
|
||||||
|
if (!newSettings.hasPassword_)
|
||||||
|
{
|
||||||
|
WifiConfigSettings oldSettings;
|
||||||
|
oldSettings.Load();
|
||||||
|
newSettings.hasPassword_ = oldSettings.hasPassword_;
|
||||||
|
newSettings.password_ = oldSettings.password_;
|
||||||
|
}
|
||||||
|
newSettings.hasSavedPassword_ = newSettings.hasPassword_;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ofstream_synced f;
|
ofstream_synced f;
|
||||||
openWithPerms(f,CONFIG_PATH);
|
openWithPerms(f,CONFIG_PATH);
|
||||||
json_writer writer(f);
|
json_writer writer(f);
|
||||||
writer.write(this);
|
writer.write(&newSettings);
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
@@ -398,6 +415,7 @@ namespace pipedal::priv
|
|||||||
|
|
||||||
|
|
||||||
JSON_MAP_BEGIN(WifiConfigSettings)
|
JSON_MAP_BEGIN(WifiConfigSettings)
|
||||||
|
// v0
|
||||||
JSON_MAP_REFERENCE(WifiConfigSettings, valid)
|
JSON_MAP_REFERENCE(WifiConfigSettings, valid)
|
||||||
JSON_MAP_REFERENCE(WifiConfigSettings, wifiWarningGiven)
|
JSON_MAP_REFERENCE(WifiConfigSettings, wifiWarningGiven)
|
||||||
JSON_MAP_REFERENCE(WifiConfigSettings, rebootRequired)
|
JSON_MAP_REFERENCE(WifiConfigSettings, rebootRequired)
|
||||||
@@ -408,8 +426,13 @@ JSON_MAP_REFERENCE(WifiConfigSettings, hasPassword)
|
|||||||
JSON_MAP_REFERENCE(WifiConfigSettings, password)
|
JSON_MAP_REFERENCE(WifiConfigSettings, password)
|
||||||
JSON_MAP_REFERENCE(WifiConfigSettings, countryCode)
|
JSON_MAP_REFERENCE(WifiConfigSettings, countryCode)
|
||||||
JSON_MAP_REFERENCE(WifiConfigSettings, channel)
|
JSON_MAP_REFERENCE(WifiConfigSettings, channel)
|
||||||
JSON_MAP_REFERENCE(WifiConfigSettings, alwaysOn)
|
|
||||||
JSON_MAP_REFERENCE(WifiConfigSettings, homeNetworks)
|
// v1: Auto-hotspot
|
||||||
|
|
||||||
|
JSON_MAP_REFERENCE(WifiConfigSettings, autoStartMode)
|
||||||
|
JSON_MAP_REFERENCE(WifiConfigSettings, homeNetwork)
|
||||||
|
JSON_MAP_REFERENCE(WifiConfigSettings, hasSavedPassword)
|
||||||
|
|
||||||
JSON_MAP_END()
|
JSON_MAP_END()
|
||||||
|
|
||||||
int32_t pipedal::ChannelToChannelNumber(const std::string &channel)
|
int32_t pipedal::ChannelToChannelNumber(const std::string &channel)
|
||||||
@@ -646,22 +669,33 @@ static std::vector<WifiConfigSettings::ssid_t> stringToSsidArray(const std::stri
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
void WifiConfigSettings::ParseArguments(const std::vector<std::string> &argv)
|
void WifiConfigSettings::ParseArguments(
|
||||||
|
const std::vector<std::string> &argv,
|
||||||
|
HotspotAutoStartMode startMode,
|
||||||
|
const std::string homeNetworkSsid
|
||||||
|
|
||||||
|
)
|
||||||
{
|
{
|
||||||
this->valid_ = false;
|
this->valid_ = false;
|
||||||
if (argv.size() < 4 || argv.size() > 6)
|
if (argv.size() != 4)
|
||||||
{
|
{
|
||||||
throw invalid_argument("Invalid number of arguments.");
|
throw invalid_argument("Invalid number of arguments.");
|
||||||
}
|
}
|
||||||
this->enable_ = true;
|
WifiConfigSettings oldSettings;
|
||||||
|
oldSettings.Load();
|
||||||
|
this->valid_ = false;
|
||||||
|
|
||||||
|
this->autoStartMode_ = (int16_t)startMode;
|
||||||
|
this->enable_ = startMode != HotspotAutoStartMode::Never;
|
||||||
|
this->homeNetwork_ = homeNetworkSsid;
|
||||||
|
|
||||||
this->countryCode_ = argv[0];
|
this->countryCode_ = argv[0];
|
||||||
this->hotspotName_ = argv[1];
|
this->hotspotName_ = argv[1];
|
||||||
this->mdnsName_ = this->hotspotName_;
|
this->mdnsName_ = this->hotspotName_;
|
||||||
this->password_ = argv[2];
|
this->password_ = argv[2];
|
||||||
this->channel_ = argv[3];
|
this->channel_ = argv[3];
|
||||||
this->hasPassword_ = this->password_.length() != 0;
|
this->hasPassword_ = this->password_.length() != 0;
|
||||||
this->homeNetworks_ = std::vector<ssid_t>();
|
this->hasSavedPassword_ = oldSettings.hasSavedPassword_;
|
||||||
this->alwaysOn_ = false;
|
|
||||||
|
|
||||||
|
|
||||||
if (!ValidateCountryCode(this->countryCode_))
|
if (!ValidateCountryCode(this->countryCode_))
|
||||||
@@ -672,26 +706,20 @@ void WifiConfigSettings::ParseArguments(const std::vector<std::string> &argv)
|
|||||||
throw invalid_argument("Hotspot name is too long.");
|
throw invalid_argument("Hotspot name is too long.");
|
||||||
if (this->hotspotName_.length() < 1)
|
if (this->hotspotName_.length() < 1)
|
||||||
throw invalid_argument("Hotspot name is too short.");
|
throw invalid_argument("Hotspot name is too short.");
|
||||||
|
|
||||||
if (this->password_.size() != 0 && this->password_.size() < 8)
|
if (this->password_.size() != 0 && this->password_.size() < 8)
|
||||||
throw invalid_argument("Passphrase must be at least 8 characters long.");
|
throw invalid_argument("Passphrase must be at least 8 characters long.");
|
||||||
|
|
||||||
|
if (this->password_.size() == 0 && !this->hasSavedPassword_)
|
||||||
|
{
|
||||||
|
throw invalid_argument("Passphrase required.");
|
||||||
|
}
|
||||||
|
|
||||||
if (!ValidateChannel(this->countryCode_, this->channel_))
|
if (!ValidateChannel(this->countryCode_, this->channel_))
|
||||||
{
|
{
|
||||||
throw invalid_argument("Channel is not valid.");
|
throw invalid_argument("Channel is not valid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argv.size() >= 5)
|
|
||||||
{
|
|
||||||
if (!TryStringToBool(argv[4],&this->alwaysOn_))
|
|
||||||
{
|
|
||||||
throw std::runtime_error(SS("Invalid boolean value: " << argv[4]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (argv.size() >= 6)
|
|
||||||
{
|
|
||||||
this->homeNetworks_ = stringToSsidArray(argv[5]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate that the channel number is supported for the given country code.
|
// validate that the channel number is supported for the given country code.
|
||||||
|
|
||||||
this->valid_ = true;
|
this->valid_ = true;
|
||||||
@@ -701,15 +729,17 @@ bool WifiConfigSettings::ConfigurationChanged(const WifiConfigSettings&other) co
|
|||||||
{
|
{
|
||||||
return !(
|
return !(
|
||||||
this->valid_ == other.valid_ &&
|
this->valid_ == other.valid_ &&
|
||||||
this->rebootRequired_ == other.rebootRequired_ &&
|
//this->rebootRequired_ == other.rebootRequired_ &&
|
||||||
this->enable_ == other.enable_ &&
|
//this->enable_ == other.enable_ &&
|
||||||
this->countryCode_ == other.countryCode_ &&
|
this->countryCode_ == other.countryCode_ &&
|
||||||
this->mdnsName_ == other.mdnsName_ &&
|
this->hotspotName_ == other.hotspotName_ &&
|
||||||
this->hasPassword_ == other.hasPassword_ &&
|
this->hasPassword_ == other.hasPassword_ &&
|
||||||
this->password_ == other.password_ &&
|
this->password_ == other.password_ &&
|
||||||
this->channel_ == other.channel_ &&
|
this->channel_ == other.channel_ &&
|
||||||
this->homeNetworks_ == other.homeNetworks_ &&
|
|
||||||
this->alwaysOn_ == other.alwaysOn_
|
this->homeNetwork_ == other.homeNetwork_ &&
|
||||||
|
this->autoStartMode_ == other.autoStartMode_ &&
|
||||||
|
this->hasSavedPassword_ == other.hasSavedPassword_
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -718,33 +748,75 @@ bool WifiConfigSettings::operator==(const WifiConfigSettings&other) const
|
|||||||
return !ConfigurationChanged(other) && this->wifiWarningGiven_ == other.wifiWarningGiven_;
|
return !ConfigurationChanged(other) && this->wifiWarningGiven_ == other.wifiWarningGiven_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool CanSeeHomeNetwork(const std::string&home, const std::vector<std::string>&availableNetworks)
|
||||||
bool WifiConfigSettings::WantsHotspot(bool ethernetConnected, const std::vector<ssid_t> &availableNetworks)
|
|
||||||
{
|
{
|
||||||
if ((!this->valid_) || (!this->enable_))
|
for (const auto &availableNetwork: availableNetworks)
|
||||||
return false;
|
|
||||||
if (ethernetConnected)
|
|
||||||
{
|
{
|
||||||
return false;
|
if (availableNetwork == home)
|
||||||
}
|
|
||||||
if (!homeNetworks_.empty())
|
|
||||||
{
|
|
||||||
for (auto &network: availableNetworks)
|
|
||||||
{
|
{
|
||||||
for (auto&homeNetwork: homeNetworks_)
|
return true;
|
||||||
{
|
|
||||||
if (network == homeNetwork)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (alwaysOn_)
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WifiConfigSettings::WantsHotspot(
|
||||||
|
bool ethernetConnected,
|
||||||
|
const std::vector<std::string> &availableRememberedNetworks,
|
||||||
|
const std::vector<std::string> &availableNetworks)
|
||||||
|
{
|
||||||
|
if ((!this->valid_))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
HotspotAutoStartMode autoStartMode = (HotspotAutoStartMode)this->autoStartMode_;
|
||||||
|
|
||||||
|
switch (autoStartMode)
|
||||||
{
|
{
|
||||||
return true;
|
case HotspotAutoStartMode::Never:
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case HotspotAutoStartMode::NoEthernetConnection:
|
||||||
|
return !ethernetConnected;
|
||||||
|
case HotspotAutoStartMode::NotAtHome:
|
||||||
|
return !CanSeeHomeNetwork(this->homeNetwork_, availableNetworks);
|
||||||
|
case HotspotAutoStartMode::NoRememberedWifiConections:
|
||||||
|
return availableRememberedNetworks.size() == 0;
|
||||||
|
case HotspotAutoStartMode::Always:
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return availableNetworks.size() == 0;
|
}
|
||||||
|
|
||||||
|
std::string pipedal::ssidToString(const std::vector<uint8_t> &ssid)
|
||||||
|
{
|
||||||
|
std::stringstream s;
|
||||||
|
for (auto v: ssid)
|
||||||
|
{
|
||||||
|
if (v == 0) break; // breaks for some arguably legal ssids, but I can live with that.
|
||||||
|
s << (char)v;
|
||||||
|
}
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> pipedal::ssidToStringVector(const std::vector<std::vector<uint8_t>> &ssids)
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
result.reserve(ssids.size());
|
||||||
|
for (const std::vector<uint8_t> &ssid: ssids)
|
||||||
|
{
|
||||||
|
result.push_back(ssidToString(ssid));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
bool WifiConfigSettings::WantsHotspot(
|
||||||
|
bool ethernetConnected,
|
||||||
|
const std::vector<std::vector<uint8_t>> &availableRememberedNetworks, // remembered networks that are currently visible
|
||||||
|
const std::vector<std::vector<uint8_t>> &availableNetworks // all visible networks.
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> sAvailableRememberedNetworks = ssidToStringVector(availableRememberedNetworks);
|
||||||
|
std::vector<std::string> sAvailableNetworks = ssidToStringVector(availableNetworks);
|
||||||
|
return WantsHotspot(ethernetConnected,sAvailableRememberedNetworks,sAvailableNetworks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
#ifndef NEW_WIFI_CONFIG
|
#ifndef NEW_WIFI_CONFIG
|
||||||
@@ -39,12 +41,23 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace pipedal {
|
namespace pipedal {
|
||||||
|
std::string ssidToString(const std::vector<uint8_t> &ssid);
|
||||||
|
std::vector<std::string> ssidToStringVector(const std::vector<std::vector<uint8_t>> &ssids);
|
||||||
|
|
||||||
|
|
||||||
uint32_t ChannelToWifiFrequency(const std::string &channel);
|
uint32_t ChannelToWifiFrequency(const std::string &channel);
|
||||||
uint32_t ChannelToWifiFrequency(uint32_t channel);
|
uint32_t ChannelToWifiFrequency(uint32_t channel);
|
||||||
int32_t ChannelToChannelNumber(const std::string&channel);
|
int32_t ChannelToChannelNumber(const std::string&channel);
|
||||||
|
|
||||||
|
|
||||||
|
enum class HotspotAutoStartMode {
|
||||||
|
// saved to file. Do not remove or renumber enums.
|
||||||
|
Never = 0,
|
||||||
|
NoEthernetConnection = 1,
|
||||||
|
NotAtHome = 2,
|
||||||
|
NoRememberedWifiConections = 3,
|
||||||
|
Always = 4
|
||||||
|
};
|
||||||
class WifiConfigSettings {
|
class WifiConfigSettings {
|
||||||
public:
|
public:
|
||||||
using ssid_t = std::vector<uint8_t>;
|
using ssid_t = std::vector<uint8_t>;
|
||||||
@@ -53,26 +66,45 @@ namespace pipedal {
|
|||||||
void Load();
|
void Load();
|
||||||
void Save();
|
void Save();
|
||||||
|
|
||||||
bool valid_ = false;
|
int16_t autoStartMode_ = 0; // see HotspotAutoStartMode
|
||||||
bool wifiWarningGiven_ = false;
|
bool hasSavedPassword_ = false;
|
||||||
bool rebootRequired_ = false;
|
std::string homeNetwork_;
|
||||||
bool enable_ = false;
|
|
||||||
std::string countryCode_ = "US"; // iso 3661
|
std::string countryCode_ = "US"; // iso 3661
|
||||||
std::string hotspotName_ = "pipedal";
|
std::string hotspotName_ = "pipedal";
|
||||||
std::string mdnsName_ = "pipedal";
|
|
||||||
std::vector<ssid_t> homeNetworks_;
|
|
||||||
bool hasPassword_ = false;
|
bool hasPassword_ = false;
|
||||||
std::string password_;
|
std::string password_;
|
||||||
std::string channel_ = "";
|
std::string channel_ = "";
|
||||||
bool alwaysOn_ = false;
|
|
||||||
|
|
||||||
void ParseArguments(const std::vector<std::string> &arguments);
|
bool wifiWarningGiven_ = false; // Do not use. Present only for backward compatibility.
|
||||||
|
bool valid_ = false; // Do not use. Present only for backward compatibility.
|
||||||
|
private:
|
||||||
|
bool rebootRequired_ = false; // Do not use. Present only for backward compatibility.
|
||||||
|
std::string mdnsName_ = "pipedal";
|
||||||
|
bool enable_ = false; // Do not use. Present only for backward compatibility.
|
||||||
|
public:
|
||||||
|
bool IsEnabled() const { return autoStartMode_ != 0; }
|
||||||
|
// Initialize from commandline arguments (see ConfigMain.cpp)
|
||||||
|
void ParseArguments(
|
||||||
|
const std::vector<std::string> &argv,
|
||||||
|
HotspotAutoStartMode startMode,
|
||||||
|
const std::string homeNetworkSsid
|
||||||
|
);
|
||||||
static bool ValidateCountryCode(const std::string&value);
|
static bool ValidateCountryCode(const std::string&value);
|
||||||
static bool ValidateChannel(const std::string&countryCode,const std::string&value);
|
static bool ValidateChannel(const std::string&countryCode,const std::string&value);
|
||||||
|
|
||||||
bool operator==(const WifiConfigSettings&other) const;
|
bool operator==(const WifiConfigSettings&other) const;
|
||||||
bool ConfigurationChanged(const WifiConfigSettings&other) const;
|
bool ConfigurationChanged(const WifiConfigSettings&other) const;
|
||||||
bool WantsHotspot(bool ethernetConnected,const std::vector<ssid_t> &availableNetworks);
|
bool WantsHotspot(
|
||||||
|
bool ethernetConnected,
|
||||||
|
const std::vector<std::string> &availableRememberedNetworks, // remembered networks that are currently visible
|
||||||
|
const std::vector<std::string> &availableNetworks // all visible networks.
|
||||||
|
);
|
||||||
|
bool WantsHotspot(
|
||||||
|
bool ethernetConnected,
|
||||||
|
const std::vector<std::vector<uint8_t>> &availableRememberedNetworks, // remembered networks that are currently visible
|
||||||
|
const std::vector<std::vector<uint8_t>> &availableNetworks // all visible networks.
|
||||||
|
);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DECLARE_JSON_MAP(WifiConfigSettings);
|
DECLARE_JSON_MAP(WifiConfigSettings);
|
||||||
|
|||||||
@@ -335,6 +335,14 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
os << value;
|
os << value;
|
||||||
}
|
}
|
||||||
|
void write(short value)
|
||||||
|
{
|
||||||
|
os << value;
|
||||||
|
}
|
||||||
|
void write(unsigned short value)
|
||||||
|
{
|
||||||
|
os << value;
|
||||||
|
}
|
||||||
void write(long long value)
|
void write(long long value)
|
||||||
{
|
{
|
||||||
os << value;
|
os << value;
|
||||||
@@ -897,6 +905,22 @@ namespace pipedal
|
|||||||
if (is_.fail())
|
if (is_.fail())
|
||||||
throw JsonException("Invalid format.");
|
throw JsonException("Invalid format.");
|
||||||
}
|
}
|
||||||
|
void read(short * value)
|
||||||
|
{
|
||||||
|
skip_whitespace();
|
||||||
|
is_ >> *value;
|
||||||
|
if (is_.fail())
|
||||||
|
throw JsonException("Invalid format.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void read(unsigned short * value)
|
||||||
|
{
|
||||||
|
skip_whitespace();
|
||||||
|
is_ >> *value;
|
||||||
|
if (is_.fail())
|
||||||
|
throw JsonException("Invalid format.");
|
||||||
|
}
|
||||||
|
|
||||||
void read(int *value)
|
void read(int *value)
|
||||||
{
|
{
|
||||||
skip_whitespace();
|
skip_whitespace();
|
||||||
|
|||||||
+39
-14
@@ -366,7 +366,8 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
clientId: number = -1;
|
clientId: number = -1;
|
||||||
|
|
||||||
serverVersion?: PiPedalVersion;
|
serverVersion?: PiPedalVersion;
|
||||||
countryCodes: Object = {};
|
countryCodes: {[Name: string]: string} = {};
|
||||||
|
|
||||||
socketServerUrl: string = "";
|
socketServerUrl: string = "";
|
||||||
varServerUrl: string = "";
|
varServerUrl: string = "";
|
||||||
lv2Path: string = "";
|
lv2Path: string = "";
|
||||||
@@ -956,7 +957,7 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
return response.json();
|
return response.json();
|
||||||
})
|
})
|
||||||
.then((countryCodes) => {
|
.then((countryCodes) => {
|
||||||
this.countryCodes = countryCodes as Object;
|
this.countryCodes = countryCodes as {[Name: string]: string};
|
||||||
|
|
||||||
return this.getWebSocket().request<number>("hello");
|
return this.getWebSocket().request<number>("hello");
|
||||||
})
|
})
|
||||||
@@ -2556,27 +2557,33 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
let oldSettings = this.wifiConfigSettings.get();
|
let oldSettings = this.wifiConfigSettings.get();
|
||||||
wifiConfigSettings = wifiConfigSettings.clone();
|
wifiConfigSettings = wifiConfigSettings.clone();
|
||||||
|
|
||||||
if ((!oldSettings.enable) && (!wifiConfigSettings.enable)) {
|
if ((!oldSettings.isEnabled()) && (!wifiConfigSettings.isEnabled())) {
|
||||||
// no effective change.
|
// no effective change.
|
||||||
resolve();
|
resolve();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!wifiConfigSettings.enable) {
|
if (!wifiConfigSettings.isEnabled()) {
|
||||||
wifiConfigSettings.hasPassword = false;
|
wifiConfigSettings.hasPassword = false;
|
||||||
wifiConfigSettings.hotspotName = oldSettings.hotspotName;
|
wifiConfigSettings.password = "";
|
||||||
} else {
|
} else {
|
||||||
if (wifiConfigSettings.countryCode === oldSettings.countryCode
|
if (wifiConfigSettings.hasPassword)
|
||||||
&& wifiConfigSettings.channel === oldSettings.channel
|
{
|
||||||
&& wifiConfigSettings.hotspotName === oldSettings.hotspotName) {
|
wifiConfigSettings.hasSavedPassword = true;
|
||||||
if (!wifiConfigSettings.hasPassword) {
|
|
||||||
// no effective change.
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// save a version for the server (potentially carrying a password)
|
// save a version for the server (potentially carrying a password)
|
||||||
let serverConfigSettings = wifiConfigSettings.clone();
|
let serverConfigSettings: WifiConfigSettings;
|
||||||
|
if (wifiConfigSettings.isEnabled()) {
|
||||||
|
serverConfigSettings = wifiConfigSettings.clone();
|
||||||
|
} else {
|
||||||
|
// avoid leaking edits to the server
|
||||||
|
serverConfigSettings = oldSettings.clone();
|
||||||
|
serverConfigSettings.autoStartMode = wifiConfigSettings.autoStartMode;
|
||||||
|
wifiConfigSettings = oldSettings.clone();
|
||||||
|
wifiConfigSettings.autoStartMode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wifiConfigSettings.hasPassword = false;
|
||||||
wifiConfigSettings.password = "";
|
wifiConfigSettings.password = "";
|
||||||
this.wifiConfigSettings.set(wifiConfigSettings);
|
this.wifiConfigSettings.set(wifiConfigSettings);
|
||||||
|
|
||||||
@@ -2661,6 +2668,24 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getKnownWifiNetworks() : Promise<string[]> {
|
||||||
|
let result = new Promise<string[]>((resolve, reject) => {
|
||||||
|
if (!this.webSocket) {
|
||||||
|
reject("Connection closed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.webSocket.request<string[]>("getKnownWifiNetworks")
|
||||||
|
.then((data) => {
|
||||||
|
resolve(data);
|
||||||
|
})
|
||||||
|
.catch((err) => reject(err));
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getWifiChannels(countryIso3661: string): Promise<WifiChannel[]> {
|
getWifiChannels(countryIso3661: string): Promise<WifiChannel[]> {
|
||||||
let result = new Promise<WifiChannel[]>((resolve, reject) => {
|
let result = new Promise<WifiChannel[]>((resolve, reject) => {
|
||||||
if (!this.webSocket) {
|
if (!this.webSocket) {
|
||||||
|
|||||||
@@ -681,6 +681,20 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
<div >
|
<div >
|
||||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">CONNECTION</Typography>
|
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">CONNECTION</Typography>
|
||||||
|
|
||||||
|
<ButtonBase
|
||||||
|
className={classes.setting} disabled={!this.state.wifiConfigSettings.valid}
|
||||||
|
onClick={() => this.handleShowWifiConfigDialog()} >
|
||||||
|
<SelectHoverBackground selected={false} showHover={true} />
|
||||||
|
<div style={{ width: "100%" }}>
|
||||||
|
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||||
|
Wi-Fi auto hotspot</Typography>
|
||||||
|
<Typography display="block" variant="caption" noWrap color="textSecondary">
|
||||||
|
{this.state.wifiConfigSettings.getSummaryText()}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ButtonBase>
|
||||||
|
|
||||||
{
|
{
|
||||||
this.state.isAndroidHosted &&
|
this.state.isAndroidHosted &&
|
||||||
(
|
(
|
||||||
@@ -699,33 +713,6 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
<ButtonBase
|
|
||||||
className={classes.setting} disabled={!this.state.wifiConfigSettings.valid}
|
|
||||||
onClick={() => this.handleShowWifiConfigDialog()} >
|
|
||||||
<SelectHoverBackground selected={false} showHover={true} />
|
|
||||||
<div style={{ width: "100%" }}>
|
|
||||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
|
||||||
Wi-Fi auto hotspot</Typography>
|
|
||||||
<Typography display="block" variant="caption" noWrap color="textSecondary">
|
|
||||||
{this.state.wifiConfigSettings.getSummaryText()}
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</ButtonBase>
|
|
||||||
|
|
||||||
<ButtonBase className={classes.setting} disabled={!this.state.wifiConfigSettings.valid}
|
|
||||||
style={{ display: "none" }}
|
|
||||||
onClick={() => this.handleShowWifiConfigDialog()} >
|
|
||||||
<SelectHoverBackground selected={false} showHover={true} />
|
|
||||||
<div style={{ width: "100%" }}>
|
|
||||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
|
||||||
Configure Wi-Fi hotspot</Typography>
|
|
||||||
<Typography display="block" variant="caption" noWrap color="textSecondary">
|
|
||||||
{this.state.wifiConfigSettings.getSummaryText()}
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</ButtonBase>
|
|
||||||
</div>
|
</div>
|
||||||
{(!this.props.onboarding) ? (
|
{(!this.props.onboarding) ? (
|
||||||
<div >
|
<div >
|
||||||
|
|||||||
+555
-269
@@ -18,17 +18,19 @@
|
|||||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import IconButton from '@mui/material/IconButton';
|
||||||
|
import VisibilityIcon from '@mui/icons-material/Visibility';
|
||||||
|
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
|
||||||
|
import FormHelperText from '@mui/material/FormHelperText';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
|
import Autocomplete from '@mui/material/Autocomplete';
|
||||||
import TextField from '@mui/material/TextField';
|
import TextField from '@mui/material/TextField';
|
||||||
import DialogEx from './DialogEx';
|
import DialogEx from './DialogEx';
|
||||||
import DialogActions from '@mui/material/DialogActions';
|
import DialogActions from '@mui/material/DialogActions';
|
||||||
import DialogContent from '@mui/material/DialogContent';
|
import DialogContent from '@mui/material/DialogContent';
|
||||||
import DialogTitle from '@mui/material/DialogTitle';
|
import DialogTitle from '@mui/material/DialogTitle';
|
||||||
import Switch from '@mui/material/Switch';
|
|
||||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
|
||||||
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
||||||
import WifiConfigSettings from './WifiConfigSettings';
|
import WifiConfigSettings from './WifiConfigSettings';
|
||||||
import NoChangePassword from './NoChangePassword';
|
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { Theme } from '@mui/material/styles';
|
import { Theme } from '@mui/material/styles';
|
||||||
import { WithStyles } from '@mui/styles';
|
import { WithStyles } from '@mui/styles';
|
||||||
@@ -39,7 +41,8 @@ import FormControl from '@mui/material/FormControl';
|
|||||||
import InputLabel from '@mui/material/InputLabel';
|
import InputLabel from '@mui/material/InputLabel';
|
||||||
import MenuItem from '@mui/material/MenuItem';
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
import WifiChannel from './WifiChannel';
|
import WifiChannel from './WifiChannel';
|
||||||
import {PiPedalModel, PiPedalModelFactory} from './PiPedalModel';
|
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
|
||||||
|
import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
|
||||||
|
|
||||||
const styles = (theme: Theme) => createStyles({
|
const styles = (theme: Theme) => createStyles({
|
||||||
pgraph: {
|
pgraph: {
|
||||||
@@ -57,319 +60,602 @@ export interface WifiConfigProps extends WithStyles<typeof styles> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface WifiConfigState {
|
export interface WifiConfigState {
|
||||||
|
autoStartMode: number;
|
||||||
|
showPassword: boolean;
|
||||||
fullScreen: boolean;
|
fullScreen: boolean;
|
||||||
|
compactWidth: boolean;
|
||||||
|
compactHeight: boolean;
|
||||||
showWifiWarningDialog: boolean;
|
showWifiWarningDialog: boolean;
|
||||||
|
showHelpDialog: boolean;
|
||||||
wifiWarningGiven: boolean;
|
wifiWarningGiven: boolean;
|
||||||
enabled: boolean;
|
|
||||||
name: string;
|
name: string;
|
||||||
newPassword: string;
|
newPassword: string;
|
||||||
|
hasPassword: boolean;
|
||||||
nameError: boolean;
|
nameError: boolean;
|
||||||
nameErrorMessage: string;
|
nameErrorMessage: string;
|
||||||
passwordError: boolean;
|
passwordError: boolean;
|
||||||
passwordErrorMessage: string;
|
passwordErrorMessage: string;
|
||||||
|
homeNetworkSsid: string;
|
||||||
|
homeNetworkError: boolean;
|
||||||
|
homeNetworkErrorMessage: string;
|
||||||
countryCode: string;
|
countryCode: string;
|
||||||
channel: string;
|
channel: string;
|
||||||
|
knownWifiNetworks: string[];
|
||||||
wifiChannels: WifiChannel[];
|
wifiChannels: WifiChannel[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let gCountryCodeOptions: { id: string, label: string }[] | undefined = undefined;
|
||||||
|
|
||||||
|
|
||||||
const WifiConfigDialog = withStyles(styles, { withTheme: true })(
|
const WifiConfigDialog = withStyles(styles, { withTheme: true })(
|
||||||
class extends ResizeResponsiveComponent<WifiConfigProps, WifiConfigState> {
|
class extends ResizeResponsiveComponent<WifiConfigProps, WifiConfigState> {
|
||||||
|
|
||||||
refName: React.RefObject<HTMLInputElement>;
|
refName: React.RefObject<HTMLInputElement>;
|
||||||
refPassword: React.RefObject<HTMLInputElement>;
|
refPassword: React.RefObject<HTMLInputElement>;
|
||||||
model: PiPedalModel;
|
model: PiPedalModel;
|
||||||
|
|
||||||
constructor(props: WifiConfigProps) {
|
constructor(props: WifiConfigProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.model = PiPedalModelFactory.getInstance();
|
this.model = PiPedalModelFactory.getInstance();
|
||||||
this.state = {
|
this.state = {
|
||||||
fullScreen: false,
|
showPassword: false,
|
||||||
enabled: this.props.wifiConfigSettings.enable,
|
fullScreen: false,
|
||||||
name: this.props.wifiConfigSettings.hotspotName,
|
compactWidth: false,
|
||||||
newPassword: "",
|
compactHeight: false,
|
||||||
nameError: false,
|
autoStartMode: this.props.wifiConfigSettings.autoStartMode,
|
||||||
nameErrorMessage: NBSP,
|
|
||||||
passwordError: false,
|
|
||||||
showWifiWarningDialog: false,
|
|
||||||
wifiWarningGiven: this.props.wifiConfigSettings.wifiWarningGiven,
|
|
||||||
passwordErrorMessage: NBSP,
|
|
||||||
countryCode: this.props.wifiConfigSettings.countryCode,
|
|
||||||
channel: this.props.wifiConfigSettings.channel,
|
|
||||||
wifiChannels: []
|
|
||||||
};
|
|
||||||
this.model.getWifiChannels(this.props.wifiConfigSettings.countryCode)
|
|
||||||
.then((wifiChannels_) => {
|
|
||||||
this.setState({wifiChannels: wifiChannels_});
|
|
||||||
}).catch((err)=> {});
|
|
||||||
|
|
||||||
this.refName = React.createRef<HTMLInputElement>();
|
|
||||||
this.refPassword = React.createRef<HTMLInputElement>();
|
|
||||||
}
|
|
||||||
mounted: boolean = false;
|
|
||||||
|
|
||||||
handleEnableChanged(e: any) {
|
|
||||||
this.setState({ enabled: e.target.checked });
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
onWindowSizeChanged(width: number, height: number): void {
|
|
||||||
this.setState({ fullScreen: height < 200 })
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
super.componentDidMount();
|
|
||||||
this.mounted = true;
|
|
||||||
}
|
|
||||||
componentWillUnmount() {
|
|
||||||
super.componentWillUnmount();
|
|
||||||
this.mounted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps: WifiConfigProps) {
|
|
||||||
|
|
||||||
if (this.props.open && !prevProps.open)
|
|
||||||
{
|
|
||||||
this.setState({
|
|
||||||
enabled: this.props.wifiConfigSettings.enable,
|
|
||||||
name: this.props.wifiConfigSettings.hotspotName,
|
name: this.props.wifiConfigSettings.hotspotName,
|
||||||
newPassword: "",
|
newPassword: "",
|
||||||
|
hasPassword: false,
|
||||||
|
nameError: false,
|
||||||
|
nameErrorMessage: NBSP,
|
||||||
|
passwordError: false,
|
||||||
|
homeNetworkSsid: this.props.wifiConfigSettings.homeNetwork,
|
||||||
|
homeNetworkError: false,
|
||||||
|
homeNetworkErrorMessage: NBSP,
|
||||||
|
showWifiWarningDialog: false,
|
||||||
|
showHelpDialog: false,
|
||||||
wifiWarningGiven: this.props.wifiConfigSettings.wifiWarningGiven,
|
wifiWarningGiven: this.props.wifiConfigSettings.wifiWarningGiven,
|
||||||
|
passwordErrorMessage: NBSP,
|
||||||
countryCode: this.props.wifiConfigSettings.countryCode,
|
countryCode: this.props.wifiConfigSettings.countryCode,
|
||||||
channel: this.props.wifiConfigSettings.channel
|
channel: this.props.wifiConfigSettings.channel,
|
||||||
});
|
knownWifiNetworks: [],
|
||||||
|
wifiChannels: []
|
||||||
|
};
|
||||||
|
this.requestWifiChannels(this.props.wifiConfigSettings.countryCode);
|
||||||
|
this.requestKnownWifiNetworks();
|
||||||
|
|
||||||
if (this.props.wifiConfigSettings.countryCode !== this.state.countryCode)
|
this.refName = React.createRef<HTMLInputElement>();
|
||||||
{
|
this.refPassword = React.createRef<HTMLInputElement>();
|
||||||
this.model.getWifiChannels(this.props.wifiConfigSettings.countryCode)
|
}
|
||||||
.then((wifiChannels) => {
|
mounted: boolean = false;
|
||||||
this.setState({wifiChannels: wifiChannels});
|
|
||||||
})
|
|
||||||
.catch((error) => {});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
onWindowSizeChanged(width: number, height: number): void {
|
||||||
|
this.setState({ fullScreen: height < 200, compactWidth: width < 600, compactHeight: height < 450 })
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
handleOk(wifiWarningGiven: boolean) {
|
componentDidMount() {
|
||||||
let hasError = false;
|
super.componentDidMount();
|
||||||
if (this.state.enabled)
|
this.mounted = true;
|
||||||
{
|
this.applyDeferredWifiChannels();
|
||||||
let name = this.state.name;
|
this.applyDeferredWifiNetworks();
|
||||||
if (name.length === 0) {
|
}
|
||||||
this.setState({nameError: true, nameErrorMessage: "* Required"});
|
componentWillUnmount() {
|
||||||
hasError = true;
|
super.componentWillUnmount();
|
||||||
} else if (name.length > 31)
|
this.mounted = false;
|
||||||
{
|
}
|
||||||
this.setState({nameError: true, nameErrorMessage: "> 31 characters"});
|
|
||||||
|
private deferredWifiNetworks?: string[] = undefined;
|
||||||
|
|
||||||
|
applyDeferredWifiNetworks() {
|
||||||
|
if (this.mounted && this.deferredWifiNetworks) {
|
||||||
|
this.setState({ knownWifiNetworks: this.deferredWifiNetworks });
|
||||||
|
this.deferredWifiNetworks = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestKnownWifiNetworks() {
|
||||||
|
this.model.getKnownWifiNetworks()
|
||||||
|
.then((networks: string[]) => {
|
||||||
|
if (this.mounted) {
|
||||||
|
this.setState({ knownWifiNetworks: networks });
|
||||||
|
} else {
|
||||||
|
this.deferredWifiNetworks = networks;
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private lastChannelRequestCountryCode = "";
|
||||||
|
private deferredWifiChannels?: WifiChannel[] = undefined;
|
||||||
|
|
||||||
|
applyDeferredWifiChannels() {
|
||||||
|
if (this.mounted && this.deferredWifiChannels) {
|
||||||
|
this.setState({ wifiChannels: this.deferredWifiChannels });
|
||||||
|
this.deferredWifiChannels = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestWifiChannels(countryCode: string) {
|
||||||
|
if (countryCode === this.lastChannelRequestCountryCode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.lastChannelRequestCountryCode = countryCode;
|
||||||
|
this.model.getWifiChannels(countryCode)
|
||||||
|
.then((wifiChannels) => {
|
||||||
|
if (this.mounted) {
|
||||||
|
this.setState({ wifiChannels: wifiChannels });
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.lastChannelRequestCountryCode = ""; // try again later. :-/
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: WifiConfigProps) {
|
||||||
|
|
||||||
|
if (this.props.open && !prevProps.open) {
|
||||||
|
this.setState({
|
||||||
|
name: this.props.wifiConfigSettings.hotspotName,
|
||||||
|
newPassword: "",
|
||||||
|
autoStartMode: this.props.wifiConfigSettings.autoStartMode,
|
||||||
|
homeNetworkSsid: this.props.wifiConfigSettings.homeNetwork,
|
||||||
|
wifiWarningGiven: this.props.wifiConfigSettings.wifiWarningGiven,
|
||||||
|
countryCode: this.props.wifiConfigSettings.countryCode,
|
||||||
|
channel: this.props.wifiConfigSettings.channel
|
||||||
|
});
|
||||||
|
this.requestKnownWifiNetworks();
|
||||||
|
this.requestWifiChannels(this.props.wifiConfigSettings.countryCode);
|
||||||
|
|
||||||
|
}
|
||||||
|
this.applyDeferredWifiChannels();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultPasswordValue(): string {
|
||||||
|
return (this.state.showPassword && this.state.newPassword === "") ?
|
||||||
|
"password" :
|
||||||
|
this.state.newPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOk(wifiWarningGiven: boolean) {
|
||||||
|
let hasError = false;
|
||||||
|
if (this.state.autoStartMode !== 0) {
|
||||||
|
let name = this.state.name;
|
||||||
|
if (name.length === 0) {
|
||||||
|
this.setState({ nameError: true, nameErrorMessage: "* Required" });
|
||||||
|
hasError = true;
|
||||||
|
} else if (name.length > 31) {
|
||||||
|
this.setState({ nameError: true, nameErrorMessage: "> 31 characters" });
|
||||||
|
hasError = true;
|
||||||
|
}
|
||||||
|
let password = this.state.newPassword;
|
||||||
|
if (!this.props.wifiConfigSettings.hasSavedPassword && password.length === 0) {
|
||||||
|
this.setState({ passwordError: true, passwordErrorMessage: "* required" });
|
||||||
|
|
||||||
|
} else if (password.length > 0) {
|
||||||
|
if (password.length < 8) {
|
||||||
|
this.setState({ passwordError: true, passwordErrorMessage: "Less than 8 characters" });
|
||||||
|
hasError = true;
|
||||||
|
|
||||||
|
} else if (password.length > 63) {
|
||||||
|
this.setState({ passwordError: true, passwordErrorMessage: "> 63 characters" });
|
||||||
|
hasError = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.state.autoStartMode === 2 && this.state.homeNetworkSsid.length === 0) {
|
||||||
|
this.setState({ homeNetworkError: true, homeNetworkErrorMessage: "* Required" });
|
||||||
|
hasError = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.state.autoStartMode !== 0 && (!this.props.wifiConfigSettings.hasSavedPassword) && this.state.newPassword.length === 0) {
|
||||||
|
this.setState({ passwordError: true, passwordErrorMessage: "* Required" });
|
||||||
hasError = true;
|
hasError = true;
|
||||||
}
|
}
|
||||||
let password = this.state.newPassword;
|
if (!hasError) {
|
||||||
if (password.length > 0) {
|
let wifiConfigSettings = new WifiConfigSettings();
|
||||||
if (password.length < 8) {
|
wifiConfigSettings.valid = true;
|
||||||
this.setState({passwordError: true, passwordErrorMessage: "Less than 8 characters"});
|
|
||||||
hasError = true;
|
|
||||||
|
|
||||||
} else if (password.length > 63) {
|
wifiConfigSettings.autoStartMode = this.state.autoStartMode;
|
||||||
this.setState({passwordError: true, passwordErrorMessage: "> 63 characters"});
|
wifiConfigSettings.homeNetwork = this.state.homeNetworkSsid;
|
||||||
hasError = true;
|
wifiConfigSettings.hotspotName = this.state.name;
|
||||||
|
wifiConfigSettings.countryCode = this.state.countryCode;
|
||||||
|
wifiConfigSettings.channel = this.state.channel;
|
||||||
|
|
||||||
|
if (this.state.newPassword.length === 0 || this.state.autoStartMode === 0) {
|
||||||
|
wifiConfigSettings.hasPassword = false;
|
||||||
|
} else {
|
||||||
|
wifiConfigSettings.hasPassword = true;
|
||||||
|
wifiConfigSettings.password = this.state.newPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
if (!this.props.wifiConfigSettings.wifiWarningGiven && !wifiWarningGiven) {
|
||||||
}
|
this.setState({ showWifiWarningDialog: true });
|
||||||
if (this.state.enabled && (!this.props.wifiConfigSettings.hasPassword) && this.state.newPassword.length === 0)
|
} else {
|
||||||
{
|
wifiConfigSettings.wifiWarningGiven = true;
|
||||||
this.setState({passwordError: true, passwordErrorMessage: "* Required"});
|
|
||||||
hasError = true;
|
|
||||||
}
|
|
||||||
if (!hasError)
|
|
||||||
{
|
|
||||||
let wifiConfigSettings = new WifiConfigSettings();
|
|
||||||
wifiConfigSettings.valid = true;
|
|
||||||
|
|
||||||
wifiConfigSettings.enable = this.state.enabled;
|
|
||||||
wifiConfigSettings.hotspotName = this.state.name;
|
|
||||||
wifiConfigSettings.countryCode = this.state.countryCode;
|
|
||||||
wifiConfigSettings.channel = this.state.channel;
|
|
||||||
|
|
||||||
if (this.state.newPassword.length === 0 || !this.state.enabled)
|
|
||||||
{
|
|
||||||
wifiConfigSettings.hasPassword = false;
|
|
||||||
} else {
|
|
||||||
wifiConfigSettings.hasPassword = true;
|
|
||||||
wifiConfigSettings.password = this.state.newPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.props.wifiConfigSettings.wifiWarningGiven && !wifiWarningGiven) {
|
|
||||||
this.setState({showWifiWarningDialog: true});
|
|
||||||
} else {
|
|
||||||
wifiConfigSettings.wifiWarningGiven = true;
|
|
||||||
this.preventPasswordPrompt();
|
|
||||||
// let preventPasswordPrompt changes settle (it's HARD to prevent a password prompt)
|
|
||||||
setTimeout(()=> {
|
|
||||||
this.props.onOk(wifiConfigSettings);
|
this.props.onOk(wifiConfigSettings);
|
||||||
},100);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
handleChannelChange(e: any) {
|
||||||
preventPasswordPrompt()
|
let value = e.target.value as string;
|
||||||
{
|
this.setState({ channel: value });
|
||||||
let passwordInput = this.refPassword.current;
|
|
||||||
if (passwordInput)
|
|
||||||
{
|
|
||||||
passwordInput.type = "text";
|
|
||||||
passwordInput.value = "";
|
|
||||||
}
|
}
|
||||||
this.setState({newPassword: ""});
|
handleCountryChanged(e: any) {
|
||||||
}
|
let value = e.target.value as string;
|
||||||
handleChannelChange(e: any)
|
|
||||||
{
|
|
||||||
let value = e.target.value as string;
|
|
||||||
this.setState({channel: value });
|
|
||||||
}
|
|
||||||
handleCountryChanged(e: any)
|
|
||||||
{
|
|
||||||
let value = e.target.value as string;
|
|
||||||
|
|
||||||
this.setState({countryCode: value});
|
this.setState({ countryCode: value });
|
||||||
this.model.getWifiChannels(value)
|
this.requestWifiChannels(value);
|
||||||
.then(wifiChannels => {
|
}
|
||||||
this.setState({wifiChannels: wifiChannels});
|
handleTogglePasswordVisibility() {
|
||||||
})
|
this.setState({ hasPassword: true, showPassword: !this.state.showPassword });
|
||||||
.catch((error)=> { });
|
}
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
private homeNetworkSsidElement?: HTMLInputElement = undefined;
|
||||||
let props = this.props;
|
|
||||||
let classes = this.props.classes;
|
|
||||||
let { open, onClose} = props;
|
|
||||||
|
|
||||||
const handleClose = () => {
|
getCountryCodeValue(countryCode: string) {
|
||||||
this.preventPasswordPrompt();
|
let value = this.model.countryCodes[countryCode];
|
||||||
// let preventPasswordPrompt changes settle (it's HARD to prevent a password prompt)
|
if (!value) return undefined;
|
||||||
setTimeout(()=> {
|
return { label: value, id: countryCode };
|
||||||
|
}
|
||||||
|
|
||||||
|
getCountryCodeOptions(): { id: string, label: string }[] {
|
||||||
|
if (gCountryCodeOptions) {
|
||||||
|
return gCountryCodeOptions;
|
||||||
|
}
|
||||||
|
let result: { label: string, id: string }[] = [];
|
||||||
|
for (let key in this.model.countryCodes) {
|
||||||
|
let value = this.model.countryCodes[key];
|
||||||
|
result.push({ id: key, label: value });
|
||||||
|
}
|
||||||
|
result.sort((left, right) => {
|
||||||
|
return left.label.localeCompare(right.label);
|
||||||
|
});
|
||||||
|
if (result.length !== 0) {
|
||||||
|
gCountryCodeOptions = result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
let props = this.props;
|
||||||
|
let classes = this.props.classes;
|
||||||
|
let { open, onClose } = props;
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
onClose();
|
onClose();
|
||||||
},100);
|
};
|
||||||
};
|
let enabled = this.state.autoStartMode !== 0;
|
||||||
|
return (
|
||||||
return (
|
<DialogEx tag="wifiConfig" open={open} fullWidth onClose={handleClose} style={{ userSelect: "none" }}
|
||||||
<DialogEx tag="wifiConfig" open={open} fullWidth onClose={handleClose} style={{userSelect: "none"}}
|
fullScreen={this.state.fullScreen}
|
||||||
fullScreen={this.state.fullScreen}
|
>
|
||||||
>
|
{(this.state.fullScreen || !this.state.compactHeight) && (
|
||||||
{ this.state.fullScreen && (
|
<DialogTitle>Wi-fi Hotspot</DialogTitle>
|
||||||
<DialogTitle>Wi-fi Hotspot</DialogTitle>
|
)}
|
||||||
)}
|
|
||||||
<DialogContent>
|
|
||||||
|
|
||||||
<FormControlLabel
|
|
||||||
control={(
|
|
||||||
<Switch
|
|
||||||
checked={this.state.enabled}
|
|
||||||
onChange={(e: any) => this.handleEnableChanged(e)}
|
|
||||||
color="primary"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
label="Enable"
|
|
||||||
/>
|
|
||||||
<TextField style={{ marginBottom: 16, marginTop: 16 }}
|
|
||||||
|
|
||||||
autoComplete="off"
|
|
||||||
id="name"
|
|
||||||
spellCheck="false"
|
|
||||||
label="SSID"
|
|
||||||
type="text"
|
|
||||||
fullWidth
|
|
||||||
error={this.state.nameError}
|
|
||||||
helperText={this.state.nameErrorMessage}
|
|
||||||
value={this.state.name}
|
|
||||||
onChange={(e) => this.setState({name: e.target.value, nameError: false, nameErrorMessage: NBSP})}
|
|
||||||
inputRef={this.refName}
|
|
||||||
disabled={!this.state.enabled}
|
|
||||||
/>
|
|
||||||
<div style={{ marginBottom: 16 }}>
|
|
||||||
<input type="password" style={{display:"none"}}/>
|
|
||||||
<NoChangePassword
|
|
||||||
inputRef={this.refPassword}
|
|
||||||
onPasswordChange={(text): void => { this.setState({ newPassword: text, passwordError: false, passwordErrorMessage: NBSP }); }}
|
|
||||||
hasPassword={this.props.wifiConfigSettings.hasPassword}
|
|
||||||
label="WEP Passphrase"
|
|
||||||
error={this.state.passwordError}
|
|
||||||
helperText={this.state.passwordErrorMessage}
|
|
||||||
defaultValue={this.state.newPassword}
|
|
||||||
disabled={!this.state.enabled}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div style={{ marginBottom: 16}}>
|
|
||||||
<FormControl>
|
|
||||||
<InputLabel htmlFor="countryCodeSelect">Country</InputLabel>
|
|
||||||
<Select variant="standard" id="countryCodeSelect" value={this.state.countryCode} style={{width: 220}}
|
|
||||||
onChange={(event)=>this.handleCountryChanged(event)} >
|
|
||||||
{Object.entries(this.model.countryCodes).map(([key,value])=> {
|
|
||||||
return (
|
|
||||||
<MenuItem value={key}>{value}</MenuItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div style={{ marginBottom: 24}}>
|
|
||||||
<FormControl>
|
|
||||||
<InputLabel htmlFor="channelSelect">Channel</InputLabel>
|
|
||||||
<Select variant="standard" id="channelSelect" value={this.state.channel} style={{width: 220}} onChange={(e)=>{
|
|
||||||
this.handleChannelChange(e);
|
|
||||||
}}>
|
|
||||||
{this.state.wifiChannels.map((channel)=> {
|
|
||||||
return (
|
|
||||||
<MenuItem value={channel.channelId}>{channel.channelName}</MenuItem>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={handleClose} variant="dialogSecondary" style={{ width: 120 }}>
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
<Button onClick={()=> this.handleOk(false)} variant="dialogPrimary" style={{ width: 120 }} >
|
|
||||||
OK
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
<DialogEx open={this.state.showWifiWarningDialog} tag="wifiConfirm"
|
|
||||||
style={{userSelect: "none"}}>
|
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<Typography className={classes.pgraph} variant="body2" color="textPrimary">
|
<div style={
|
||||||
Enabling the Wi-Fi hotspot will disable regular Wi-Fi network access on the PiPedal device. Once
|
!this.state.compactWidth
|
||||||
enabled, connect to the hotspot and launch http://172.23.0.2 or http://{this.state.name}.local to access the PiPedal web app again.
|
? { display: "flex", gap: 16, flexDirection: "column", flexFlow: "nowrap", alignItems: "start" }
|
||||||
</Typography>
|
: { display: "block", gap: 16, flexDirection: "row", flexFlow: "nowrap" }
|
||||||
<Typography className={classes.pgraph} variant="body2" color="textPrimary" gutterBottom>
|
}
|
||||||
Are you sure you want to proceed?
|
>
|
||||||
</Typography>
|
<div style={{
|
||||||
|
display: "flex", flexGrow: 1, flexBasis: 100,
|
||||||
|
gap: 16, flexDirection: "column", flexFlow: "nowrap", alignItems: "start"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
|
||||||
|
<FormControl variant="standard" style={{ flexGrow: 1, flexBasis: 1 }} >
|
||||||
|
<InputLabel htmlFor="behavior">Auto-start hotspot when</InputLabel>
|
||||||
|
<Select id="behavior" value={this.state.autoStartMode}
|
||||||
|
onChange={(el) => {
|
||||||
|
let value = el.target.value as number
|
||||||
|
this.setState({
|
||||||
|
autoStartMode: value
|
||||||
|
|
||||||
|
});
|
||||||
|
if (value === 2 && this.state.homeNetworkSsid.length === 0 && this.state.knownWifiNetworks.length !== 0) {
|
||||||
|
this.setState({
|
||||||
|
homeNetworkSsid: this.state.knownWifiNetworks[0]
|
||||||
|
});
|
||||||
|
if (this.homeNetworkSsidElement) {
|
||||||
|
this.homeNetworkSsidElement.value = this.state.knownWifiNetworks[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem value={0}>Never</MenuItem>
|
||||||
|
<MenuItem value={1}>No ethernet connection</MenuItem>
|
||||||
|
<MenuItem value={2}>Not at home</MenuItem>
|
||||||
|
<MenuItem value={3}>No remembered Wi-Fi connections</MenuItem>
|
||||||
|
<MenuItem value={4}>Always</MenuItem>
|
||||||
|
</Select>
|
||||||
|
<FormHelperText>{NBSP}</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
{(this.state.compactWidth || this.state.autoStartMode !== 2) && (
|
||||||
|
<IconButton style={{ flexGrow: 0, flexShrink: 0, marginTop: 8 }}
|
||||||
|
onClick={() => { this.setState({ showHelpDialog: true }); }}
|
||||||
|
>
|
||||||
|
<HelpOutlineIcon />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div style={{
|
||||||
|
display: this.state.autoStartMode === 2 ? "flex" : "none", gap: 16, flexGrow: 1, flexBasis: 100, flexDirection: "column", flexFlow: "nowrap", alignItems: "center",
|
||||||
|
}}>
|
||||||
|
<Autocomplete options={this.state.knownWifiNetworks}
|
||||||
|
freeSolo autoSelect={false} forcePopupIcon={true}
|
||||||
|
style={{
|
||||||
|
flexGrow: 1, marginLeft: this.state.compactWidth ? 32 : 0
|
||||||
|
}}
|
||||||
|
value={this.state.homeNetworkSsid}
|
||||||
|
|
||||||
|
onChange={(event, value): void => {
|
||||||
|
this.setState({ homeNetworkSsid: value?.toString() ?? "", homeNetworkError: false, homeNetworkErrorMessage: NBSP });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderInput={
|
||||||
|
(params) =>
|
||||||
|
<TextField {...params} variant="standard" label="Home Network SSID"
|
||||||
|
autoComplete="off"
|
||||||
|
spellCheck="false"
|
||||||
|
error={this.state.homeNetworkError}
|
||||||
|
onChange={
|
||||||
|
(event) => {
|
||||||
|
this.setState({ homeNetworkSsid: event.target.value, homeNetworkError: false, homeNetworkErrorMessage: NBSP });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
helperText={this.state.homeNetworkErrorMessage}
|
||||||
|
InputLabelProps={{
|
||||||
|
shrink: true
|
||||||
|
}}
|
||||||
|
/>}
|
||||||
|
/>
|
||||||
|
<IconButton style={{ visibility: this.state.compactWidth ? "hidden" : "visible", flexGrow: 0, flexShrink: 0 }}
|
||||||
|
onClick={() => { this.setState({ showHelpDialog: true }); }}
|
||||||
|
>
|
||||||
|
<HelpOutlineIcon />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={
|
||||||
|
!this.state.compactWidth
|
||||||
|
? { display: "flex", flexFlow: "row nowrap", gap: 24, alignItems: "start" }
|
||||||
|
: { display: "block" }
|
||||||
|
}>
|
||||||
|
|
||||||
|
<TextField variant="standard" style={{ marginBottom: 8, flexGrow: 1, flexBasis: 1 }}
|
||||||
|
|
||||||
|
autoComplete="off"
|
||||||
|
spellCheck="false"
|
||||||
|
error={this.state.nameError}
|
||||||
|
id="name"
|
||||||
|
label="SSID"
|
||||||
|
type="text"
|
||||||
|
fullWidth
|
||||||
|
helperText={this.state.nameErrorMessage}
|
||||||
|
value={this.state.name}
|
||||||
|
onChange={(e) => this.setState({ name: e.target.value, nameError: false, nameErrorMessage: NBSP })}
|
||||||
|
inputRef={this.refName}
|
||||||
|
InputLabelProps={{
|
||||||
|
shrink: true
|
||||||
|
}}
|
||||||
|
disabled={!enabled}
|
||||||
|
/>
|
||||||
|
<div style={{ marginBottom: 8, flexGrow: 1, flexBasis: 1 }}>
|
||||||
|
<form autoComplete='off' onSubmit={() => false}> {/*Prevents chrome from saving passwords */}
|
||||||
|
<TextField label="WEP passphrase" variant="standard"
|
||||||
|
autoComplete="off"
|
||||||
|
spellCheck="false"
|
||||||
|
fullWidth
|
||||||
|
error={this.state.passwordError}
|
||||||
|
|
||||||
|
onFocus={() => { this.setState({ hasPassword: true }) }}
|
||||||
|
type={this.state.showPassword ? "text" : "password"}
|
||||||
|
onChange={(event): void => {
|
||||||
|
this.setState({ hasPassword: true, newPassword: event.target.value.toString(), passwordError: false, passwordErrorMessage: NBSP });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
helperText={this.state.passwordErrorMessage}
|
||||||
|
defaultValue={
|
||||||
|
this.getDefaultPasswordValue()
|
||||||
|
}
|
||||||
|
disabled={!enabled}
|
||||||
|
InputLabelProps={{
|
||||||
|
shrink: true
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment:
|
||||||
|
this.props.wifiConfigSettings.hasSavedPassword && !this.state.hasPassword && !this.state.showPassword ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : ""
|
||||||
|
,
|
||||||
|
endAdornment: (
|
||||||
|
<IconButton size="small"
|
||||||
|
aria-label="toggle password visibility"
|
||||||
|
onClick={() => { this.handleTogglePasswordVisibility(); }}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
(this.state.showPassword) ?
|
||||||
|
(
|
||||||
|
<VisibilityIcon fontSize="small" />
|
||||||
|
) :
|
||||||
|
(
|
||||||
|
<VisibilityOffIcon fontSize="small" />
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</IconButton>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div style={
|
||||||
|
!this.state.compactWidth
|
||||||
|
? { display: "flex", flexFlow: "row nowrap", gap: 24, alignItems: "start" }
|
||||||
|
: { display: "block" }
|
||||||
|
}>
|
||||||
|
<div style={{ display: "flex", marginBottom: 8, flexGrow: 1, flexBasis: 1 }}>
|
||||||
|
<Autocomplete fullWidth
|
||||||
|
defaultValue={this.getCountryCodeValue(this.state.countryCode)}
|
||||||
|
disableClearable={true}
|
||||||
|
onChange={(event, value) => { if (value) { this.setState({ countryCode: value.id }) } }}
|
||||||
|
options={this.getCountryCodeOptions()}
|
||||||
|
renderInput={(params) => (<TextField {...params} variant="standard" label="Regulatory Domain" />)}
|
||||||
|
/>
|
||||||
|
{/*
|
||||||
|
<Select variant="standard" label="Regulatory Domain" id="countryCodeSelect"
|
||||||
|
fullWidth value={this.state.countryCode} style={{}}
|
||||||
|
onChange={(event) => this.handleCountryChanged(event)} disabled={!enabled} >
|
||||||
|
{Object.entries(this.model.countryCodes).map(([key, value]) => {
|
||||||
|
return (
|
||||||
|
<MenuItem value={key}>{value}</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
*/}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div style={{ display: "flex", flexFlow: "column nowrap", marginBottom: 8, flexGrow: 1, flexBasis: 1 }}>
|
||||||
|
<FormControl style={{ flexGrow: 1 }} >
|
||||||
|
<InputLabel htmlFor="channelSelect">Channel</InputLabel>
|
||||||
|
<Select variant="standard" id="channelSelect" value={this.state.channel}
|
||||||
|
fullWidth
|
||||||
|
disabled={!enabled}
|
||||||
|
onChange={(e) => {
|
||||||
|
this.handleChannelChange(e);
|
||||||
|
}}>
|
||||||
|
{this.state.wifiChannels.map((channel) => {
|
||||||
|
return (
|
||||||
|
<MenuItem value={channel.channelId}>{channel.channelName}</MenuItem>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={()=> this.setState({showWifiWarningDialog: false})} variant="dialogSecondary" style={{ width: 120 }}>
|
<Button onClick={handleClose} variant="dialogSecondary" style={{ width: 120 }}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={()=> {
|
<Button onClick={() => this.handleOk(false)} variant="dialogPrimary" style={{ width: 120 }} >
|
||||||
this.setState({showWifiWarningDialog: false});
|
OK
|
||||||
this.handleOk(true);
|
|
||||||
}} variant="dialogPrimary" style={{ width: 120 }} >
|
|
||||||
PROCEED
|
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</DialogEx>
|
{this.state.showHelpDialog && (
|
||||||
</DialogEx>
|
<DialogEx open={this.state.showHelpDialog} tag="wifiHelp"
|
||||||
);
|
style={{ userSelect: "none" }}>
|
||||||
}
|
<DialogContent>
|
||||||
});
|
<Typography className={classes.pgraph} variant="h6" color="textPrimary">
|
||||||
|
PiPedal Auto-Hotspot
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography className={classes.pgraph} variant="body2" color="textPrimary">
|
||||||
|
The PiPedal <b><i>Auto-Hotspot</i></b> feature allows you to connect to your Raspberry Pi even if you don't have
|
||||||
|
access to a Wi-Fi router. For example, if you are performing at a live venue, you probably will not
|
||||||
|
have access to a Wi-Fi router; but you can configure PiPedal so that your Raspberry Pi automatically
|
||||||
|
starts a Wi-Fi hotspot when you are not at home. The feature is primarily intended for use with the
|
||||||
|
PiPedal Android client, but you may find it useful for other purposes as well.
|
||||||
|
</Typography>
|
||||||
|
<Typography className={classes.pgraph} variant="body2" color="textPrimary">
|
||||||
|
Raspberry Pi's are unable to run hotspots, and have another active Wi-Fi connection at the same time; so the auto-hotspot feature
|
||||||
|
automatically turns the hotspot on, when your Raspberry Pi cannot otherwise be connected to, and can be configured to
|
||||||
|
automatically turn the PiPedal hotspot off when you do want your Raspberry Pi to connect to another Wi-Fi access point.
|
||||||
|
Which auto-start option you should select depends on how you normally connect to your Raspberry Pi when you are at home.
|
||||||
|
</Typography>
|
||||||
|
<Typography className={classes.pgraph} variant="body2" color="textPrimary">
|
||||||
|
If you normally connect to your Raspberry Pi using an ethernet connection, the <b><i>No ethernet connection</i></b> is a
|
||||||
|
good choice. The PiPedal Wi-Fi hotspot will be available whenever the ethernet cable is unplugged. <b><i>Always on</i></b> is
|
||||||
|
also a good choice, but may confuse your phone or tablet, since your Android device will now have to decide whether to auto-connect to your home Wi-Fi
|
||||||
|
router, or to the Raspberry Pi hotspot. If you use the <b><i>No ethernet connection</i></b> option, your phone or tablet will
|
||||||
|
never see the PiPedal hotspot and your Wi-Fi router at the same time.
|
||||||
|
</Typography>
|
||||||
|
<Typography className={classes.pgraph} variant="body2" color="textPrimary">
|
||||||
|
If you normally connect to your Raspberry Pi through a Wi-Fi router, <b><i>Not at home</i></b> is a good choice. The
|
||||||
|
PiPedal hotspot will be automatically turned off whenever your home Wi-Fi router is in range, and automatically turned on
|
||||||
|
when you are out of range of your home Wi-Fi router.
|
||||||
|
</Typography>
|
||||||
|
<Typography className={classes.pgraph} variant="body2" color="textPrimary">
|
||||||
|
If there are multiple locations, and multiple Wi-Fi routers you use with PiPedal on a regular basis, you can select
|
||||||
|
the <b><i>No remembered Wi-Fi connections</i></b> option, but this is a riskier option. The PiPedal hotspot will be automatically turned on if there are no
|
||||||
|
Wi-Fi access points in range that you have previously connected to from your Raspberry Pi, and will be automatically turned on otherwise.
|
||||||
|
The risk is that you could find yourself unable to connect to your Raspberry Pi when performing
|
||||||
|
at a local bar, after you have used your Rasberry Pi to connect to the Wi-Fi access point at the coffee shop nextdoor. (Public Wi-Fi access
|
||||||
|
points usually won't work because devices that are connected to a public access point can't connect to each other).
|
||||||
|
Will you ever do that? Probably not. But there is some risk that you might find yourself unable to connect at a live venue. Whether that's an
|
||||||
|
acceptable risk is up to you.
|
||||||
|
</Typography>
|
||||||
|
<Typography className={classes.pgraph} variant="body2" color="textPrimary">
|
||||||
|
Typically, when you're away from home, there's no easy way to connect to your Raspberry Pi from a laptop in order to
|
||||||
|
correct the problem. So you should carefully test that your auto-hotspot configuration works as expected before you adventure
|
||||||
|
away from home with PiPedal.
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
onClick={
|
||||||
|
() => {
|
||||||
|
this.setState({ showHelpDialog: false });
|
||||||
|
}}
|
||||||
|
variant="dialogSecondary" >
|
||||||
|
Ok
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
|
||||||
|
</DialogEx>
|
||||||
|
|
||||||
|
)}
|
||||||
|
{this.state.showWifiWarningDialog && (
|
||||||
|
<DialogEx open={this.state.showWifiWarningDialog} tag="wifiConfirm"
|
||||||
|
style={{ userSelect: "none" }}>
|
||||||
|
<DialogContent>
|
||||||
|
<Typography className={classes.pgraph} variant="body2" color="textPrimary">
|
||||||
|
Enabling the Wi-Fi hotspot will disable regular Wi-Fi network access on your Raspberry Pi when the PiPedal hotspot is active.
|
||||||
|
If you are relying on Wi-Fi access to connect to your Raspberry Pi, consider carefully whether your autostart options
|
||||||
|
will allow you to connect to your Raspberry Pi once applied. PiPedal
|
||||||
|
<a href="https://rerdavies.github.io/pipedal/Configuring.html" target="_blank" rel="noreferrer">
|
||||||
|
online documentation</a> provides a discussion of how to choose safe hotspot auto-start options.
|
||||||
|
</Typography>
|
||||||
|
<Typography className={classes.pgraph} variant="body2" color="textPrimary">
|
||||||
|
When you are connected to the PiPedal hotspot, you can connect to the PiPedal web server at http://10.48.0.1.
|
||||||
|
</Typography>
|
||||||
|
<Typography className={classes.pgraph} variant="body2" color="textPrimary" gutterBottom>
|
||||||
|
Are you sure you want to continue?
|
||||||
|
</Typography>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={() => this.setState({ showWifiWarningDialog: false })} variant="dialogSecondary" style={{ width: 120 }}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button onClick={() => {
|
||||||
|
this.setState({ showWifiWarningDialog: false });
|
||||||
|
this.handleOk(true);
|
||||||
|
}} variant="dialogPrimary" style={{ width: 120 }} >
|
||||||
|
PROCEED
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</DialogEx>
|
||||||
|
)}
|
||||||
|
</DialogEx >
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default WifiConfigDialog;
|
export default WifiConfigDialog;
|
||||||
@@ -21,10 +21,12 @@
|
|||||||
|
|
||||||
export default class WifiConfigSettings {
|
export default class WifiConfigSettings {
|
||||||
deserialize(input: any) : WifiConfigSettings{
|
deserialize(input: any) : WifiConfigSettings{
|
||||||
|
this.autoStartMode = input.autoStartMode;
|
||||||
|
this.hasSavedPassword = input.hasSavedPassword;
|
||||||
|
this.homeNetwork = input.homeNetwork;
|
||||||
this.valid = input.valid;
|
this.valid = input.valid;
|
||||||
|
|
||||||
this.wifiWarningGiven = input.wifiWarningGiven;
|
this.wifiWarningGiven = input.wifiWarningGiven;
|
||||||
this.rebootRequired = input.rebootRequired;
|
|
||||||
this.enable = input.enable;
|
|
||||||
this.hotspotName = input.hotspotName;
|
this.hotspotName = input.hotspotName;
|
||||||
this.hasPassword = input.hasPassword;
|
this.hasPassword = input.hasPassword;
|
||||||
this.password = input.password;
|
this.password = input.password;
|
||||||
@@ -35,29 +37,27 @@ export default class WifiConfigSettings {
|
|||||||
clone() : WifiConfigSettings {
|
clone() : WifiConfigSettings {
|
||||||
return new WifiConfigSettings().deserialize(this);
|
return new WifiConfigSettings().deserialize(this);
|
||||||
}
|
}
|
||||||
valid: boolean = true;
|
autoStartMode: number = 0;
|
||||||
|
hasSavedPassword: boolean = false;
|
||||||
|
homeNetwork: string = "";
|
||||||
wifiWarningGiven: boolean = false;
|
wifiWarningGiven: boolean = false;
|
||||||
enable: boolean = true;
|
|
||||||
hasPassword: boolean = false;
|
hasPassword: boolean = false;
|
||||||
rebootRequired = false;
|
valid: boolean = false;
|
||||||
hotspotName: string = "pipedal";
|
hotspotName: string = "pipedal";
|
||||||
password: string = "";
|
password: string = "";
|
||||||
countryCode: string = "US";
|
countryCode: string = "US";
|
||||||
channel: string = "g6";
|
channel: string = "0";
|
||||||
|
|
||||||
|
isEnabled() { return this.autoStartMode !== 0;}
|
||||||
getSummaryText() {
|
getSummaryText() {
|
||||||
let result: string;
|
let result: string;
|
||||||
if (!this.valid) {
|
if (!this.valid) {
|
||||||
result = "Not available.";
|
result = "Not available.";
|
||||||
} else if (!this.enable) {
|
} else if (this.autoStartMode === 0) {
|
||||||
result = "Disabled.";
|
result = "Disabled.";
|
||||||
} else {
|
} else {
|
||||||
result = this.hotspotName;
|
result = this.hotspotName;
|
||||||
}
|
}
|
||||||
if (this.rebootRequired)
|
|
||||||
{
|
|
||||||
result += " (Restart required)";
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+111
-100
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2022 Robin Davies
|
// Copyright (c) 2022-2024 Robin Davies
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
// this software and associated documentation files (the "Software"), to deal in
|
// this software and associated documentation files (the "Software"), to deal in
|
||||||
@@ -1132,7 +1132,7 @@ static void PrintHelp()
|
|||||||
PrettyPrinter pp;
|
PrettyPrinter pp;
|
||||||
pp << "pipedalconfig - Command-line post-install configuration for PiPedal"
|
pp << "pipedalconfig - Command-line post-install configuration for PiPedal"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "Copyright (c) 2022 Robin Davies. All rights reserved."
|
<< "Copyright (c) 2022-2024 Robin Davies."
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "See https://rerdavies.github.io/pipedal/Documentation.html for "
|
<< "See https://rerdavies.github.io/pipedal/Documentation.html for "
|
||||||
@@ -1157,10 +1157,10 @@ static void PrintHelp()
|
|||||||
<< "\n"
|
<< "\n"
|
||||||
|
|
||||||
<< HangingIndent() << " --install [--port <port#>]\t"
|
<< HangingIndent() << " --install [--port <port#>]\t"
|
||||||
<< "Install or re-install services and service accounts."
|
<< "Install or re-install PiPedal services and service accounts."
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "The --port option controls which port the web server uses."
|
<< "The --port option controls which TCP/IP port the web server uses."
|
||||||
<< "\n\n"
|
<< "\n\n"
|
||||||
|
|
||||||
<< HangingIndent() << " --uninstall\t"
|
<< HangingIndent() << " --uninstall\t"
|
||||||
@@ -1169,68 +1169,54 @@ static void PrintHelp()
|
|||||||
<< "\n"
|
<< "\n"
|
||||||
|
|
||||||
<< HangingIndent() << " --enable\t"
|
<< HangingIndent() << " --enable\t"
|
||||||
<< "Start the pipedal service at boot time."
|
<< "Start PiPedal services at boot time."
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
|
|
||||||
<< HangingIndent() << " --disable\tDo not start the pipedal service at boot time."
|
<< HangingIndent() << " --disable\tDo not start PiPedal services at boot time."
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< HangingIndent() << " --start\tStart the pipedal services."
|
<< HangingIndent() << " --start\tStart PiPedal services."
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< HangingIndent() << " --stop\tStop the pipedal services."
|
<< HangingIndent() << " --stop\tStop PiPedal services."
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< HangingIndent() << " --restart\tRestart the pipedal services."
|
<< HangingIndent() << " --restart\tRestart PiPedal services."
|
||||||
<< "\n"
|
<< "\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
|
<< HangingIndent() << " --enable-hotspot\t <country_code> <ssid> <wep_password> <channel> [<hotspot-option>]"
|
||||||
<< HangingIndent() << " --enable-p2p [<country_code> <ssid> [[<pin>] <channel>] ]\t"
|
<< "\n\nEnable Wi-Fi hotspot."
|
||||||
<< "Enable the P2P (Wi-Fi Direct) hotspot."
|
|
||||||
<< "\n\n"
|
<< "\n\n"
|
||||||
<< "With no additional arguments, the P2P channel is enabled with most-recent settings."
|
<< "PiPedal's Wi-Fi hotspot allows you to connect to your Raspberry Pi when you don't have a Wi-Fi router, for example, when you are "
|
||||||
|
<< "performing away from home. It is most particularly useful when using the PiPedal Android client. Consult PiPedal's online documentation "
|
||||||
|
<< "for guidance on configuring a Wi-Fi hotspot."
|
||||||
<< "\n\n"
|
<< "\n\n"
|
||||||
<< "<country_code> is the 2-letter ISO-3166 country code for "
|
<< "One of the following hotspot options can be specifed. If no hotspot option is given, the hotspot will always be enabled. "
|
||||||
"the country you are in. see below for further notes."
|
<< "If one of the hotspot options are given, the PiPedal server will turn the hotspot on or off automatically, as conditions change."
|
||||||
|
<< "\n\n"
|
||||||
|
<< "--home-network <wifi-ssid>\n"
|
||||||
|
<< AddIndent(4) << "Hotspot is disabled if the specificed Wi-Fi network is detected.\n"
|
||||||
|
<< AddIndent(-4)
|
||||||
|
<< "--no-ethernet\n"
|
||||||
|
<< AddIndent(4) << "Hotspot is disabled if an ethernet network is connected.\n"
|
||||||
|
<< AddIndent(-4)
|
||||||
|
<< "--no-wifi\n"
|
||||||
|
<< AddIndent(4) << "Hotspot is disabled if a remembered Wi-Fi network is detected.\n"
|
||||||
|
<< AddIndent(-4)
|
||||||
|
<< "\n"
|
||||||
|
<< "Caution: Wi-Fi connections are disabled when the hotspot is activated. If you currently access your Raspberry Pi using "
|
||||||
|
<< "Wi-Fi, choose your hotspot options carefully, to ensure that you can still access your Raspberry Pi."
|
||||||
<< "\n\n"
|
<< "\n\n"
|
||||||
<< "<ssid> is the name you see when connecting. "
|
<< "country_code is the 2-letter ISO-3166 country code for "
|
||||||
|
<< "the country you are in. see below for further notes."
|
||||||
<< "\n\n"
|
<< "\n\n"
|
||||||
<< "<pin> is an exactly-eight-digit pin number that you must "
|
<< "If the Wi-Fi channel is not specified, a Wi-Fi channel will be automatically selected."
|
||||||
<< "enter when connecting to the hotspot. If you don't "
|
|
||||||
<< "provide a pin, pipedalconfig will generate and "
|
|
||||||
<< "display a random pin for you. The pin is a "
|
|
||||||
<< "so-called \"label\" pin, which is the same every "
|
|
||||||
<< "time you are asked to enter it (unlike a keypad pin "
|
|
||||||
<< "which changes every time you need to enter it."
|
|
||||||
<< "\n\n"
|
|
||||||
<< "Consider attaching a label to the bottom of your device "
|
|
||||||
<< "so you can can remember the pin if you wan't to connect a new "
|
|
||||||
<< "device to PiPedal. (It's also available on the Settings page of PiPedal, if you have access to PiPedal UI on another device.)"
|
|
||||||
<< "\n\n"
|
|
||||||
<< "For best performance, the channel number should be 1, 6, or 11 (the Wifi Direct \"social\" channels). "
|
|
||||||
<< "Channel number defaults to 1."
|
|
||||||
<< "\n\n"
|
<< "\n\n"
|
||||||
|
|
||||||
<< HangingIndent() << " --disable-p2p\tDisable Wi-Fi Direct access."
|
<< HangingIndent() << " --disable-hotspot\tDisabled the Wi-Fi hotspot."
|
||||||
<< "\n\n"
|
<< "\n\n"
|
||||||
|
<< HangingIndent() << " --list-wifi-channels [<country_code>] \tList valid Wifi channels for the current/specified country."
|
||||||
<< HangingIndent() << " --list-p2p-channels [<country_code>] \tList valid p2p channels for the current/specified country."
|
|
||||||
<< "\n\n"
|
|
||||||
|
|
||||||
// << HangingIndent() << " --enable-legacy-ap\t <country_code> <ssid> <wep_password> <channel>\tEnable a legacy Wi-Fi access point."
|
|
||||||
// << "\n\n"
|
|
||||||
// << "Enable a legacy Wi-Fi access point. \n\n"
|
|
||||||
// << "country_code is the 2-letter ISO-3166 country code for "
|
|
||||||
// << "the country you are in. see below for further notes."
|
|
||||||
// << "\n\n"
|
|
||||||
// << "See below for an explanation of when you might want to use a legacy Wi-Fi access point instead of Wifi-Direct access."
|
|
||||||
// << "an explanation of when you might want to use a legacy Access Point instead of "
|
|
||||||
// << "a P2P (Wi-Fi Direct) connection. Generally, you should prefer a P2p connection "
|
|
||||||
// << "to an ordinary Hotspot connection."
|
|
||||||
// << "\n\n"
|
|
||||||
|
|
||||||
<< HangingIndent() << " --disable-legacy-ap\tDisabled the legacy Wi-Fi access point."
|
|
||||||
<< "\n\n"
|
<< "\n\n"
|
||||||
|
|
||||||
<< Indent(0) << "Country codes:"
|
<< Indent(0) << "Country codes:"
|
||||||
@@ -1244,28 +1230,11 @@ static void PrintHelp()
|
|||||||
<< "with reduced amplitude and feature sets."
|
<< "with reduced amplitude and feature sets."
|
||||||
<< "\n\n"
|
<< "\n\n"
|
||||||
<< "For the most part, Wi-Fi country codes are taken from the list of ISO 3661 "
|
<< "For the most part, Wi-Fi country codes are taken from the list of ISO 3661 "
|
||||||
<< "2-letter country codes; although there are a handful of exceptions for small "
|
<< "2-letter country codes; although there are a handful of exceptions for small "
|
||||||
<< "countries and islands. See the Alpha-2 code column of "
|
<< "countries and islands. See the Alpha-2 code column of "
|
||||||
<< "\n\n"
|
<< "\n\n"
|
||||||
<< Indent(8) << "https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes."
|
<< Indent(8) << "https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes."
|
||||||
<< "\n\n"
|
<< "\n\n";
|
||||||
|
|
||||||
<< Indent(0) << "Legacy Wi-Fi Access Points:"
|
|
||||||
<< "\n\n"
|
|
||||||
<< Indent(4)
|
|
||||||
<< "Some older devices may not be able to connect to PiPedal using Wi-Fi Direct connections. "
|
|
||||||
"Old Apple devices, for example, do not support Wi-Fi Direct. In theory, Wi-Fi Direct should "
|
|
||||||
"allow legacy Wi-Fi devices to connect to a Wi-Fi Direct access points as if it were an "
|
|
||||||
"ordinary Access Point. If this turns out "
|
|
||||||
"not to be the case, you can configure PiPedal to provide a legacy Wi-Fi access point instead. "
|
|
||||||
"\n\n"
|
|
||||||
"Unlike Wi-Fi Direct connections, legacy Access Points will prevent both the connecting device "
|
|
||||||
"and the PiPedal host machine from connecting to the Internet over a simultanous Wi-Fi connection Access "
|
|
||||||
"Point. On a connecting Android device, you won't be able to use the data connection either when a legacy "
|
|
||||||
"Wi-Fi connection is active."
|
|
||||||
"\n\n"
|
|
||||||
"Wi-Fi Direct connections are "
|
|
||||||
"therefore preferrable under almost all circumstances.\n\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ListP2PChannels(const std::vector<std::string> &arguments)
|
static int ListP2PChannels(const std::vector<std::string> &arguments)
|
||||||
@@ -1315,7 +1284,7 @@ int main(int argc, char **argv)
|
|||||||
bool helpError = false;
|
bool helpError = false;
|
||||||
bool stop = false, start = false;
|
bool stop = false, start = false;
|
||||||
bool enable = false, disable = false, restart = false;
|
bool enable = false, disable = false, restart = false;
|
||||||
bool enable_ap = false, disable_ap = false;
|
bool enable_hotspot = false, disable_hotspot = false;
|
||||||
bool enable_p2p = false, disable_p2p = false;
|
bool enable_p2p = false, disable_p2p = false;
|
||||||
bool list_p2p_channels = false;
|
bool list_p2p_channels = false;
|
||||||
bool get_current_port = false;
|
bool get_current_port = false;
|
||||||
@@ -1324,6 +1293,9 @@ int main(int argc, char **argv)
|
|||||||
bool excludeShutdownService = false;
|
bool excludeShutdownService = false;
|
||||||
std::string prefixOption;
|
std::string prefixOption;
|
||||||
std::string portOption;
|
std::string portOption;
|
||||||
|
std::string homeNetwork;
|
||||||
|
bool noEthernet = false;
|
||||||
|
bool noWifi = false;
|
||||||
|
|
||||||
parser.AddOption("--nosudo", &nosudo); // strictly a debugging aid. Run without sudo, until we fail because of permissions.
|
parser.AddOption("--nosudo", &nosudo); // strictly a debugging aid. Run without sudo, until we fail because of permissions.
|
||||||
parser.AddOption("--install", &install);
|
parser.AddOption("--install", &install);
|
||||||
@@ -1337,22 +1309,17 @@ int main(int argc, char **argv)
|
|||||||
parser.AddOption("--help", &help);
|
parser.AddOption("--help", &help);
|
||||||
parser.AddOption("--prefix", &prefixOption);
|
parser.AddOption("--prefix", &prefixOption);
|
||||||
parser.AddOption("--port", &portOption);
|
parser.AddOption("--port", &portOption);
|
||||||
// parser.AddOption("--enable-legacy-ap", &enable_ap);
|
parser.AddOption("--enable-hotspot", &enable_hotspot);
|
||||||
parser.AddOption("--disable-ap", &disable_ap);
|
parser.AddOption("--disable-hotspot", &disable_hotspot);
|
||||||
parser.AddOption("--enable-p2p", &enable_p2p);
|
parser.AddOption("--home-network",&homeNetwork);
|
||||||
parser.AddOption("--disable-p2p", &disable_p2p);
|
parser.AddOption("--no-ethernet",&noEthernet);
|
||||||
parser.AddOption("--list-p2p-channels", &list_p2p_channels);
|
parser.AddOption("--no-wifi",&noWifi);
|
||||||
parser.AddOption("--fix-permissions", &fix_permissions);
|
|
||||||
|
|
||||||
parser.AddOption("--get-current-port", &get_current_port); // private. For debug use only.
|
|
||||||
|
|
||||||
parser.AddOption("--excludeShutdownService", &excludeShutdownService); // private (unstable) option used by shutdown service.
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
parser.Parse(argc, (const char **)argv);
|
parser.Parse(argc, (const char **)argv);
|
||||||
|
|
||||||
int actionCount =
|
int actionCount =
|
||||||
help + get_current_port + install + uninstall + stop + start + enable + disable + enable_ap + disable_ap + restart + enable_p2p + disable_p2p + list_p2p_channels + fix_permissions;
|
help + get_current_port + install + uninstall + stop + start + enable + disable + enable_hotspot + disable_hotspot + restart + enable_p2p + disable_p2p + list_p2p_channels + fix_permissions;
|
||||||
if (actionCount > 1)
|
if (actionCount > 1)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Please provide only one action.");
|
throw std::runtime_error("Please provide only one action.");
|
||||||
@@ -1366,7 +1333,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
throw std::runtime_error("No action provided.");
|
throw std::runtime_error("No action provided.");
|
||||||
}
|
}
|
||||||
if ((!enable_p2p) && (!enable_ap) && (!list_p2p_channels))
|
if ((!enable_p2p) && (!enable_hotspot) && (!list_p2p_channels))
|
||||||
{
|
{
|
||||||
if (parser.Arguments().size() != 0)
|
if (parser.Arguments().size() != 0)
|
||||||
{
|
{
|
||||||
@@ -1374,6 +1341,23 @@ int main(int argc, char **argv)
|
|||||||
helpError = true;
|
helpError = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int hotspotOptionCount =
|
||||||
|
(homeNetwork.length() != 0 ? 1: 0)
|
||||||
|
+ noEthernet
|
||||||
|
+ noWifi;
|
||||||
|
|
||||||
|
if (enable_hotspot)
|
||||||
|
{
|
||||||
|
if (hotspotOptionCount > 1)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Only one hotspot option at a time can be specified.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (hotspotOptionCount > 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Hotspot options only only valid when the --enable-hotspot option has been supplied.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
@@ -1383,7 +1367,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
if (helpError)
|
if (helpError)
|
||||||
{
|
{
|
||||||
cout << "\n";
|
cout << endl;
|
||||||
return EXIT_FAILURE; // don't scroll the error off the screen.
|
return EXIT_FAILURE; // don't scroll the error off the screen.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1483,21 +1467,23 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
else if (enable_p2p)
|
else if (enable_p2p)
|
||||||
{
|
{
|
||||||
try
|
cout << "ERROR: Wi-Fi p2p connections are no longer supported. Use hotspots instead." << endl;
|
||||||
{
|
return EXIT_FAILURE;
|
||||||
auto argv = parser.Arguments();
|
// try
|
||||||
WifiDirectConfigSettings settings;
|
// {
|
||||||
settings.ParseArguments(argv);
|
// auto argv = parser.Arguments();
|
||||||
settings.valid_ = true;
|
// WifiDirectConfigSettings settings;
|
||||||
settings.enable_ = true;
|
// settings.ParseArguments(argv);
|
||||||
SetWifiDirectConfig(settings);
|
// settings.valid_ = true;
|
||||||
RestartService(true); // also have to retart web service so that it gets the correct device name.
|
// settings.enable_ = true;
|
||||||
}
|
// SetWifiDirectConfig(settings);
|
||||||
catch (const std::exception &e)
|
// RestartService(true); // also have to retart web service so that it gets the correct device name.
|
||||||
{
|
// }
|
||||||
cout << "ERROR: " << e.what() << endl;
|
// catch (const std::exception &e)
|
||||||
return EXIT_FAILURE;
|
// {
|
||||||
}
|
// cout << "ERROR: " << e.what() << endl;
|
||||||
|
// return EXIT_FAILURE;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
else if (disable_p2p)
|
else if (disable_p2p)
|
||||||
{
|
{
|
||||||
@@ -1508,20 +1494,45 @@ int main(int argc, char **argv)
|
|||||||
RestartService(true);
|
RestartService(true);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
else if (enable_ap)
|
else if (enable_hotspot)
|
||||||
{
|
{
|
||||||
auto argv = parser.Arguments();
|
auto argv = parser.Arguments();
|
||||||
WifiConfigSettings settings;
|
WifiConfigSettings settings;
|
||||||
settings.ParseArguments(argv);
|
|
||||||
|
|
||||||
|
HotspotAutoStartMode startMode = HotspotAutoStartMode::Always;
|
||||||
|
if (homeNetwork.length() != 0)
|
||||||
|
{
|
||||||
|
startMode = HotspotAutoStartMode::NotAtHome;
|
||||||
|
} else if (noEthernet)
|
||||||
|
{
|
||||||
|
startMode = HotspotAutoStartMode::NoEthernetConnection;
|
||||||
|
} else if (noWifi)
|
||||||
|
{
|
||||||
|
startMode = HotspotAutoStartMode::NoRememberedWifiConections;
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ParseArguments(argv,startMode,homeNetwork);
|
||||||
|
|
||||||
|
if (settings.hasPassword_)
|
||||||
|
{
|
||||||
|
settings.hasSavedPassword_ = true;
|
||||||
|
}
|
||||||
SetWifiConfig(settings);
|
SetWifiConfig(settings);
|
||||||
|
if (silentSysExec(SYSTEMCTL_BIN " restart " PIPEDALD_SERVICE ".service") != EXIT_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to restart the " PIPEDALD_SERVICE " service.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (disable_ap)
|
else if (disable_hotspot)
|
||||||
{
|
{
|
||||||
WifiConfigSettings settings;
|
WifiConfigSettings settings;
|
||||||
settings.valid_ = true;
|
settings.valid_ = true;
|
||||||
settings.enable_ = false;
|
settings.autoStartMode_ = (uint16_t)HotspotAutoStartMode::Never;
|
||||||
SetWifiConfig(settings);
|
SetWifiConfig(settings);
|
||||||
|
if (silentSysExec(SYSTEMCTL_BIN " restart " PIPEDALD_SERVICE ".service") != EXIT_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to restart the " PIPEDALD_SERVICE " service.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
|
|||||||
+159
-23
@@ -29,6 +29,7 @@
|
|||||||
#include "ServiceConfiguration.hpp"
|
#include "ServiceConfiguration.hpp"
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
using namespace dbus::networkmanager;
|
using namespace dbus::networkmanager;
|
||||||
@@ -51,6 +52,8 @@ namespace pipedal::impl
|
|||||||
virtual void Reload() override;
|
virtual void Reload() override;
|
||||||
virtual void Close() override;
|
virtual void Close() override;
|
||||||
|
|
||||||
|
std::vector<std::string> GetKnownWifiNetworks();
|
||||||
|
|
||||||
virtual PostHandle Post(PostCallback&&fn) override;
|
virtual PostHandle Post(PostCallback&&fn) override;
|
||||||
virtual PostHandle PostDelayed(const clock::duration&delay,PostCallback&&fn) override;
|
virtual PostHandle PostDelayed(const clock::duration&delay,PostCallback&&fn) override;
|
||||||
virtual bool CancelPost(PostHandle handle) override;
|
virtual bool CancelPost(PostHandle handle) override;
|
||||||
@@ -97,8 +100,14 @@ namespace pipedal::impl
|
|||||||
void ReleaseNetworkManager();
|
void ReleaseNetworkManager();
|
||||||
void OnEthernetStateChanged(uint32_t state);
|
void OnEthernetStateChanged(uint32_t state);
|
||||||
void OnWlanStateChanged(uint32_t state);
|
void OnWlanStateChanged(uint32_t state);
|
||||||
std::vector<ssid_t> GetAutoConnectSsids();
|
std::vector<AccessPoint::ptr> GetAllAccessPoints();
|
||||||
std::vector<ssid_t> GetKnownVisibleAccessPoints();
|
std::vector<ssid_t> GetAllAutoConnectSsids();
|
||||||
|
std::vector<ssid_t> GetKnownVisibleAccessPoints(const std::vector<ssid_t> &allAccessPoints);
|
||||||
|
|
||||||
|
void UpdateKnownNetworks(
|
||||||
|
std::vector<ssid_t> &knownSsids,
|
||||||
|
std::vector<AccessPoint::ptr> &allAccessPoints
|
||||||
|
);
|
||||||
|
|
||||||
void FireNetworkChanging();
|
void FireNetworkChanging();
|
||||||
|
|
||||||
@@ -126,9 +135,11 @@ namespace pipedal::impl
|
|||||||
std::recursive_mutex networkChangingListenerMutex;
|
std::recursive_mutex networkChangingListenerMutex;
|
||||||
NetworkChangingListener networkChangingListener;
|
NetworkChangingListener networkChangingListener;
|
||||||
|
|
||||||
|
std::mutex knownWifiNetworksMutex;
|
||||||
|
std::vector<std::string> knownWifiNetworks;
|
||||||
|
|
||||||
bool ethernetConnected = true;
|
bool ethernetConnected = true;
|
||||||
bool wlanConnected = true;
|
bool wlanConnected = true;
|
||||||
bool isAutoWlanConnectionVisible = true;
|
|
||||||
|
|
||||||
DBusEventHandle onDeviceAddedHandle = INVALID_DBUS_EVENT_HANDLE;
|
DBusEventHandle onDeviceAddedHandle = INVALID_DBUS_EVENT_HANDLE;
|
||||||
DBusEventHandle onDeviceRemovedHandle = INVALID_DBUS_EVENT_HANDLE;
|
DBusEventHandle onDeviceRemovedHandle = INVALID_DBUS_EVENT_HANDLE;
|
||||||
@@ -190,7 +201,7 @@ void HotspotManagerImpl::onInitialize()
|
|||||||
{
|
{
|
||||||
wifiConfigSettings.Load();
|
wifiConfigSettings.Load();
|
||||||
|
|
||||||
if (wifiConfigSettings.valid_ && wifiConfigSettings.enable_)
|
if (wifiConfigSettings.valid_ && wifiConfigSettings.IsEnabled())
|
||||||
{
|
{
|
||||||
onStartMonitoring();
|
onStartMonitoring();
|
||||||
}
|
}
|
||||||
@@ -445,7 +456,7 @@ void HotspotManagerImpl::onReload()
|
|||||||
// ignore.
|
// ignore.
|
||||||
return;
|
return;
|
||||||
case State::Disabled:
|
case State::Disabled:
|
||||||
if (wifiConfigSettings.valid_ && wifiConfigSettings.enable_)
|
if (wifiConfigSettings.valid_ && wifiConfigSettings.IsEnabled())
|
||||||
{
|
{
|
||||||
onStartMonitoring();
|
onStartMonitoring();
|
||||||
}
|
}
|
||||||
@@ -487,6 +498,8 @@ void HotspotManagerImpl::Close()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HotspotManager::ptr HotspotManager::Create()
|
HotspotManager::ptr HotspotManager::Create()
|
||||||
{
|
{
|
||||||
return std::make_unique<HotspotManagerImpl>();
|
return std::make_unique<HotspotManagerImpl>();
|
||||||
@@ -508,37 +521,134 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string ssidToString(const std::vector<uint8_t> &ssid)
|
|
||||||
|
struct NetworkSortRecord {
|
||||||
|
std::string ssid;
|
||||||
|
bool connected = false;
|
||||||
|
bool knownNetwork = false;
|
||||||
|
bool visibleNetwork = false;
|
||||||
|
uint8_t strength;
|
||||||
|
};
|
||||||
|
void HotspotManagerImpl::UpdateKnownNetworks(
|
||||||
|
std::vector<ssid_t> &knownSsids,
|
||||||
|
std::vector<AccessPoint::ptr> & allAccessPoints
|
||||||
|
)
|
||||||
{
|
{
|
||||||
std::stringstream s;
|
std::map<std::string,NetworkSortRecord> map;
|
||||||
for (auto v: ssid)
|
|
||||||
|
for (auto &knownSsid: knownSsids)
|
||||||
{
|
{
|
||||||
if (v == 0) break; // breaks for some arguably legal ssids, but I can live with that.
|
std::string ssid = ssidToString(knownSsid);
|
||||||
s << (char)v;
|
if (ssid.length() != 0)
|
||||||
|
{
|
||||||
|
NetworkSortRecord &record = map[ssid];
|
||||||
|
record.ssid = ssid;
|
||||||
|
record.knownNetwork = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return s.str();
|
for (auto&accessPoint: allAccessPoints)
|
||||||
|
{
|
||||||
|
uint8_t strength = accessPoint->Strength();
|
||||||
|
auto vSsid = accessPoint->Ssid();
|
||||||
|
std::string ssid = ssidToString(vSsid);
|
||||||
|
if (ssid.length() != 0)
|
||||||
|
{
|
||||||
|
NetworkSortRecord&record = map[ssid];
|
||||||
|
record.ssid = ssid;
|
||||||
|
record.visibleNetwork = true;
|
||||||
|
record.strength = strength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this->wlanDevice)
|
||||||
|
{
|
||||||
|
auto activeConnectionPath = this->wlanDevice->ActiveConnection();
|
||||||
|
if (activeConnectionPath.length() > 2) // "/" -> no connection. Be paranoid about "".
|
||||||
|
{
|
||||||
|
auto activeConnection = ActiveConnection::Create(dbusDispatcher,activeConnectionPath);
|
||||||
|
std::string activeSsid = activeConnection->Id();
|
||||||
|
auto it = map.find(activeSsid);
|
||||||
|
if (it != map.end())
|
||||||
|
{
|
||||||
|
it->second.connected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<NetworkSortRecord> records;
|
||||||
|
records.reserve(map.size());
|
||||||
|
for (auto & mapEntry: map)
|
||||||
|
{
|
||||||
|
records.push_back(mapEntry.second);
|
||||||
|
}
|
||||||
|
std::sort(records.begin(),records.end(), [](const NetworkSortRecord&left, const NetworkSortRecord &right)
|
||||||
|
{
|
||||||
|
if (left.connected != right.connected)
|
||||||
|
{
|
||||||
|
return left.connected > right.connected;
|
||||||
|
}
|
||||||
|
if (left.knownNetwork != right.knownNetwork)
|
||||||
|
{
|
||||||
|
return left.knownNetwork > right.knownNetwork;
|
||||||
|
}
|
||||||
|
if (left.visibleNetwork != right.visibleNetwork)
|
||||||
|
{
|
||||||
|
return left.visibleNetwork > right.visibleNetwork;
|
||||||
|
}
|
||||||
|
if (left.strength != right.strength)
|
||||||
|
{
|
||||||
|
return left.strength > right.strength;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
if (records.size() > 10)
|
||||||
|
{
|
||||||
|
records.resize(10);
|
||||||
|
}
|
||||||
|
std::vector<std::string> result;
|
||||||
|
result.reserve(records.size());
|
||||||
|
for (auto &record: records)
|
||||||
|
{
|
||||||
|
result.push_back(std::move(record.ssid));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard lock { this->knownWifiNetworksMutex };
|
||||||
|
this->knownWifiNetworks = std::move(result);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::vector<uint8_t>> HotspotManagerImpl::GetKnownVisibleAccessPoints()
|
|
||||||
|
std::vector<AccessPoint::ptr> HotspotManagerImpl::GetAllAccessPoints() {
|
||||||
|
std::vector<AccessPoint::ptr> accessPoints;
|
||||||
|
|
||||||
|
for (const auto &accessPointPath : wlanWirelessDevice->AccessPoints())
|
||||||
|
{
|
||||||
|
auto accessPoint = AccessPoint::Create(dbusDispatcher, accessPointPath);
|
||||||
|
accessPoints.push_back(std::move(accessPoint));
|
||||||
|
}
|
||||||
|
return accessPoints;
|
||||||
|
|
||||||
|
}
|
||||||
|
std::vector<std::vector<uint8_t>> HotspotManagerImpl::GetKnownVisibleAccessPoints(const std::vector<ssid_t>&allAccessPoints)
|
||||||
{
|
{
|
||||||
std::vector<std::vector<uint8_t>> knownSsids = this->GetAutoConnectSsids();
|
std::vector<std::vector<uint8_t>> knownSsids = this->GetAllAutoConnectSsids();
|
||||||
|
|
||||||
std::unordered_set<std::vector<uint8_t>, VectorHash<uint8_t>> index{knownSsids.begin(), knownSsids.end()};
|
std::unordered_set<std::vector<uint8_t>, VectorHash<uint8_t>> index{knownSsids.begin(), knownSsids.end()};
|
||||||
|
|
||||||
std::vector<ssid_t> result;
|
std::vector<ssid_t> result;
|
||||||
for (const auto &accessPointPath : wlanWirelessDevice->AccessPoints())
|
std::vector<AccessPoint::ptr> accessPoints;
|
||||||
|
|
||||||
|
for (const auto &accessPoint : allAccessPoints)
|
||||||
{
|
{
|
||||||
auto accessPoint = AccessPoint::Create(dbusDispatcher, accessPointPath);
|
if (index.contains(accessPoint))
|
||||||
auto ssid = accessPoint->Ssid();
|
|
||||||
if (index.contains(ssid))
|
|
||||||
{
|
{
|
||||||
result.push_back(ssid);
|
result.push_back(accessPoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::vector<uint8_t>> HotspotManagerImpl::GetAutoConnectSsids()
|
std::vector<std::vector<uint8_t>> HotspotManagerImpl::GetAllAutoConnectSsids()
|
||||||
{
|
{
|
||||||
auto availableConnections = wlanDevice->AvailableConnections();
|
auto availableConnections = wlanDevice->AvailableConnections();
|
||||||
std::vector<std::vector<uint8_t>> ssids;
|
std::vector<std::vector<uint8_t>> ssids;
|
||||||
@@ -599,13 +709,31 @@ void HotspotManagerImpl::onAccessPointChanged()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<std::vector<uint8_t>> GetAccessPointSsids(std::vector<AccessPoint::ptr>&accessPoints)
|
||||||
|
{
|
||||||
|
std::vector<std::vector<uint8_t>> result;
|
||||||
|
for (const auto&accessPoint: accessPoints)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
result.push_back(accessPoint->Ssid());
|
||||||
|
} catch (const std::exception&ignored)
|
||||||
|
{
|
||||||
|
// race to get a disappearing ssid. Ignore the error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
void HotspotManagerImpl::MaybeStartHotspot()
|
void HotspotManagerImpl::MaybeStartHotspot()
|
||||||
{
|
{
|
||||||
std::vector<std::vector<uint8_t>> connectableSsids = GetKnownVisibleAccessPoints(); // all the ssids currently visible for which we have credentials.
|
std::vector<AccessPoint::ptr> allAccessPoints = GetAllAccessPoints();
|
||||||
bool wantsHotspot = this->wifiConfigSettings.WantsHotspot(
|
std::vector<std::vector<uint8_t>> allAccessPointSsids = GetAccessPointSsids(allAccessPoints);
|
||||||
this->ethernetConnected,connectableSsids);
|
std::vector<std::vector<uint8_t>> connectableSsids = GetKnownVisibleAccessPoints(allAccessPointSsids); // all the ssids currently visible for which we have credentials.
|
||||||
|
|
||||||
|
this->UpdateKnownNetworks(connectableSsids,allAccessPoints);
|
||||||
|
|
||||||
this->isAutoWlanConnectionVisible = connectableSsids.size() != 0;
|
bool wantsHotspot = this->wifiConfigSettings.WantsHotspot(
|
||||||
|
|
||||||
|
this->ethernetConnected,connectableSsids,allAccessPointSsids);
|
||||||
|
|
||||||
if (this->state == State::Monitoring && wantsHotspot)
|
if (this->state == State::Monitoring && wantsHotspot)
|
||||||
{
|
{
|
||||||
@@ -849,3 +977,11 @@ void HotspotManagerImpl::FireNetworkChanging() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> HotspotManagerImpl::GetKnownWifiNetworks()
|
||||||
|
{
|
||||||
|
std::lock_guard lock(knownWifiNetworksMutex); // pushed off the service thread.
|
||||||
|
return this->knownWifiNetworks;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ namespace pipedal {
|
|||||||
HotspotManager(HotspotManager&&) = delete;
|
HotspotManager(HotspotManager&&) = delete;
|
||||||
HotspotManager & operator=(const HotspotManager&) = delete;
|
HotspotManager & operator=(const HotspotManager&) = delete;
|
||||||
HotspotManager & operator=(const HotspotManager&&) = delete;
|
HotspotManager & operator=(const HotspotManager&&) = delete;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
HotspotManager() {} // use Create().
|
HotspotManager() {} // use Create().
|
||||||
@@ -47,6 +46,9 @@ namespace pipedal {
|
|||||||
virtual void Reload() = 0;
|
virtual void Reload() = 0;
|
||||||
virtual void Close() = 0;
|
virtual void Close() = 0;
|
||||||
|
|
||||||
|
virtual std::vector<std::string> GetKnownWifiNetworks() = 0;
|
||||||
|
|
||||||
|
|
||||||
using NetworkChangingListener = std::function<void(bool ethernetConnected,bool hotspotEnabled)>;
|
using NetworkChangingListener = std::function<void(bool ethernetConnected,bool hotspotEnabled)>;
|
||||||
|
|
||||||
virtual void SetNetworkChangingListener(NetworkChangingListener &&listener) = 0;
|
virtual void SetNetworkChangingListener(NetworkChangingListener &&listener) = 0;
|
||||||
|
|||||||
+16
-1
@@ -91,7 +91,7 @@ PiPedalModel::PiPedalModel()
|
|||||||
OnNetworkChanging(ethernetConnected,hotspotEnabling);
|
OnNetworkChanging(ethernetConnected,hotspotEnabling);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
hotspotManager->Open();
|
// don't actuall start the hotspotManager until after LV2 is initialized (in order to avoid logging oddities)
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::Close()
|
void PiPedalModel::Close()
|
||||||
@@ -2241,6 +2241,11 @@ static bool HasAlsaDevice(const std::vector<AlsaDeviceInfo> devices, const std::
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PiPedalModel::StartHotspotMonitoring()
|
||||||
|
{
|
||||||
|
this->hotspotManager->Open();
|
||||||
|
}
|
||||||
|
|
||||||
void PiPedalModel::WaitForAudioDeviceToComeOnline()
|
void PiPedalModel::WaitForAudioDeviceToComeOnline()
|
||||||
{
|
{
|
||||||
auto serverSettings = this->GetJackServerSettings();
|
auto serverSettings = this->GetJackServerSettings();
|
||||||
@@ -2324,6 +2329,16 @@ void PiPedalModel::CancelNetworkChangingTimer()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::string> PiPedalModel::GetKnownWifiNetworks()
|
||||||
|
{
|
||||||
|
if (!this->hotspotManager)
|
||||||
|
{
|
||||||
|
return std::vector<std::string>();
|
||||||
|
}
|
||||||
|
return this->hotspotManager->GetKnownWifiNetworks();
|
||||||
|
}
|
||||||
|
|
||||||
void PiPedalModel::OnNetworkChanging(bool ethernetConnected,bool hotspotConnected)
|
void PiPedalModel::OnNetworkChanging(bool ethernetConnected,bool hotspotConnected)
|
||||||
{
|
{
|
||||||
CancelNetworkChangingTimer();
|
CancelNetworkChangingTimer();
|
||||||
|
|||||||
@@ -245,6 +245,8 @@ namespace pipedal
|
|||||||
networkChangedListener = listener;
|
networkChangedListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StartHotspotMonitoring();
|
||||||
|
|
||||||
void WaitForAudioDeviceToComeOnline();
|
void WaitForAudioDeviceToComeOnline();
|
||||||
|
|
||||||
UpdateStatus GetUpdateStatus();
|
UpdateStatus GetUpdateStatus();
|
||||||
@@ -333,6 +335,7 @@ namespace pipedal
|
|||||||
|
|
||||||
void SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings);
|
void SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings);
|
||||||
WifiConfigSettings GetWifiConfigSettings();
|
WifiConfigSettings GetWifiConfigSettings();
|
||||||
|
std::vector<std::string> GetKnownWifiNetworks();
|
||||||
|
|
||||||
void SetWifiDirectConfigSettings(const WifiDirectConfigSettings &wifiConfigSettings);
|
void SetWifiDirectConfigSettings(const WifiDirectConfigSettings &wifiConfigSettings);
|
||||||
WifiDirectConfigSettings GetWifiDirectConfigSettings();
|
WifiDirectConfigSettings GetWifiDirectConfigSettings();
|
||||||
|
|||||||
@@ -1025,6 +1025,12 @@ public:
|
|||||||
std::vector<AlsaDeviceInfo> devices = model.GetAlsaDevices();
|
std::vector<AlsaDeviceInfo> devices = model.GetAlsaDevices();
|
||||||
this->Reply(replyTo, "getAlsaDevices", devices);
|
this->Reply(replyTo, "getAlsaDevices", devices);
|
||||||
}
|
}
|
||||||
|
else if (message == "getKnownWifiNetworks")
|
||||||
|
{
|
||||||
|
std::vector<std::string> channels = this->model.GetKnownWifiNetworks();
|
||||||
|
this->Reply(replyTo, "getWifiChannels", channels);
|
||||||
|
|
||||||
|
}
|
||||||
else if (message == "getWifiChannels")
|
else if (message == "getWifiChannels")
|
||||||
{
|
{
|
||||||
std::string country;
|
std::string country;
|
||||||
|
|||||||
+4
-1
@@ -458,7 +458,10 @@ void PluginHost::Load(const char *lv2Path)
|
|||||||
|
|
||||||
for (const std::string &s : messages)
|
for (const std::string &s : messages)
|
||||||
{
|
{
|
||||||
Lv2Log::info("lilv: " + s);
|
if (s.length() != 0)
|
||||||
|
{
|
||||||
|
Lv2Log::info("lilv: " + s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto collator = Locale::GetInstance()->GetCollator();
|
auto collator = Locale::GetInstance()->GetCollator();
|
||||||
|
|||||||
@@ -63,6 +63,11 @@ namespace pipedal
|
|||||||
this->indent = indent;
|
this->indent = indent;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
PrettyPrinter&AddIndent(int64_t indent)
|
||||||
|
{
|
||||||
|
this->indent += indent;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void WriteLine() {
|
void WriteLine() {
|
||||||
lineBuffer.push_back('\n');
|
lineBuffer.push_back('\n');
|
||||||
@@ -246,6 +251,15 @@ namespace pipedal
|
|||||||
return pp;
|
return pp;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
pp_manip AddIndent(int n)
|
||||||
|
{
|
||||||
|
return [n] (PrettyPrinter&pp) ->PrettyPrinter& {
|
||||||
|
pp.AddIndent(n);
|
||||||
|
return pp;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
pp_manip HangingIndent()
|
pp_manip HangingIndent()
|
||||||
{
|
{
|
||||||
return [] (PrettyPrinter&pp) ->PrettyPrinter&{
|
return [] (PrettyPrinter&pp) ->PrettyPrinter&{
|
||||||
|
|||||||
+8
-1
@@ -961,12 +961,19 @@ bool Storage::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings
|
|||||||
{
|
{
|
||||||
copyToSave.hasPassword_ = previousValue.hasPassword_;
|
copyToSave.hasPassword_ = previousValue.hasPassword_;
|
||||||
copyToSave.password_ = previousValue.hasPassword_;
|
copyToSave.password_ = previousValue.hasPassword_;
|
||||||
|
copyToSave.hasSavedPassword_ = previousValue.hasPassword_;
|
||||||
|
} else {
|
||||||
|
if (copyToSave.IsEnabled())
|
||||||
|
{
|
||||||
|
copyToSave.hasSavedPassword_ = copyToSave.hasPassword_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bool configChanged = wifiConfigSettings.ConfigurationChanged(previousValue);
|
bool configChanged = copyToSave.ConfigurationChanged(previousValue);
|
||||||
copyToSave.Save();
|
copyToSave.Save();
|
||||||
this->wifiConfigSettings = copyToSave;
|
this->wifiConfigSettings = copyToSave;
|
||||||
this->wifiConfigSettings.hasPassword_ = false;
|
this->wifiConfigSettings.hasPassword_ = false;
|
||||||
this->wifiConfigSettings.password_ = "";
|
this->wifiConfigSettings.password_ = "";
|
||||||
|
|
||||||
return configChanged;
|
return configChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -41,6 +41,7 @@
|
|||||||
#include "WebServer.hpp"
|
#include "WebServer.hpp"
|
||||||
|
|
||||||
#include "Uri.hpp"
|
#include "Uri.hpp"
|
||||||
|
#include "ss.hpp"
|
||||||
|
|
||||||
#include <websocketpp/config/asio_no_tls.hpp>
|
#include <websocketpp/config/asio_no_tls.hpp>
|
||||||
|
|
||||||
@@ -1194,7 +1195,7 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
catch (websocketpp::exception const &e)
|
catch (websocketpp::exception const &e)
|
||||||
{
|
{
|
||||||
std::cout << e.what() << std::endl;
|
Lv2Log::error(SS("Web server: " << e.what()));
|
||||||
}
|
}
|
||||||
if (this->signalOnDone != -1)
|
if (this->signalOnDone != -1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,19 +29,25 @@ int main(int argc, char**argv)
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
std::string line;
|
std::string line;
|
||||||
std::cout << "e=enable,x=disable,q=quit > " << std::endl;;
|
std::cout << "e=no-etthernet,a=always,n=never,q=quit > " << std::endl;;
|
||||||
std::getline(std::cin,line);
|
std::getline(std::cin,line);
|
||||||
|
|
||||||
if (line == "e")
|
if (line == "e")
|
||||||
{
|
{
|
||||||
settings.Load();
|
settings.Load();
|
||||||
settings.enable_ = true;
|
settings.autoStartMode_ = (uint16_t)HotspotAutoStartMode::NoEthernetConnection;
|
||||||
settings.Save();
|
settings.Save();
|
||||||
hotspotManager->Reload();
|
hotspotManager->Reload();
|
||||||
} else if (line == "x")
|
} else if (line == "a")
|
||||||
{
|
{
|
||||||
settings.Load();
|
settings.Load();
|
||||||
settings.enable_ = false;
|
settings.autoStartMode_ = (uint16_t)HotspotAutoStartMode::Always;
|
||||||
|
settings.Save();
|
||||||
|
hotspotManager->Reload();
|
||||||
|
} else if (line == "n")
|
||||||
|
{
|
||||||
|
settings.Load();
|
||||||
|
settings.autoStartMode_ = (uint16_t)HotspotAutoStartMode::Never;
|
||||||
settings.Save();
|
settings.Save();
|
||||||
hotspotManager->Reload();
|
hotspotManager->Reload();
|
||||||
} else if (line == "q") {
|
} else if (line == "q") {
|
||||||
@@ -53,9 +59,6 @@ int main(int argc, char**argv)
|
|||||||
hotspotManager->Close();
|
hotspotManager->Close();
|
||||||
hotspotManager = nullptr;
|
hotspotManager = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ int main(int argc, char *argv[])
|
|||||||
(unsigned long)getpid());
|
(unsigned long)getpid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model.StartHotspotMonitoring();
|
||||||
model.WaitForAudioDeviceToComeOnline();
|
model.WaitForAudioDeviceToComeOnline();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ Installer:
|
|||||||
sudo systemctl restart polkitd.service
|
sudo systemctl restart polkitd.service
|
||||||
|
|
||||||
|
|
||||||
- Scanning.
|
|
||||||
- verify that scanning doesn't cause overruns.
|
- verify that scanning doesn't cause overruns.
|
||||||
- UI changes.
|
|
||||||
- test behaviour when Osgilliad is offline.
|
- test behaviour when Osgilliad is offline.
|
||||||
- docs changes.
|
- docs changes.
|
||||||
- unicode commandline arguments.
|
- unicode commandline arguments.
|
||||||
|
|||||||
Reference in New Issue
Block a user