Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Change FS from SPIFFS to LittleFS #684

Draft
wants to merge 7 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions scripts/ota_updater/ota_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import base64, sys, math
from hashlib import md5

# Global variable for total bytes to transfer
total = 0

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
if rc != 0:
Expand All @@ -19,31 +22,47 @@ def on_connect(client, userdata, flags, rc):

print("Waiting for device to come online...")

# Called from on_message to print a progress bar
def on_progress(progress, total):
g_total = total
bar_width = 30
bar = int(bar_width*(progress/total))
print("\r[", '+'*bar, ' '*(bar_width-bar), "] ", progress, "/", total, end='', sep='')
if (progress == total):
print()
sys.stdout.flush()

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
global total
# decode string for python2/3 compatiblity
msg.payload = msg.payload.decode()

if msg.topic.endswith('$implementation/ota/status'):
status = int(msg.payload.split()[0])

if userdata.get("published"):
if status == 206: # in progress
if status == 200:
on_progress(total, total)
print("Firmware uploaded successfully. Waiting for device to come back online.")
sys.stdout.flush()
elif status == 202:
print("Checksum accepted")
elif status == 206: # in progress
# state in progress, print progress bar
progress, total = [int(x) for x in msg.payload.split()[1].split('/')]
bar_width = 30
bar = int(bar_width*(progress/total))
print("\r[", '+'*bar, ' '*(bar_width-bar), "] ", msg.payload.split()[1], end='', sep='')
if (progress == total):
print()
sys.stdout.flush()
on_progress(progress, total)
elif status == 304: # not modified
print("Device firmware already up to date with md5 checksum: {}".format(userdata.get('md5')))
client.disconnect()
elif status == 403: # forbidden
print("Device ota disabled, aborting...")
client.disconnect()
elif (status > 300) and (status < 500):
print("Other error '" + msg.payload + "', aborting...")
client.disconnect()
else:
print("Other error '" + msg.payload + "'")

