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

[Cleanup] Reduce build size + clean up loose ends #3655

Merged
merged 33 commits into from
May 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
100d588
[Cleanup] Fix warnings of some uninitialised variables.
TD-er May 21, 2021
8d006a8
[Docs] Document %iswifi% system environment variable
TD-er May 22, 2021
d320092
[Domoticz MQTT] Move JSON serialize/deserialize to helper .h/.cpp
TD-er May 22, 2021
535e81c
[Cleanup] Reduce build size handle internal commands macros
TD-er May 22, 2021
0047e49
[GPIO] Split duplicate code into shared function to reduce build size
TD-er May 22, 2021
8b29429
[Rules] Remove unused parameter & change event parameter to const
TD-er May 22, 2021
ac5d0b9
[WiFi] Remove unneeded log connection status
TD-er May 22, 2021
d21721d
[Cleanup] Remove code duplication to reduce build size
TD-er May 22, 2021
113ec46
[Cleanup] Stream JSON from PROGMEM LabelType::Enum array to reduce size
TD-er May 22, 2021
5ee2e33
[Cleanup] Do not include DNS server in minimal OTA builds to reduce size
TD-er May 22, 2021
92768a3
[Cleanup] Reduce build size by keeping flash strings as flash string
TD-er May 24, 2021
a5fab90
[Cleanup] Optimise streaming JSON
TD-er May 24, 2021
3965abc
[Cleanup] Add FlashStringHelper function wrappers to reduce build size
TD-er May 24, 2021
dcaf9f3
[Cleanup] Add missing F() macro where applicable
TD-er May 24, 2021
9c363dc
[Serial log] Small optimization to reduce build size + process logs
TD-er May 24, 2021
54bf060
[Cleanup] Add small optimisations to reduce build size
TD-er May 24, 2021
99f72cc
[Cleanup] Change return type of static get string functions to flash …
TD-er May 25, 2021
62424b6
[Cleanup] Reduce build size of parseStandardConversions function
TD-er May 25, 2021
be3e503
[Cleanup] Reduce build size using flash strings in selectors
TD-er May 25, 2021
ba3e473
[Cleanup] Fix build error due to missing change in commit.
TD-er May 25, 2021
3074df6
[Cleanup] Change return type of some commands to FlashString
TD-er May 25, 2021
b56a919
[Cleanup] Remove unneeded String() wrappers
TD-er May 25, 2021
8dfc246
[Cleanup] Remove "new rules" from any build
TD-er May 25, 2021
1f40cd1
[Cleanup] Domoticz MQTT, generate own JSON, not using ArduinoJSON lib
TD-er May 25, 2021
cd35a3e
[Cleanup] Serialize JSON not using ArduinoJSON to reduce build size
TD-er May 25, 2021
e3f65c1
[Cleanup] Use EMPTY_STRING instead of F("") to reduce build size
TD-er May 25, 2021
3d8a505
[Cleanup] Reduce build size for Factory Default device name
TD-er May 25, 2021
79a3271
[Cleanup] Fix build issue on Serial Proxy
TD-er May 25, 2021
e739486
[Cleanup] Add more functions with flash string as parameter to reduce…
TD-er May 25, 2021
1c7cd15
[Cleanup] Add wrapper to web_server.arg() with flash string arg
TD-er May 26, 2021
2dcdcc7
[Cleanup] Remove addLog macro and use separate functions per type
TD-er May 26, 2021
0140419
Fix new introduced bug in htmlEscape function
TD-er May 26, 2021
bfbabf7
[DeviceModel] Change to enum class to allow compiler help check usage
TD-er May 26, 2021
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
17 changes: 17 additions & 0 deletions docs/source/Reference/SystemVariable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,15 @@ More uses of these system variables can be seen in the rules section and formula
- 11
- WiFi channel of current AP.
- Yes
* - ``%iswifi%``
- 7
- Bitset of WiFi connection state

* ``0`` = disconnected
* ``1`` = Connected
* ``3`` = Got IP && Connected
* ``7`` = Got IP && Connected && Completed to set all flags WiFi is initialized
- Yes
* - ``%vcc%``
- 5.2
- VCC value, this is only available in the VCC builds of FW (with "VCC" in the file name).
Expand All @@ -167,6 +176,14 @@ More uses of these system variables can be seen in the rules section and formula
- 2212667
- MAC address in integer to be used in rules (only the last 24 bit).
- Yes
* - ``%isntp%``
- 1
- Indicates whether time was set
- yes
* - ``%ismqtt%``
- 1
- Indicates whether a configured MQTT broker is active
- yes


