Merge branch 'memory-optimization' into v2.0.0
This commit is contained in:
commit
403bc179ef
64
src/ha.h
64
src/ha.h
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define JSON_SIZE 512
|
#define JSON_SIZE 1024
|
||||||
#define TOPIC_SIZE 255
|
#define TOPIC_SIZE 255
|
||||||
#define CONFIG_TOPIC "homeassistant/%s/" MAIN_DEVICE_ID "/%s"
|
#define CONFIG_TOPIC "homeassistant/%s/" MAIN_DEVICE_ID "/%s"
|
||||||
#define BASE_TOPIC MAIN_DEVICE_ID "/%s"
|
#define BASE_TOPIC MAIN_DEVICE_ID "/%s"
|
||||||
@ -92,15 +92,13 @@ namespace Ha {
|
|||||||
void publishConfig() {
|
void publishConfig() {
|
||||||
StaticJsonDocument<JSON_SIZE> jsonDoc;
|
StaticJsonDocument<JSON_SIZE> jsonDoc;
|
||||||
buildConfig(jsonDoc);
|
buildConfig(jsonDoc);
|
||||||
|
auto configTopic = buildConfigTopic();
|
||||||
char message[JSON_SIZE] = {};
|
publisher(configTopic.get(), jsonDoc.as<string>().c_str());
|
||||||
serializeJson(jsonDoc, message);
|
|
||||||
|
|
||||||
publisher(configTopic, message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void publishCleanupConfig() {
|
void publishCleanupConfig() {
|
||||||
publisher(configTopic, "");
|
auto configTopic = buildConfigTopic();
|
||||||
|
publisher(configTopic.get(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void toJson(JsonDocument& jsonDoc) {
|
void toJson(JsonDocument& jsonDoc) {
|
||||||
@ -119,11 +117,8 @@ namespace Ha {
|
|||||||
jsonDoc["name"] = name;
|
jsonDoc["name"] = name;
|
||||||
|
|
||||||
buildUniqueId(jsonDoc);
|
buildUniqueId(jsonDoc);
|
||||||
buildConfigTopic();
|
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
char configTopic[TOPIC_SIZE] = {};
|
|
||||||
|
|
||||||
void buildUniqueId(JsonDocument& jsonDoc) {
|
void buildUniqueId(JsonDocument& jsonDoc) {
|
||||||
char uniqueId[50];
|
char uniqueId[50];
|
||||||
if (multiValueComponent && deviceClass) {
|
if (multiValueComponent && deviceClass) {
|
||||||
@ -134,12 +129,14 @@ namespace Ha {
|
|||||||
jsonDoc["unique_id"] = uniqueId;
|
jsonDoc["unique_id"] = uniqueId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void buildConfigTopic() {
|
unique_ptr<char[]> buildConfigTopic() {
|
||||||
|
unique_ptr<char[]> topic(new char[TOPIC_SIZE]);
|
||||||
if (multiValueComponent && deviceClass) {
|
if (multiValueComponent && deviceClass) {
|
||||||
snprintf(configTopic, sizeof(configTopic), CONFIG_TOPIC"_%s""/config", type, deviceClass, id);
|
snprintf(topic.get(), TOPIC_SIZE, CONFIG_TOPIC"_%s""/config", type, deviceClass, id);
|
||||||
} else {
|
} else {
|
||||||
snprintf(configTopic, sizeof(configTopic), CONFIG_TOPIC"/config", type, id);
|
snprintf(topic.get(), TOPIC_SIZE, CONFIG_TOPIC"/config", type, id);
|
||||||
}
|
}
|
||||||
|
return topic;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -149,8 +146,8 @@ namespace Ha {
|
|||||||
inline static unordered_map<string, Command*> mapCommandIds;
|
inline static unordered_map<string, Command*> mapCommandIds;
|
||||||
|
|
||||||
Command(Component* cmp, onMessage f) : f(f), cmp(cmp) {
|
Command(Component* cmp, onMessage f) : f(f), cmp(cmp) {
|
||||||
snprintf(commandTopic, sizeof(commandTopic), BASE_TOPIC"/set", cmp->id);
|
auto commandTopic = buildTopic();
|
||||||
mapCommandTopics.insert({ string(commandTopic), this });
|
mapCommandTopics.insert({ string(commandTopic.get()), this });
|
||||||
mapCommandIds.insert({ string(cmp->id), this });
|
mapCommandIds.insert({ string(cmp->id), this });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,39 +160,48 @@ namespace Ha {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
char commandTopic[TOPIC_SIZE] = {};
|
|
||||||
onMessage f;
|
onMessage f;
|
||||||
|
|
||||||
void buildConfig(JsonDocument& jsonDoc) override {
|
void buildConfig(JsonDocument& jsonDoc) override {
|
||||||
jsonDoc["command_topic"] = (const char*)commandTopic;
|
auto commandTopic = buildTopic();
|
||||||
|
jsonDoc["command_topic"] = commandTopic.get();
|
||||||
if (retain) jsonDoc["retain"] = true;
|
if (retain) jsonDoc["retain"] = true;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
Component* cmp;
|
Component* cmp;
|
||||||
|
|
||||||
|
unique_ptr<char[]> buildTopic() {
|
||||||
|
unique_ptr<char[]> topic(new char[TOPIC_SIZE]);
|
||||||
|
snprintf(topic.get(), TOPIC_SIZE, BASE_TOPIC "/set", cmp->id);
|
||||||
|
return topic;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct State : Config {
|
struct State : Config {
|
||||||
char stateTopic[TOPIC_SIZE] = {};
|
char* topic;
|
||||||
const char* jsonAttributesTemplate = nullptr;
|
const char* jsonAttributesTemplate = nullptr;
|
||||||
const char* valueTemplate = nullptr;
|
const char* valueTemplate = nullptr;
|
||||||
|
|
||||||
State(Component* cmp) : cmp(cmp) {}
|
State(Component* cmp) : cmp(cmp) {
|
||||||
|
auto len = snprintf(nullptr, 0, BASE_TOPIC"/state", cmp->id);
|
||||||
|
topic = new char[len + 1];
|
||||||
|
}
|
||||||
|
|
||||||
void withStateTopic() {
|
void withStateTopic() {
|
||||||
snprintf(stateTopic, sizeof(stateTopic), BASE_TOPIC"/state", cmp->id);
|
sprintf(topic, BASE_TOPIC"/state", cmp->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateState(const char* message) {
|
void updateState(const char* message) {
|
||||||
if (stateTopic[0]) publisher(stateTopic, message);
|
if (topic[0]) publisher(topic, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void buildConfig(JsonDocument& jsonDoc) override {
|
void buildConfig(JsonDocument& jsonDoc) override {
|
||||||
if (stateTopic[0]) {
|
if (topic[0]) {
|
||||||
jsonDoc["state_topic"] = (const char*)stateTopic;
|
jsonDoc["state_topic"] = (const char*)topic;
|
||||||
if (jsonAttributesTemplate) {
|
if (jsonAttributesTemplate) {
|
||||||
jsonDoc["json_attributes_template"] = jsonAttributesTemplate;
|
jsonDoc["json_attributes_template"] = jsonAttributesTemplate;
|
||||||
jsonDoc["json_attributes_topic"] = (const char*)stateTopic;
|
jsonDoc["json_attributes_topic"] = (const char*)topic;
|
||||||
}
|
}
|
||||||
if (valueTemplate) jsonDoc["value_template"] = valueTemplate;
|
if (valueTemplate) jsonDoc["value_template"] = valueTemplate;
|
||||||
}
|
}
|
||||||
@ -209,9 +215,9 @@ namespace Ha {
|
|||||||
|
|
||||||
StatefulCommand(Component* cmp, onMessage f) : Command(cmp, f), State(cmp) {}
|
StatefulCommand(Component* cmp, onMessage f) : Command(cmp, f), State(cmp) {}
|
||||||
|
|
||||||
void restoreStateFromCommand() {
|
void restoreStateFromTopic() {
|
||||||
withStateTopic();
|
withStateTopic();
|
||||||
mapRestoreStateTopics.insert({stateTopic, this});
|
mapRestoreStateTopics.insert({State::topic, this});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -508,12 +514,12 @@ namespace Ha {
|
|||||||
|
|
||||||
[[deprecated("Use restoreStateFromCommand() instead")]]
|
[[deprecated("Use restoreStateFromCommand() instead")]]
|
||||||
Builder& restoreFromState() {
|
Builder& restoreFromState() {
|
||||||
cmp->restoreStateFromCommand();
|
cmp->restoreStateFromTopic();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder& restoreStateFromCommand() {
|
Builder& restoreStateFromTopic() {
|
||||||
cmp->restoreStateFromCommand();
|
cmp->restoreStateFromTopic();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -30,10 +30,10 @@ namespace WebServer {
|
|||||||
server.on("/commands", HTTP_GET, [](AsyncWebServerRequest *request) {
|
server.on("/commands", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
|
|
||||||
DynamicJsonDocument jsonResponse(JSON_SIZE*10);
|
DynamicJsonDocument jsonResponse(5120);
|
||||||
JsonArray array = jsonResponse.to<JsonArray>();
|
JsonArray array = jsonResponse.to<JsonArray>();
|
||||||
for (auto it = Command::mapCommandIds.begin(); it != Command::mapCommandIds.end(); ++it) {
|
for (auto it = Command::mapCommandIds.begin(); it != Command::mapCommandIds.end(); ++it) {
|
||||||
StaticJsonDocument<JSON_SIZE/2> jsonDoc;
|
StaticJsonDocument<256> jsonDoc;
|
||||||
it->second->toJson(jsonDoc);
|
it->second->toJson(jsonDoc);
|
||||||
array.add(jsonDoc);
|
array.add(jsonDoc);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include <unity.h>
|
#include <unity.h>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#define MAIN_DEVICE_ID "test"
|
#define MAIN_DEVICE_ID "test"
|
||||||
|
|
||||||
@ -208,6 +209,18 @@ void testBinarySensor(void) {
|
|||||||
TEST_ASSERT_NOT_NULL(GenericSensor::mapSensors["id"]);
|
TEST_ASSERT_NOT_NULL(GenericSensor::mapSensors["id"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testPublisher(void) {
|
||||||
|
Ha::publisher = [](const char* topic, const char* message) -> uint16_t {
|
||||||
|
TEST_ASSERT_EQUAL_STRING("{\"name\":\"a_name\",\"unique_id\":\"test_id\",\"command_topic\":\"test/id/set\"}", message);
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
Switch s("a_name", "id");
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
s.buildConfig(doc);
|
||||||
|
s.publishConfig();
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
UNITY_BEGIN();
|
UNITY_BEGIN();
|
||||||
RUN_TEST(testDevice);
|
RUN_TEST(testDevice);
|
||||||
@ -224,5 +237,6 @@ int main(int argc, char **argv) {
|
|||||||
RUN_TEST(testSwitchWithState);
|
RUN_TEST(testSwitchWithState);
|
||||||
RUN_TEST(testNumber);
|
RUN_TEST(testNumber);
|
||||||
RUN_TEST(testBinarySensor);
|
RUN_TEST(testBinarySensor);
|
||||||
|
RUN_TEST(testPublisher);
|
||||||
return UNITY_END();
|
return UNITY_END();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user