elif msg.topic.endswith('$fw/checksum'):
checksum = msg.payload
Expand Down Expand Up @@ -127,6 +146,8 @@ def main(broker_host, broker_port, broker_username, broker_password, broker_ca_c
if __name__ == '__main__':
import argparse

print (sys.argv[1:])

parser = argparse.ArgumentParser(
description='ota firmware update scirpt for ESP8226 implemenation of the Homie mqtt IoT convention.')

Expand Down
6 changes: 3 additions & 3 deletions src/Homie/Boot/BootConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,15 +285,15 @@ void BootConfig::_onCaptivePortal(AsyncWebServerRequest *request) {
Interface::get().getLogger() << F("Proxy") << endl;
_proxyHttpRequest(request);
}
} else if (request->url() == "/" && !SPIFFS.exists(CONFIG_UI_BUNDLE_PATH)) {
} else if (request->url() == "/" && !LittleFS.exists(CONFIG_UI_BUNDLE_PATH)) {
// UI File not found
String msg = String(F("UI bundle not loaded. See Configuration API usage: http://homieiot.github.io/homie-esp8266"));
Interface::get().getLogger() << msg << endl;
request->send(404, F("text/plain"), msg);
} else if (request->url() == "/" && SPIFFS.exists(CONFIG_UI_BUNDLE_PATH)) {
} else if (request->url() == "/" && LittleFS.exists(CONFIG_UI_BUNDLE_PATH)) {
// Respond with UI
Interface::get().getLogger() << F("UI bundle found") << endl;
AsyncWebServerResponse *response = request->beginResponse(SPIFFS.open(CONFIG_UI_BUNDLE_PATH, "r"), F("index.html"), F("text/html"));
AsyncWebServerResponse *response = request->beginResponse(LittleFS.open(CONFIG_UI_BUNDLE_PATH, "r"), F("index.html"), F("text/html"));
request->send(response);
} else {
// Faild to find request
Expand Down
2 changes: 1 addition & 1 deletion src/Homie/Boot/BootConfig.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "Arduino.h"
#include <LittleFS.h>

#include "../Constants.hpp"
#if HOMIE_CONFIG
Expand All @@ -10,7 +11,6 @@
#include <WiFi.h>
#include <HTTPClient.h>
#include <AsyncTCP.h>
#include <SPIFFS.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
Expand Down
18 changes: 12 additions & 6 deletions src/Homie/Boot/BootNormal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ void BootNormal::loop() {
}

for (HomieNode* iNode : HomieNode::nodes) {
if (iNode->runLoopDisconnected || (Interface::get().getMqttClient().connected()) && _mqttConnectNotified ) iNode->loop();
if (iNode->runLoopDisconnected || (Interface::get().getMqttClient().connected() && _mqttConnectNotified) ) iNode->loop();
}
if (_mqttReconnectTimer.check()) {
_mqttConnect();
Expand Down Expand Up @@ -385,16 +385,22 @@ void BootNormal::_onWifiDisconnected(const WiFiEventStationModeDisconnected& eve
Interface::get().event.wifiReason = event.reason;
Interface::get().eventHandler(Interface::get().event);

_wifiConnect();
// _wifiConnect();
}
#endif // ESP32

void BootNormal::_mqttConnect() {
if (!Interface::get().disable) {
if (Interface::get().led.enabled) Interface::get().getBlinker().start(LED_MQTT_DELAY);
_mqttConnectNotified = false;
Interface::get().getLogger() << F("↕ Attempting to connect to MQTT...") << endl;
Interface::get().getMqttClient().connect();
bool fence=!Interface::get().disable;;
#if defined(ESP8266)
fence &= WiFi.isConnected();
#endif // ESP32
if (fence) {
if (Interface::get().led.enabled) Interface::get().getBlinker().start(LED_MQTT_DELAY);
_mqttConnectNotified = false;
Interface::get().getLogger() << F("↕ Attempting to connect to MQTT...") << endl;
Interface::get().getMqttClient().connect();
}
}
}

Expand Down
52 changes: 26 additions & 26 deletions src/Homie/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,34 @@ using namespace HomieInternals;

Config::Config()
: _configStruct()
, _spiffsBegan(false)
, _littlefsBegan(false)
, _valid(false) {
}

bool Config::_spiffsBegin() {
if (!_spiffsBegan) {
bool Config::_littlefsBegin() {
if (!_littlefsBegan) {
#ifdef ESP32
_spiffsBegan = SPIFFS.begin(true);
_littlefsBegan = LittleFS.begin(true);
#elif defined(ESP8266)
_spiffsBegan = SPIFFS.begin();
_littlefsBegan = LittleFS.begin();
#endif
if (!_spiffsBegan) Interface::get().getLogger() << F("✖ Cannot mount filesystem") << endl;
if (!_littlefsBegan) Interface::get().getLogger() << F("✖ Cannot mount filesystem") << endl;
}

return _spiffsBegan;
return _littlefsBegan;
}

bool Config::load() {
if (!_spiffsBegin()) { return false; }
if (!_littlefsBegin()) { return false; }

_valid = false;

if (!SPIFFS.exists(CONFIG_FILE_PATH)) {
if (!LittleFS.exists(CONFIG_FILE_PATH)) {
Interface::get().getLogger() << F("✖ ") << CONFIG_FILE_PATH << F(" doesn't exist") << endl;
return false;
}

File configFile = SPIFFS.open(CONFIG_FILE_PATH, "r");
File configFile = LittleFS.open(CONFIG_FILE_PATH, "r");
if (!configFile) {
Interface::get().getLogger() << F("✖ Cannot open config file") << endl;
return false;
Expand Down Expand Up @@ -85,11 +85,11 @@ bool Config::load() {
const char* reqWifiDns2 = reqWifi["dns2"] | "";

uint16_t reqMqttPort = reqMqtt["port"] | DEFAULT_MQTT_PORT;
bool reqMqttSsl = reqMqtt["ssl"] | false;
// bool reqMqttSsl = reqMqtt["ssl"] | false;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This would break MQTT over SSL for me.
As this PR contains a mixture of multiple things:

  • ota_updater changes
  • LittleFS support
  • broken SSL support
  • changes on WiFi connect behaviour
    we should split this up into multiple smaller PRs covering each a single topic. I will take care about a compiler flags driven switch between SPIFFS and LittleFS.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thank you, for the review. Maybe the ota_updater changes are caused by merging my changes back into his fork?
I also started working on the LittleFS change but stopped when it came to the async web server, since it doesn't support LittleFS. IMO LittleFS can right now only be supported with HOMIE_CONFIG=0. When the web server is used, we should default to SPIFFS.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I did not have a look at the commits and commit history but I think, we should try to keep Git history a little bit clean. For me code changes are already hard to follow.
Maybe I can make compile fail if LittleFS is selected without disabling the web server.

Copy link
Collaborator

Choose a reason for hiding this comment

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

It's better with a clean start. If you give it a go using this PR as inspiration, we can close this one in a few days.
Failing the compilation should be easy with a set of nested #if(n)defs

bool reqMqttAuth = reqMqtt["auth"] | false;
const char* reqMqttUsername = reqMqtt["username"] | "";
const char* reqMqttPassword = reqMqtt["password"] | "";
const char* reqMqttFingerprint = reqMqtt["ssl_fingerprint"] | "";
// const char* reqMqttFingerprint = reqMqtt["ssl_fingerprint"] | "";
const char* reqMqttBaseTopic = reqMqtt["base_topic"] | DEFAULT_MQTT_BASE_TOPIC;

strlcpy(_configStruct.name, reqName, MAX_FRIENDLY_NAME_LENGTH);
Expand Down Expand Up @@ -148,7 +148,7 @@ bool Config::load() {
}

char* Config::getSafeConfigFile() const {
File configFile = SPIFFS.open(CONFIG_FILE_PATH, "r");
File configFile = LittleFS.open(CONFIG_FILE_PATH, "r");
size_t configSize = configFile.size();

char buf[MAX_JSON_CONFIG_FILE_SIZE];
Expand All @@ -170,19 +170,19 @@ char* Config::getSafeConfigFile() const {
}

void Config::erase() {
if (!_spiffsBegin()) { return; }
if (!_littlefsBegin()) { return; }

SPIFFS.remove(CONFIG_FILE_PATH);
SPIFFS.remove(CONFIG_NEXT_BOOT_MODE_FILE_PATH);
LittleFS.remove(CONFIG_FILE_PATH);
LittleFS.remove(CONFIG_NEXT_BOOT_MODE_FILE_PATH);
}

void Config::setHomieBootModeOnNextBoot(HomieBootMode bootMode) {
if (!_spiffsBegin()) { return; }
if (!_littlefsBegin()) { return; }

if (bootMode == HomieBootMode::UNDEFINED) {
SPIFFS.remove(CONFIG_NEXT_BOOT_MODE_FILE_PATH);
LittleFS.remove(CONFIG_NEXT_BOOT_MODE_FILE_PATH);
} else {
File bootModeFile = SPIFFS.open(CONFIG_NEXT_BOOT_MODE_FILE_PATH, "w");
File bootModeFile = LittleFS.open(CONFIG_NEXT_BOOT_MODE_FILE_PATH, "w");
if (!bootModeFile) {
Interface::get().getLogger() << F("✖ Cannot open NEXTMODE file") << endl;
return;
Expand All @@ -195,9 +195,9 @@ void Config::setHomieBootModeOnNextBoot(HomieBootMode bootMode) {
}

HomieBootMode Config::getHomieBootModeOnNextBoot() {
if (!_spiffsBegin()) { return HomieBootMode::UNDEFINED; }
if (!_littlefsBegin()) { return HomieBootMode::UNDEFINED; }

File bootModeFile = SPIFFS.open(CONFIG_NEXT_BOOT_MODE_FILE_PATH, "r");
File bootModeFile = LittleFS.open(CONFIG_NEXT_BOOT_MODE_FILE_PATH, "r");
if (bootModeFile) {
int v = bootModeFile.parseInt();
bootModeFile.close();
Expand All @@ -208,11 +208,11 @@ HomieBootMode Config::getHomieBootModeOnNextBoot() {
}

void Config::write(const JsonObject config) {
if (!_spiffsBegin()) { return; }
if (!_littlefsBegin()) { return; }

SPIFFS.remove(CONFIG_FILE_PATH);
LittleFS.remove(CONFIG_FILE_PATH);

File configFile = SPIFFS.open(CONFIG_FILE_PATH, "w");
File configFile = LittleFS.open(CONFIG_FILE_PATH, "w");
if (!configFile) {
Interface::get().getLogger() << F("✖ Cannot open config file") << endl;
return;
Expand All @@ -222,7 +222,7 @@ void Config::write(const JsonObject config) {
}

bool Config::patch(const char* patch) {
if (!_spiffsBegin()) { return false; }
if (!_littlefsBegin()) { return false; }

StaticJsonDocument<MAX_JSON_CONFIG_ARDUINOJSON_BUFFER_SIZE> patchJsonDoc;

Expand All @@ -232,7 +232,7 @@ bool Config::patch(const char* patch) {
}

JsonObject patchObject = patchJsonDoc.as<JsonObject>();
File configFile = SPIFFS.open(CONFIG_FILE_PATH, "r");
File configFile = LittleFS.open(CONFIG_FILE_PATH, "r");
if (!configFile) {
Interface::get().getLogger() << F("✖ Cannot open config file") << endl;
return false;
Expand Down
9 changes: 3 additions & 6 deletions src/Homie/Config.hpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
#pragma once

#include "Arduino.h"

#include <LittleFS.h>
#include <ArduinoJson.h>
#ifdef ESP32
#include <SPIFFS.h>
#endif // ESP32
#include "FS.h"
#include "Datatypes/Interface.hpp"
#include "Datatypes/ConfigStruct.hpp"
Expand Down Expand Up @@ -34,10 +31,10 @@ class Config {

private:
ConfigStruct _configStruct;
bool _spiffsBegan;
bool _littlefsBegan;
bool _valid;

bool _spiffsBegin();
bool _littlefsBegin();
void _patchJsonObject(JsonObject object, JsonObject patch);
};

Expand Down