Merge branch 'v1.4.1'
This commit is contained in:
commit
a3b8b8a65d
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/schema/library.json",
|
"$schema": "https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/schema/library.json",
|
||||||
"name": "ha-mqtt",
|
"name": "ha-mqtt",
|
||||||
"version": "1.4.0",
|
"version": "1.4.1",
|
||||||
"description": "Home Assistant classes for integration with MQTT auto discovery",
|
"description": "Home Assistant classes for integration with MQTT auto discovery",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@ -13,4 +13,6 @@ default_envs = native
|
|||||||
|
|
||||||
[env:native]
|
[env:native]
|
||||||
platform = native
|
platform = native
|
||||||
debug_build_flags = -std=c++11
|
test_filter = native/*
|
||||||
|
lib_deps =
|
||||||
|
bblanchon/ArduinoJson@6.21.5
|
||||||
|
|||||||
354
src/ha.h
354
src/ha.h
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include "utils.h"
|
#include "list.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ namespace Ha {
|
|||||||
StaticJsonDocument<JSON_SIZE> jsonDoc;
|
StaticJsonDocument<JSON_SIZE> jsonDoc;
|
||||||
buildConfig(jsonDoc);
|
buildConfig(jsonDoc);
|
||||||
|
|
||||||
char message[JSON_SIZE];
|
char message[JSON_SIZE] = {};
|
||||||
serializeJson(jsonDoc, message);
|
serializeJson(jsonDoc, message);
|
||||||
|
|
||||||
publisher(configTopic, message);
|
publisher(configTopic, message);
|
||||||
@ -110,7 +110,7 @@ namespace Ha {
|
|||||||
buildConfigTopic();
|
buildConfigTopic();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
char configTopic[TOPIC_SIZE];
|
char configTopic[TOPIC_SIZE] = {};
|
||||||
|
|
||||||
void buildUniqueId(JsonDocument& jsonDoc) {
|
void buildUniqueId(JsonDocument& jsonDoc) {
|
||||||
char uniqueId[50];
|
char uniqueId[50];
|
||||||
@ -131,6 +131,181 @@ namespace Ha {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Command : Config {
|
||||||
|
bool retain = false;
|
||||||
|
static unordered_map<string, Command*> mapCommandTopics;
|
||||||
|
|
||||||
|
Command(Component* cmp, onMessage f) : f(f), cmp(cmp) {
|
||||||
|
snprintf(commandTopic, sizeof(commandTopic), BASE_TOPIC"/set", cmp->type, MAIN_DEVICE_ID, cmp->id);
|
||||||
|
mapCommandTopics.insert({ string(commandTopic), this });
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void onCommand(const char* msg) {
|
||||||
|
if (f) f(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
char commandTopic[TOPIC_SIZE] = {};
|
||||||
|
onMessage f;
|
||||||
|
|
||||||
|
void buildConfig(JsonDocument& jsonDoc) override {
|
||||||
|
jsonDoc["command_topic"] = (const char*)commandTopic;
|
||||||
|
if (retain) jsonDoc["retain"] = true;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Component* cmp;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct State : Config {
|
||||||
|
char stateTopic[TOPIC_SIZE] = {};
|
||||||
|
const char* jsonAttributesTemplate = nullptr;
|
||||||
|
|
||||||
|
State(Component* cmp) : cmp(cmp) {}
|
||||||
|
|
||||||
|
void withStateTopic() {
|
||||||
|
snprintf(stateTopic, sizeof(stateTopic), BASE_TOPIC"/state", cmp->type, MAIN_DEVICE_ID, cmp->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateState(const char* message) {
|
||||||
|
if (stateTopic[0]) publisher(stateTopic, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void buildConfig(JsonDocument& jsonDoc) override {
|
||||||
|
if (stateTopic[0]) {
|
||||||
|
jsonDoc["state_topic"] = (const char*)stateTopic;
|
||||||
|
if (jsonAttributesTemplate) {
|
||||||
|
jsonDoc["json_attributes_template"] = jsonAttributesTemplate;
|
||||||
|
jsonDoc["json_attributes_topic"] = (const char*)stateTopic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Component* cmp;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StatefulCommand : Command, State {
|
||||||
|
static unordered_map<string, Command*> mapRestoreStateTopics;
|
||||||
|
|
||||||
|
StatefulCommand(Component* cmp, onMessage f) : Command(cmp, f), State(cmp) {}
|
||||||
|
|
||||||
|
void restoreFromState() {
|
||||||
|
mapRestoreStateTopics.insert({stateTopic, this});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void buildConfig(JsonDocument& jsonDoc) override {
|
||||||
|
Command::buildConfig(jsonDoc);
|
||||||
|
State::buildConfig(jsonDoc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Button : Component, Command {
|
||||||
|
|
||||||
|
Button(const char* name, const char* id, onMessage f = nullptr) : Component(id, name, "button"), Command(this, f) {}
|
||||||
|
|
||||||
|
void buildConfig(JsonDocument& jsonDoc) override {
|
||||||
|
Component::buildConfig(jsonDoc);
|
||||||
|
Command::buildConfig(jsonDoc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Switch : Component, StatefulCommand {
|
||||||
|
|
||||||
|
Switch(const char* name, const char* id, onMessage f = nullptr) : Component(id, name, "switch"), StatefulCommand(this, f) {}
|
||||||
|
|
||||||
|
void updateState(bool state) {
|
||||||
|
State::updateState(state ? "ON" : "OFF");
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildConfig(JsonDocument& jsonDoc) override {
|
||||||
|
Component::buildConfig(jsonDoc);
|
||||||
|
StatefulCommand::buildConfig(jsonDoc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Number : Component, StatefulCommand {
|
||||||
|
unsigned int min = 1;
|
||||||
|
unsigned int max = 100;
|
||||||
|
unsigned int step = 1;
|
||||||
|
|
||||||
|
Number(const char* name, const char* id, onMessage f) : Component(id, name, "number"), StatefulCommand(this, f) {}
|
||||||
|
|
||||||
|
void updateState(unsigned int value) {
|
||||||
|
State::updateState(to_string(value).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildConfig(JsonDocument& jsonDoc) override {
|
||||||
|
Component::buildConfig(jsonDoc);
|
||||||
|
StatefulCommand::buildConfig(jsonDoc);
|
||||||
|
jsonDoc["min"] = min;
|
||||||
|
jsonDoc["max"] = max;
|
||||||
|
jsonDoc["step"] = step;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sensor : Component, State {
|
||||||
|
const char* unitMeasure = nullptr;
|
||||||
|
const char* valueTemplate = nullptr;
|
||||||
|
unsigned int precision = 2;
|
||||||
|
static unordered_map<string, Sensor*> mapSensors;
|
||||||
|
|
||||||
|
Sensor(const char* name, const char* id) : Component(id, name, "sensor"), State(this) {
|
||||||
|
withStateTopic();
|
||||||
|
mapSensors.insert({ string(id), this });
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildConfig(JsonDocument& jsonDoc) override {
|
||||||
|
Component::buildConfig(jsonDoc);
|
||||||
|
State::buildConfig(jsonDoc);
|
||||||
|
if (unitMeasure) jsonDoc["unit_of_measurement"] = unitMeasure;
|
||||||
|
if (valueTemplate) jsonDoc["value_template"] = valueTemplate;
|
||||||
|
if (isNumericSensor()) jsonDoc["suggested_display_precision"] = precision;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool isNumericSensor() {
|
||||||
|
return deviceClass || unitMeasure;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TemperatureSensor : Sensor {
|
||||||
|
TemperatureSensor(const char* id, const char* name = "Temperature") : Sensor(name, id) {
|
||||||
|
deviceClass = "temperature";
|
||||||
|
unitMeasure = "°C";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HumiditySensor : Sensor {
|
||||||
|
HumiditySensor(const char* id, const char* name = "Humidity") : Sensor(name, id) {
|
||||||
|
deviceClass = "humidity";
|
||||||
|
unitMeasure = "%";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PressureSensor : Sensor {
|
||||||
|
PressureSensor(const char* id, const char* name = "Pressure") : Sensor(name, id) {
|
||||||
|
deviceClass = "pressure";
|
||||||
|
unitMeasure = "hPa";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VoltageSensor : Sensor {
|
||||||
|
VoltageSensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) {
|
||||||
|
this->valueTemplate = valueTemplate;
|
||||||
|
deviceClass = "voltage";
|
||||||
|
unitMeasure = "V";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BatterySensor : Sensor {
|
||||||
|
BatterySensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) {
|
||||||
|
this->valueTemplate = valueTemplate;
|
||||||
|
deviceClass = "battery";
|
||||||
|
unitMeasure = "%";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct AbstractBuilder {
|
struct AbstractBuilder {
|
||||||
static List<AbstractBuilder> builders;
|
static List<AbstractBuilder> builders;
|
||||||
|
|
||||||
@ -248,179 +423,6 @@ namespace Ha {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Command : Config {
|
|
||||||
bool retain = false;
|
|
||||||
static unordered_map<string, Command*> mapCommandTopics;
|
|
||||||
|
|
||||||
Command(Component* cmp, onMessage f) : f(f), cmp(cmp) {
|
|
||||||
snprintf(commandTopic, sizeof(commandTopic), BASE_TOPIC"/set", cmp->type, MAIN_DEVICE_ID, cmp->id);
|
|
||||||
mapCommandTopics.insert({ string(commandTopic), this });
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void onCommand(const char* msg) {
|
|
||||||
if (f) f(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
char commandTopic[TOPIC_SIZE];
|
|
||||||
onMessage f;
|
|
||||||
|
|
||||||
void buildConfig(JsonDocument& jsonDoc) override {
|
|
||||||
jsonDoc["command_topic"] = (const char*)commandTopic;
|
|
||||||
if (retain) jsonDoc["retain"] = true;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
Component* cmp;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Button : Component, Command {
|
|
||||||
|
|
||||||
Button(const char* name, const char* id, onMessage f = nullptr) : Component(id, name, "button"), Command(this, f) {}
|
|
||||||
|
|
||||||
void buildConfig(JsonDocument& jsonDoc) override {
|
|
||||||
Component::buildConfig(jsonDoc);
|
|
||||||
Command::buildConfig(jsonDoc);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct State : Config {
|
|
||||||
char stateTopic[TOPIC_SIZE];
|
|
||||||
const char* jsonAttributesTemplate = nullptr;
|
|
||||||
|
|
||||||
State(Component* cmp) : cmp(cmp) {}
|
|
||||||
|
|
||||||
void withStateTopic() {
|
|
||||||
snprintf(stateTopic, sizeof(stateTopic), BASE_TOPIC"/state", cmp->type, MAIN_DEVICE_ID, cmp->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateState(const char* message) {
|
|
||||||
if (stateTopic[0]) publisher(stateTopic, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void buildConfig(JsonDocument& jsonDoc) override {
|
|
||||||
if (stateTopic[0]) {
|
|
||||||
jsonDoc["state_topic"] = (const char*)stateTopic;
|
|
||||||
if (jsonAttributesTemplate) {
|
|
||||||
jsonDoc["json_attributes_template"] = jsonAttributesTemplate;
|
|
||||||
jsonDoc["json_attributes_topic"] = (const char*)stateTopic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
Component* cmp;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StatefulCommand : Command, State {
|
|
||||||
static unordered_map<string, Command*> mapRestoreStateTopics;
|
|
||||||
|
|
||||||
StatefulCommand(Component* cmp, onMessage f) : Command(cmp, f), State(cmp) {}
|
|
||||||
|
|
||||||
void restoreFromState() {
|
|
||||||
mapRestoreStateTopics.insert({stateTopic, this});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void buildConfig(JsonDocument& jsonDoc) override {
|
|
||||||
Command::buildConfig(jsonDoc);
|
|
||||||
State::buildConfig(jsonDoc);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Switch : Component, StatefulCommand {
|
|
||||||
|
|
||||||
Switch(const char* name, const char* id, onMessage f = nullptr) : Component(id, name, "switch"), StatefulCommand(this, f) {}
|
|
||||||
|
|
||||||
void updateState(bool state) {
|
|
||||||
State::updateState(state ? "ON" : "OFF");
|
|
||||||
}
|
|
||||||
|
|
||||||
void buildConfig(JsonDocument& jsonDoc) override {
|
|
||||||
Component::buildConfig(jsonDoc);
|
|
||||||
StatefulCommand::buildConfig(jsonDoc);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Number : Component, StatefulCommand {
|
|
||||||
unsigned int min, max, step;
|
|
||||||
|
|
||||||
Number(const char* name, const char* id, onMessage f) : Component(id, name, "number"), StatefulCommand(this, f) {}
|
|
||||||
|
|
||||||
void updateState(unsigned int value) {
|
|
||||||
State::updateState(to_string(value).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void buildConfig(JsonDocument& jsonDoc) override {
|
|
||||||
Component::buildConfig(jsonDoc);
|
|
||||||
StatefulCommand::buildConfig(jsonDoc);
|
|
||||||
jsonDoc["min"] = min;
|
|
||||||
jsonDoc["max"] = max;
|
|
||||||
jsonDoc["step"] = step;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Sensor : Component, State {
|
|
||||||
const char* unitMeasure = nullptr;
|
|
||||||
const char* valueTemplate = nullptr;
|
|
||||||
unsigned int precision = 2;
|
|
||||||
static unordered_map<string, Sensor*> mapSensors;
|
|
||||||
|
|
||||||
Sensor(const char* name, const char* id) : Component(id, name, "sensor"), State(this) {
|
|
||||||
withStateTopic();
|
|
||||||
mapSensors.insert({ string(id), this });
|
|
||||||
}
|
|
||||||
|
|
||||||
void buildConfig(JsonDocument& jsonDoc) override {
|
|
||||||
Component::buildConfig(jsonDoc);
|
|
||||||
State::buildConfig(jsonDoc);
|
|
||||||
if (unitMeasure) jsonDoc["unit_of_measurement"] = unitMeasure;
|
|
||||||
if (valueTemplate) jsonDoc["value_template"] = valueTemplate;
|
|
||||||
if (isNumericSensor()) jsonDoc["suggested_display_precision"] = precision;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool isNumericSensor() {
|
|
||||||
return deviceClass || unitMeasure;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TemperatureSensor : Sensor {
|
|
||||||
TemperatureSensor(const char* id, const char* name = "Temperature") : Sensor(name, id) {
|
|
||||||
deviceClass = "temperature";
|
|
||||||
unitMeasure = "°C";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VoltageSensor : Sensor {
|
|
||||||
VoltageSensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) {
|
|
||||||
this->valueTemplate = valueTemplate;
|
|
||||||
deviceClass = "voltage";
|
|
||||||
unitMeasure = "V";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BatterySensor : Sensor {
|
|
||||||
BatterySensor(const char* id, const char* name, const char* valueTemplate) : Sensor(name, id) {
|
|
||||||
this->valueTemplate = valueTemplate;
|
|
||||||
deviceClass = "battery";
|
|
||||||
unitMeasure = "%";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HumiditySensor : Sensor {
|
|
||||||
HumiditySensor(const char* id, const char* name = "Humidity") : Sensor(name, id) {
|
|
||||||
deviceClass = "humidity";
|
|
||||||
unitMeasure = "%";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PressureSensor : Sensor {
|
|
||||||
PressureSensor(const char* id, const char* name = "Pressure") : Sensor(name, id) {
|
|
||||||
deviceClass = "pressure";
|
|
||||||
unitMeasure = "hPa";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
List<Component> Component::components;
|
List<Component> Component::components;
|
||||||
List<AbstractBuilder> AbstractBuilder::builders;
|
List<AbstractBuilder> AbstractBuilder::builders;
|
||||||
unordered_map<string, Command*> Command::mapCommandTopics;
|
unordered_map<string, Command*> Command::mapCommandTopics;
|
||||||
|
|||||||
210
test/native/ha/test_components/main.cpp
Normal file
210
test/native/ha/test_components/main.cpp
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
#include <unity.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#define MAIN_DEVICE_ID "test"
|
||||||
|
|
||||||
|
#include "ha.h"
|
||||||
|
|
||||||
|
using namespace Ha;
|
||||||
|
|
||||||
|
void setUp(void) {
|
||||||
|
// set stuff up here
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown(void) {
|
||||||
|
// clean stuff up here
|
||||||
|
}
|
||||||
|
|
||||||
|
void testDevice(void) {
|
||||||
|
auto d = DeviceConfig::create("1").withName("name").withModel("model").withArea("area").withManufacturer("man");
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
d.buildConfig(doc);
|
||||||
|
|
||||||
|
JsonObject dev = doc["device"];
|
||||||
|
TEST_ASSERT_TRUE(doc.containsKey("device"));
|
||||||
|
TEST_ASSERT_EQUAL_STRING("name", dev["name"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("model", dev["model"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("area", dev["suggested_area"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("man", dev["manufacturer"]);
|
||||||
|
TEST_ASSERT_TRUE(dev.containsKey("identifiers"));
|
||||||
|
TEST_ASSERT_EQUAL_STRING("1", dev["identifiers"][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testButton(void) {
|
||||||
|
Button b("a_name", "id");
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
b.buildConfig(doc);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING(MAIN_DEVICE_ID"_id", doc["unique_id"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("homeassistant/button/" MAIN_DEVICE_ID "/id/set", doc["command_topic"]);
|
||||||
|
TEST_ASSERT_FALSE(doc["retain"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("a_name", doc["name"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(NULL, doc["device_class"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(NULL, doc["entity_category"]);
|
||||||
|
TEST_ASSERT_NOT_NULL(Command::mapCommandTopics[doc["command_topic"]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testSensor(void) {
|
||||||
|
Sensor s("a_name", "id");
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
s.buildConfig(doc);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING(MAIN_DEVICE_ID"_id", doc["unique_id"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("homeassistant/sensor/" MAIN_DEVICE_ID "/id/state", doc["state_topic"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("a_name", doc["name"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(NULL, doc["device_class"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(NULL, doc["entity_category"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(NULL, doc["unit_of_measurement"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(NULL, doc["value_template"]);
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, doc["suggested_display_precision"]);
|
||||||
|
TEST_ASSERT_NOT_NULL(Sensor::mapSensors["id"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testNumericSensor1(void) {
|
||||||
|
Sensor s("a_name", "id");
|
||||||
|
s.deviceClass = "class";
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
s.buildConfig(doc);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT(2, doc["suggested_display_precision"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testNumericSensor2(void) {
|
||||||
|
Sensor s("a_name", "id");
|
||||||
|
s.unitMeasure = "%";
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
s.buildConfig(doc);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT(2, doc["suggested_display_precision"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testSwitch(void) {
|
||||||
|
Switch s("a_name", "id");
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
s.buildConfig(doc);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING(MAIN_DEVICE_ID"_id", doc["unique_id"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("homeassistant/switch/" MAIN_DEVICE_ID "/id/set", doc["command_topic"]);
|
||||||
|
TEST_ASSERT_FALSE(doc["retain"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("a_name", doc["name"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(NULL, doc["device_class"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(NULL, doc["entity_category"]);
|
||||||
|
TEST_ASSERT_NOT_NULL(Command::mapCommandTopics[doc["command_topic"]]);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING(NULL, doc["state_topic"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testSwitchWithState(void) {
|
||||||
|
Switch s("a_name", "id");
|
||||||
|
s.withStateTopic();
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
s.buildConfig(doc);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("homeassistant/switch/" MAIN_DEVICE_ID "/id/state", doc["state_topic"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testNumber(void) {
|
||||||
|
Number n("a_name", "id", nullptr);
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
n.buildConfig(doc);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING(MAIN_DEVICE_ID"_id", doc["unique_id"]);
|
||||||
|
TEST_ASSERT_EQUAL_INT16(1, doc["min"]);
|
||||||
|
TEST_ASSERT_EQUAL_INT16(100, doc["max"]);
|
||||||
|
TEST_ASSERT_EQUAL_INT16(1, doc["step"]);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("homeassistant/number/" MAIN_DEVICE_ID "/id/set", doc["command_topic"]);
|
||||||
|
TEST_ASSERT_FALSE(doc["retain"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("a_name", doc["name"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(NULL, doc["device_class"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(NULL, doc["entity_category"]);
|
||||||
|
TEST_ASSERT_NOT_NULL(Command::mapCommandTopics[doc["command_topic"]]);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING(NULL, doc["state_topic"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testTemperatureSensor(void) {
|
||||||
|
TemperatureSensor s("id");
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
s.buildConfig(doc);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("Temperature", doc["name"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("temperature", doc["device_class"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("°C", doc["unit_of_measurement"]);
|
||||||
|
TEST_ASSERT_EQUAL_INT(2, doc["suggested_display_precision"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testHumiditySensor(void) {
|
||||||
|
HumiditySensor s("id");
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
s.buildConfig(doc);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("Humidity", doc["name"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("humidity", doc["device_class"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("%", doc["unit_of_measurement"]);
|
||||||
|
TEST_ASSERT_EQUAL_INT(2, doc["suggested_display_precision"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testPressureSensor(void) {
|
||||||
|
PressureSensor s("id");
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
s.buildConfig(doc);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("Pressure", doc["name"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("pressure", doc["device_class"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("hPa", doc["unit_of_measurement"]);
|
||||||
|
TEST_ASSERT_EQUAL_INT(2, doc["suggested_display_precision"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testVoltageSensor(void) {
|
||||||
|
VoltageSensor s("id", "a_name", nullptr);
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
s.buildConfig(doc);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("a_name", doc["name"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("voltage", doc["device_class"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("V", doc["unit_of_measurement"]);
|
||||||
|
TEST_ASSERT_EQUAL_INT(2, doc["suggested_display_precision"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testBatterySensor(void) {
|
||||||
|
BatterySensor s("id", "a_name", nullptr);
|
||||||
|
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
s.buildConfig(doc);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("a_name", doc["name"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("battery", doc["device_class"]);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("%", doc["unit_of_measurement"]);
|
||||||
|
TEST_ASSERT_EQUAL_INT(2, doc["suggested_display_precision"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(testDevice);
|
||||||
|
RUN_TEST(testButton);
|
||||||
|
RUN_TEST(testSensor);
|
||||||
|
RUN_TEST(testTemperatureSensor);
|
||||||
|
RUN_TEST(testHumiditySensor);
|
||||||
|
RUN_TEST(testPressureSensor);
|
||||||
|
RUN_TEST(testVoltageSensor);
|
||||||
|
RUN_TEST(testBatterySensor);
|
||||||
|
RUN_TEST(testNumericSensor1);
|
||||||
|
RUN_TEST(testNumericSensor2);
|
||||||
|
RUN_TEST(testSwitch);
|
||||||
|
RUN_TEST(testSwitchWithState);
|
||||||
|
RUN_TEST(testNumber);
|
||||||
|
return UNITY_END();
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#include <unity.h>
|
#include <unity.h>
|
||||||
#include "utils.h"
|
#include "list.h"
|
||||||
|
|
||||||
void setUp(void) {
|
void setUp(void) {
|
||||||
// set stuff up here
|
// set stuff up here
|
||||||
Loading…
x
Reference in New Issue
Block a user