Skip to content

Commit

Permalink
minor: web interface secured, unused OTA removed
Browse files Browse the repository at this point in the history
Merge pull request #3 from JuergenLeber/develop
  • Loading branch information
JuergenLeber authored Nov 24, 2024
2 parents 3f4ab93 + 2282061 commit 4c00948
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 80 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
Import("env")

# determine the latest releasev semver
latest_release_tag = subprocess.run(["git", "describe", "--tags"], stdout=subprocess.PIPE, text=True)
latest_release_tag = subprocess.run(["git", "tag", "-l", "--sort=-committerdate"], stdout=subprocess.PIPE, text=True)
latest_release_tag = latest_release_tag.stdout.strip()
print ("\033[93;1;4mLatest Release Tag : " + latest_release_tag + "\033[0m")

Expand All @@ -19,6 +19,12 @@
latest_release_main = latest_release_digits[0]
latest_release_minor = latest_release_digits[1]
latest_release_patch = latest_release_digits[2]

# increase patch for local development build
latest_release_patch = str(int(latest_release_patch) + 1)
latest_release_semver = latest_release_main + "." + latest_release_minor + "." + latest_release_patch
latest_release_semver_incl_v = "v" + latest_release_semver

print ("\033[93;1;4mLatest Release Main : " + latest_release_main + "\033[0m")
print ("\033[93;1;4mLatest Release Minor : " + latest_release_minor + "\033[0m")
print ("\033[93;1;4mLatest Release Patch : " + latest_release_patch + "\033[0m")
Expand Down
6 changes: 1 addition & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
echo "fulltag = [$fulltag]"
declare versiontag=$(echo $fulltag | cut -d'-' -f1)
echo "extract SemVer numbers from version tag [$versiontag]"
declare -i lastmajordigit=$(echo $versiontag | cut -c 1- | cut -d'.' -f1)
declare -i lastmajordigit=$(echo $versiontag | cut -c 2- | cut -d'.' -f1)
echo "lastmajordigit = $lastmajordigit"
declare -i lastminordigit=$(echo $versiontag | cut -c 1- | cut -d'.' -f2)
echo "lastminordigit = $lastminordigit"
Expand Down Expand Up @@ -169,10 +169,6 @@ jobs:
- name: Install PlatformIO Core
run: pip install --upgrade platformio

- name: Setup OTA settings file
run: |
cp ota.ini.example ota.ini
- name: Build
run: |
pio run -e wt32-eth01
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ As the Zwift Cog has 14 teeth and a standard chainring 34 teeth the default rati

Based on this ratio and the selected ratio from Zwift (e.g. 1.23 ~ "Gear 5") the ratio that will later be applied to the trainer's force will be calculated:


$R_{relative} = R_{selected} / R_{standard}$

Example:
Expand Down Expand Up @@ -115,11 +116,12 @@ This new grade value is then sent to the trainer in the track resistance mode an

The "Target Power" mode uses a different approach. Here we want to set an expected watts value depending on the current track and speed. To calculate the speed we assume a default wheel diameter $d$ of 0.7m and take the current cadence $c$ from the trainer that is being multiplied with the wanted gear ratio. The product is then being multiplied with the calculated perimeter of the wheel:

$V_{gs} = (c · R_{selected}) · (d * \pi)$

$V_{gs} = (c · R_{selected}) · (d · \pi)$