Standard Conversions
Expand Down
91 changes: 8 additions & 83 deletions src/_C002.ino
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
# include "src/Helpers/PeriodicalActions.h"
# include "src/Helpers/StringParser.h"

# include <ArduinoJson.h>

String CPlugin_002_pubname;
bool CPlugin_002_mqtt_retainFlag = false;

Expand Down Expand Up @@ -77,31 +75,11 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String&
controllerIndex_t ControllerID = findFirstEnabledControllerWithId(CPLUGIN_ID_002);

if (validControllerIndex(ControllerID)) {
DynamicJsonDocument root(512);
deserializeJson(root, event->String2.c_str());

if (!root.isNull())
{
unsigned int idx = root[F("idx")];
float nvalue = root[F("nvalue")];
long nvaluealt = root[F("nvalue")];

// const char* name = root["name"]; // Not used
// const char* svalue = root["svalue"]; // Not used
const char *svalue1 = root[F("svalue1")];

// const char* svalue2 = root["svalue2"]; // Not used
// const char* svalue3 = root["svalue3"]; // Not used
const char *switchtype = root[F("switchType")]; // Expect "On/Off" or "dimmer"

if (nvalue == 0) {
nvalue = nvaluealt;
}

if ((int)switchtype == 0) {
switchtype = "?";
}

unsigned int idx;
float nvalue;
long nvaluealt;
String svalue1, switchtype;
if (deserializeDomoticzJson(event->String2, idx, nvalue, nvaluealt, svalue1, switchtype)) {
for (taskIndex_t x = 0; x < TASKS_MAX; x++) {
// We need the index of the controller we are: 0...CONTROLLER_MAX
if (Settings.TaskDeviceEnabled[x] && (Settings.TaskDeviceID[ControllerID][x] == idx)) // get idx for our controller index
Expand All @@ -122,7 +100,7 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String&
{
int baseVar = x * VARS_PER_TASK;

if (strcasecmp_P(switchtype, PSTR("dimmer")) == 0)
if (switchtype.equalsIgnoreCase(F("dimmer")))
{
mustSendEvent = true;
int pwmValue = UserVar[baseVar];
Expand Down Expand Up @@ -205,59 +183,7 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String&
{
if (event->idx != 0)
{
String json;
{
DynamicJsonDocument root(200);
root[F("idx")] = event->idx;
root[F("RSSI")] = mapRSSItoDomoticz();
# if FEATURE_ADC_VCC
root[F("Battery")] = mapVccToDomoticz();
# endif // if FEATURE_ADC_VCC

const Sensor_VType sensorType = event->getSensorType();

switch (sensorType)
{
case Sensor_VType::SENSOR_TYPE_SWITCH:
root[F("command")] = String(F("switchlight"));

if (UserVar[event->BaseVarIndex] == 0) {
root[F("switchcmd")] = String(F("Off"));
}
else {
root[F("switchcmd")] = String(F("On"));
}
break;
case Sensor_VType::SENSOR_TYPE_DIMMER:
root[F("command")] = String(F("switchlight"));

if (UserVar[event->BaseVarIndex] == 0) {
root[F("switchcmd")] = String(F("Off"));
}
else {
root[F("Set%20Level")] = UserVar[event->BaseVarIndex];
}
break;

case Sensor_VType::SENSOR_TYPE_SINGLE:
case Sensor_VType::SENSOR_TYPE_LONG:
case Sensor_VType::SENSOR_TYPE_DUAL:
case Sensor_VType::SENSOR_TYPE_TRIPLE:
case Sensor_VType::SENSOR_TYPE_QUAD:
case Sensor_VType::SENSOR_TYPE_TEMP_HUM:
case Sensor_VType::SENSOR_TYPE_TEMP_BARO:
case Sensor_VType::SENSOR_TYPE_TEMP_EMPTY_BARO:
case Sensor_VType::SENSOR_TYPE_TEMP_HUM_BARO:
case Sensor_VType::SENSOR_TYPE_WIND:
case Sensor_VType::SENSOR_TYPE_STRING:
default:
root[F("nvalue")] = 0;
root[F("svalue")] = formatDomoticzSensorType(event);
break;
}

serializeJson(root, json);
}
String json = serializeDomoticzJson(event);
# ifndef BUILD_NO_DEBUG
String log = F("MQTT : ");
log += json;
Expand All @@ -272,8 +198,7 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String&
} // if ixd !=0
else
{
String log = F("MQTT : IDX cannot be zero!");
addLog(LOG_LEVEL_ERROR, log);
addLog(LOG_LEVEL_ERROR, F("MQTT : IDX cannot be zero!"));
}
break;
}
Expand Down
4 changes: 2 additions & 2 deletions src/_C003.ino
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ bool CPlugin_003(CPlugin::Function function, struct EventStruct *event, String&
// We now create a URI for the request
String url = F("variableset ");
url += event->idx;
url += ",";
url += ',';
url += formatUserVarNoCheck(event, 0);
url += "\n";
url += '\n';
success = C003_DelayHandler->addToQueue(C003_queue_element(event->ControllerIndex, event->TaskIndex, std::move(url)));
Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C003_DELAY_QUEUE, C003_DelayHandler->getNextScheduleTime());

Expand Down
2 changes: 1 addition & 1 deletion src/_C004.ino
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ bool do_process_c004_delay_queue(int controller_number, const C004_queue_element
String postStr = do_create_http_request(
hostName, F("POST"),
F("/update"), // uri
"", // auth_header
EMPTY_STRING, // auth_header
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a generic improvement, simply replace all F("") by EMPTY_STRING ? Or does it require a __FlashStringHelper reference?

(If so then I'll start updating that in my work in progress 😉)

Copy link
Member Author

Choose a reason for hiding this comment

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

Nope, it is slightly more complex :)

For those functions that return a String object, this is an optimization as you don't need to create a String object, but simply reference a static const existing one.
But it is a bigger reduction in size if you can create functions that return a flash string instead of having code for every assignment of a flash string to a String object.

e.g. a typical toString function:

String toString(myEnumClassType enumValue) {
  switch (enumValue){
    case myEnumClassType::bla:
      return F("bla");
  }
}

This return will effectively generate return String(F("bla")); for every flash string return calls.
By returning a flash string type, you only cast it to String after the function is called. (or not at all if it can be kept as a flash string)
For example the webserver markup function calls that now also accept a flash string array, which only holds a pointer instead of allocating memory for the string only to dump it to the TXBuffer object, which also can handle flash strings without conversion.

That's the true change of this PR.

F("Content-Type: application/x-www-form-urlencoded\r\n"),
postDataStr.length());

Expand Down
6 changes: 3 additions & 3 deletions src/_C007.ino
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ bool do_process_c007_delay_queue(int controller_number, const C007_queue_element
url += F("&json=");

for (byte i = 0; i < element.valueCount; ++i) {
url += (i == 0) ? F("{") : F(",");
url += (i == 0) ? '{' : ',';
url += F("field");
url += element.idx + i;
url += ":";
url += ':';
url += element.txt[i];
}
url += "}";
url += '}';
url += F("&apikey=");
url += getControllerPass(element.controller_idx, ControllerSettings); // "0UDNN17RW6XAS2E5" // api key

Expand Down
1 change: 0 additions & 1 deletion src/_C008.ino
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
# define CPLUGIN_008
# define CPLUGIN_ID_008 8
# define CPLUGIN_NAME_008 "Generic HTTP"
# include <ArduinoJson.h>

bool CPlugin_008(CPlugin::Function function, struct EventStruct *event, String& string)
{
Expand Down
116 changes: 75 additions & 41 deletions src/_C009.ino
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
# define CPLUGIN_009
# define CPLUGIN_ID_009 9
# define CPLUGIN_NAME_009 "FHEM HTTP"
# include <ArduinoJson.h>

bool CPlugin_009(CPlugin::Function function, struct EventStruct *event, String& string)
{
Expand Down Expand Up @@ -76,7 +75,7 @@ bool CPlugin_009(CPlugin::Function function, struct EventStruct *event, String&
break;
}


success = C009_DelayHandler->addToQueue(C009_queue_element(event));
Scheduler.scheduleNextDelayQueue(ESPEasy_Scheduler::IntervalTimer_e::TIMER_C009_DELAY_QUEUE, C009_DelayHandler->getNextScheduleTime());
break;
Expand Down Expand Up @@ -110,52 +109,87 @@ bool do_process_c009_delay_queue(int controller_number, const C009_queue_element
if (!try_connect_host(controller_number, client, ControllerSettings)) {
return false;
}

LoadTaskSettings(element.TaskIndex);
String jsonString;
jsonString.reserve(768);
{
// Create json root object
DynamicJsonDocument root(1024);
root[F("module")] = String(F("ESPEasy"));
root[F("version")] = String(F("1.04"));

// Create nested objects
JsonObject data = root.createNestedObject(String(F("data")));
JsonObject ESP = data.createNestedObject(String(F("ESP")));
ESP[F("name")] = Settings.Name;
ESP[F("unit")] = Settings.Unit;
ESP[F("version")] = Settings.Version;
ESP[F("build")] = Settings.Build;
ESP[F("build_notes")] = String(F(BUILD_NOTES));
ESP[F("build_git")] = getValue(LabelType::GIT_BUILD);
ESP[F("node_type_id")] = NODE_TYPE_ID;
ESP[F("sleep")] = Settings.deepSleep_wakeTime;

// embed IP, important if there is NAT/PAT
// char ipStr[20];
// IPAddress ip = NetworkLocalIP();
// sprintf_P(ipStr, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
ESP[F("ip")] = NetworkLocalIP().toString();

// Create nested SENSOR json object
JsonObject SENSOR = data.createNestedObject(String(F("SENSOR")));

// char itemNames[valueCount][2];
for (byte x = 0; x < element.valueCount; x++)
jsonString = '{';
{
// Each sensor value get an own object (0..n)
// sprintf(itemNames[x],"%d",x);
JsonObject val = SENSOR.createNestedObject(String(x));
val[F("deviceName")] = getTaskDeviceName(element.TaskIndex);
val[F("valueName")] = ExtraTaskSettings.TaskDeviceValueNames[x];
val[F("type")] = static_cast<int>(element.sensorType);
val[F("value")] = element.txt[x];
jsonString += to_json_object_value(F("module"), F("ESPEasy"));
jsonString += ',';
jsonString += to_json_object_value(F("version"), F("1.04"));

// Create nested object "ESP" inside "data"
jsonString += ',';
jsonString += F("\"data\":{");
{
jsonString += F("\"ESP\":{");
{
// Create nested objects in "ESP":
jsonString += to_json_object_value(F("name"), Settings.Name);
jsonString += ',';
jsonString += to_json_object_value(F("unit"), String(Settings.Unit));
jsonString += ',';
jsonString += to_json_object_value(F("version"), String(Settings.Version));
jsonString += ',';
jsonString += to_json_object_value(F("build"), String(Settings.Build));
jsonString += ',';
jsonString += to_json_object_value(F("build_notes"), F(BUILD_NOTES));
jsonString += ',';
jsonString += to_json_object_value(F("build_git"), getValue(LabelType::GIT_BUILD));
jsonString += ',';
jsonString += to_json_object_value(F("node_type_id"), String(NODE_TYPE_ID));
jsonString += ',';
jsonString += to_json_object_value(F("sleep"), String(Settings.deepSleep_wakeTime));

// embed IP, important if there is NAT/PAT
// char ipStr[20];
// IPAddress ip = NetworkLocalIP();
// sprintf_P(ipStr, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
jsonString += ',';
jsonString += to_json_object_value(F("ip"), NetworkLocalIP().toString());
}
jsonString += '}'; // End "ESP"

jsonString += ',';

// Create nested object "SENSOR" json object inside "data"
jsonString += F("\"SENSOR\":{");
{
// char itemNames[valueCount][2];
for (byte x = 0; x < element.valueCount; x++)
{
// Each sensor value get an own object (0..n)
// sprintf(itemNames[x],"%d",x);
if (x != 0) {
jsonString += ',';
}

jsonString += '"';
jsonString += x;
jsonString += F("\":{");
{
jsonString += to_json_object_value(F("deviceName"), getTaskDeviceName(element.TaskIndex));
jsonString += ',';
jsonString += to_json_object_value(F("valueName"), ExtraTaskSettings.TaskDeviceValueNames[x]);
jsonString += ',';
jsonString += to_json_object_value(F("type"), String(static_cast<int>(element.sensorType)));
jsonString += ',';
jsonString += to_json_object_value(F("value"), element.txt[x]);
}
jsonString += '}'; // End "sensor value N"
}
}
jsonString += '}'; // End "SENSOR"
}
jsonString += '}'; // End "data"
}

// Create json buffer
serializeJson(root, jsonString);
jsonString += '}'; // End JSON structure
}

// addLog(LOG_LEVEL_INFO, F("C009 Test JSON:"));
// addLog(LOG_LEVEL_INFO, jsonString);

// We now create a URI for the request
String request = create_http_request_auth(
controller_number, element.controller_idx, ControllerSettings,
Expand Down
Loading