This speed is then taken to calculate the geared total force [as described above](#calculate-total-geared-force) which is then being used to calculate the needed power $P$:

$P = F_{totalGeared} * V_{gs}$
$P = F_{totalGeared} · V_{gs}$

This value is then being sent to the trainer in the target power mode as in ERG mode but of course is updated on every parameter change.

Expand Down Expand Up @@ -150,13 +152,13 @@ This value is then being sent to the trainer in the target power mode as in ERG
To start the WT32-ETH01 in boot mode it is necessary to connect "IO0" with GND and then to reset the board, shortly connect "EN" to GND for a quarter of a second.

## Software installation
- Make a copy of the provided ``ota.ini.example`` file and name it ``ota.ini`` (you can adjust the values in the file to your needs but also leave it as it is). This is because the credentials shouldn't be committed to GitHub and so they are stored in a separate file that is on the .gitignore list.
- Open the project in [PlatformIO](https://platformio.org) and let it install the dependencies
- Connect the programmer and upload via the task wt32-eth01 -> Upload and Monitor
- Connect an ethernet cable and make sure a DHCP server exists in your network
- After a few seconds you should be able to see the IP address and the hostname (like e.g. "SHIFTR-123456.local") in the monitor log
- If you don't use the Ethernet interface you can also use the WiFi functionality. For that the device opens an AP with the device name (e.g. "SHIFTR 123456") and the password is the same but with "-" instead of space. Please note that WiFi is provided by an external library called [IoTWebConf](https://github.com/prampec/IotWebConf) and more or less untested
- If you don't use the Ethernet interface you can also use the WiFi functionality. For that the device opens an AP with the device name (e.g. "SHIFTR-123456") and the password is the same but of course can be changed later. Please note that WiFi is provided by an external library called [IoTWebConf](https://github.com/prampec/IotWebConf) and is more or less untested
- After that you can configure the device and its network settings in the web interface on e.g. http://SHIFTR-123456.local
- The status page is accessible without credentials, the settings and firmware update pages need the username "admin" and the password is the configured AP password or just the device name (e.g. "SHIFTR-123456") as default. Note that both are case sensitive!
- Further updates can be made over ethernet or WiFi so you can disconnect the programming adapter now

## Finalization
Expand Down
2 changes: 2 additions & 0 deletions include/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#define ST(A) #A
#define STR(A) ST(A)

#define DEFAULT_USERNAME "admin"

#define DEVICE_NAME_PREFIX "SHIFTR"

#define WEB_SERVER_PORT 80
Expand Down
5 changes: 4 additions & 1 deletion include/SettingsManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ typedef enum VirtualShiftingMode {

class SettingsManager {
public:
static void initialize();
static void initialize(IotWebConf* iotWebConf);
static uint16_t getChainringTeeth();
static uint16_t getSprocketTeeth();
static void setChainringTeeth(uint16_t chainringTeeth);
Expand All @@ -35,6 +35,8 @@ class SettingsManager {
static std::string getTrainerDeviceName();
static void setTrainerDeviceName(std::string trainerDevice);
static IotWebConfParameterGroup* getIoTWebConfSettingsParameterGroup();
static std::string getUsername();
static std::string getAPPassword();

private:
static char iotWebConfChainringTeethParameterValue[];
Expand All @@ -50,6 +52,7 @@ class SettingsManager {
static IotWebConfSelectParameter iotWebConfVirtualShiftingModeParameter;
static IotWebConfCheckboxParameter iotWebConfVirtualShiftingParameter;
static IotWebConfTextParameter iotWebConfTrainerDeviceParameter;
static IotWebConf* iotWebConf;
};

#endif
10 changes: 5 additions & 5 deletions include/Version.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

#ifndef VERSION_H
#define VERSION_H
#define VERSION "v0.0.0"
#define VERSION_MAJOR 0
#define VERSION "v1.0.1"
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_PATCH 0
#define VERSION_BUILD "0000000"
#define VERSION_TIMESTAMP "2024-Nov-18 19:00:00"
#define VERSION_PATCH 1
#define VERSION_BUILD "cdc7c8a"
#define VERSION_TIMESTAMP "2024-Nov-24 23:07:28"
#endif
6 changes: 0 additions & 6 deletions ota.ini.example

This file was deleted.

12 changes: 0 additions & 12 deletions platformio.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
[platformio]
extra_configs = ota.ini

[env:wt32-eth01]
platform = espressif32
board = wt32-eth01
Expand All @@ -14,8 +11,6 @@ lib_deps =
prampec/IotWebConf @ ^3.2.1
build_flags =
-DSERIAL_DEBUG_BAUDRATE=${env:wt32-eth01.monitor_speed}
-DOTA_USERNAME=${ota.username}
-DOTA_PASSWORD=${ota.password}
-DCORE_DEBUG_LEVEL=3
board_build.embed_files =
src-web/index.html
Expand All @@ -26,10 +21,3 @@ board_build.embed_files =
[env:wt32-eth01_local]
extends = env:wt32-eth01
extra_scripts = pre:.github/workflows/build.py

[env:wt32-eth01_ota]
extends = env:wt32-eth01
upload_protocol = espota
upload_port = ${ota.upload_port}
upload_flags = --auth=${ota.password}

22 changes: 20 additions & 2 deletions src/SettingsManager.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include <SettingsManager.h>
#include <Utils.h>
#include <Config.h>

char SettingsManager::iotWebConfChainringTeethParameterValue[16];
char SettingsManager::iotWebConfSprocketTeethParameterValue[16];
Expand All @@ -16,7 +18,10 @@ IotWebConfSelectParameter SettingsManager::iotWebConfVirtualShiftingModeParamete
IotWebConfCheckboxParameter SettingsManager::iotWebConfVirtualShiftingParameter = IotWebConfCheckboxParameter("Virtual shifting", "virtual_shifting", SettingsManager::iotWebConfVirtualShiftingParameterValue, sizeof(iotWebConfVirtualShiftingParameterValue), true);
IotWebConfTextParameter SettingsManager::iotWebConfTrainerDeviceParameter = IotWebConfTextParameter("Trainer device", "trainer_device", iotWebConfTrainerDeviceParameterValue, sizeof(iotWebConfTrainerDeviceParameterValue), "");

void SettingsManager::initialize() {
IotWebConf* SettingsManager::iotWebConf;

void SettingsManager::initialize(IotWebConf* iotWebConf) {
SettingsManager::iotWebConf = iotWebConf;
iotWebConfSettingsGroup.addItem(&iotWebConfTrainerDeviceParameter);
iotWebConfSettingsGroup.addItem(&iotWebConfVirtualShiftingParameter);
iotWebConfSettingsGroup.addItem(&iotWebConfChainringTeethParameter);
Expand Down Expand Up @@ -97,4 +102,17 @@ void SettingsManager::setTrainerDeviceName(std::string trainerDevice) {

IotWebConfParameterGroup* SettingsManager::getIoTWebConfSettingsParameterGroup() {
return &iotWebConfSettingsGroup;
}
}

std::string SettingsManager::getUsername() {
return std::string(DEFAULT_USERNAME);
}

std::string SettingsManager::getAPPassword() {
iotwebconf::Parameter* aPPasswordParameter = iotWebConf->getApPasswordParameter();
std::string aPPassword = std::string(aPPasswordParameter->valueBuffer);
if (aPPassword.length() == 0) {
aPPassword = Utils::getHostName().c_str();
}
return aPPassword;
}
76 changes: 32 additions & 44 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include <Arduino.h>
#include <ArduinoOTA.h>
#include <AsyncTCP.h>
#include <BTDeviceManager.h>
#include <Config.h>
Expand Down Expand Up @@ -27,12 +26,11 @@ bool isMDNSStarted = false;
bool isBLEConnected = false;
bool isEthernetConnected = false;
bool isWiFiConnected = false;
bool isOTAInProgress = false;

DNSServer dnsServer;
WebServer webServer(WEB_SERVER_PORT);
HTTPUpdateServer updateServer;
IotWebConf iotWebConf(Utils::getDeviceName().c_str(), &dnsServer, &webServer, Utils::getHostName().c_str(), WIFI_CONFIG_VERSION);
IotWebConf iotWebConf(Utils::getHostName().c_str(), &dnsServer, &webServer, Utils::getHostName().c_str(), WIFI_CONFIG_VERSION);

ServiceManager serviceManager;

Expand All @@ -49,29 +47,6 @@ void setup() {
}
log_i("Bluetooth device manager initialized");

// initialize OTA
ArduinoOTA.onStart([]() {
log_i("OTA started");
isOTAInProgress = true;
});
ArduinoOTA.onEnd([]() {
log_i("OTA finished, rebooting...");
delay(1000);
ESP.restart();
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
log_i("OTA progress: %u%%", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
log_e("OTA error: %u, rebooting...", error);
delay(1000);
ESP.restart();
});
ArduinoOTA.setHostname(Utils::getHostName().c_str());
ArduinoOTA.setMdnsEnabled(false);
ArduinoOTA.setPassword(STR(OTA_PASSWORD));
log_i("OTA initialized");

// initialize network events
WiFi.onEvent(networkEvent);
log_i("Network events initialized");
Expand All @@ -81,25 +56,46 @@ void setup() {
log_i("Ethernet interface initialized");

// initialize settings manager
SettingsManager::initialize();
SettingsManager::initialize(&iotWebConf);

// initialize wifi manager and web server
iotWebConf.setStatusPin(WIFI_STATUS_PIN);
iotWebConf.setConfigPin(WIFI_CONFIG_PIN);
iotWebConf.addParameterGroup(SettingsManager::getIoTWebConfSettingsParameterGroup());
iotWebConf.setupUpdateServer(
[](const char* updatePath) { updateServer.setup(&webServer, updatePath); },
[](const char* userName, char* password) { updateServer.updateCredentials(STR(OTA_USERNAME), STR(OTA_PASSWORD)); });
[](const char* updatePath) { updateServer.setup(&webServer, updatePath, SettingsManager::getUsername().c_str(), SettingsManager::getAPPassword().c_str()); },
[](const char* userName, char* password) { updateServer.updateCredentials(userName, password); });
iotWebConf.init();

// workaround for missing thing name
strncpy(iotWebConf.getThingNameParameter()->valueBuffer, Utils::getHostName().c_str(), iotWebConf.getThingNameParameter()->getLength());

webServer.on("/debug", handleWebServerDebug);
webServer.on("/status", handleWebServerStatus);
webServer.on("/favicon.ico", [] { handleWebServerFile("favicon.ico"); });
webServer.on("/style.css", [] { handleWebServerFile("style.css"); });
webServer.on("/", [] { handleWebServerFile("index.html"); });
webServer.on("/settings", HTTP_GET, [] { handleWebServerFile("settings.html"); });
webServer.on("/settings", HTTP_POST, [] { handleWebServerSettingsPost(); });
webServer.on("/devicesettings", [] { handleWebServerSettings(); });
webServer.on("/config", [] { iotWebConf.handleConfig(); });
webServer.on("/settings", HTTP_GET, [] {
if (!webServer.authenticate(SettingsManager::getUsername().c_str(), SettingsManager::getAPPassword().c_str())) {
return webServer.requestAuthentication();
}
handleWebServerFile("settings.html"); });
webServer.on("/settings", HTTP_POST, [] {
if (!webServer.authenticate(SettingsManager::getUsername().c_str(), SettingsManager::getAPPassword().c_str())) {
return webServer.requestAuthentication();
}
handleWebServerSettingsPost(); });
webServer.on("/devicesettings", [] {
if (!webServer.authenticate(SettingsManager::getUsername().c_str(), SettingsManager::getAPPassword().c_str())) {
return webServer.requestAuthentication();
}
handleWebServerSettings(); });
webServer.on("/config", [] {
if (!webServer.authenticate(SettingsManager::getUsername().c_str(), SettingsManager::getAPPassword().c_str())) {
return webServer.requestAuthentication();
}
iotWebConf.handleConfig(); });

webServer.onNotFound([]() { iotWebConf.handleNotFound(); });
log_i("WiFi manager and web server initialized");

Expand Down Expand Up @@ -137,13 +133,9 @@ void setup() {
}

void loop() {
if (!isOTAInProgress) {
BTDeviceManager::update();
DirConManager::update();
iotWebConf.doLoop();
} else {
ArduinoOTA.handle();
}
BTDeviceManager::update();
DirConManager::update();
iotWebConf.doLoop();
}

void networkEvent(WiFiEvent_t event) {
Expand All @@ -158,8 +150,6 @@ void networkEvent(WiFiEvent_t event) {
case ARDUINO_EVENT_ETH_GOT_IP:
log_i("Ethernet DHCP successful with IP %u.%u.%u.%u", ETH.localIP()[0], ETH.localIP()[1], ETH.localIP()[2], ETH.localIP()[3]);
isEthernetConnected = true;
ArduinoOTA.end();
ArduinoOTA.begin();
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
log_i("Ethernet disconnected");
Expand All @@ -172,8 +162,6 @@ void networkEvent(WiFiEvent_t event) {
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
log_i("WiFi DHCP successful with IP %u.%u.%u.%u", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]);
isWiFiConnected = true;
ArduinoOTA.end();
ArduinoOTA.begin();
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
log_i("WiFi disconnected");
Expand Down

0 comments on commit 4c00948

Please sign in to comment.