ESP32原生开发——小智AI解析3(thing.cc)
头文件
#ifndef THING_H #define THING_H #include <string> #include <map> #include <functional> #include <vector> #include <stdexcept> #include <cJSON.h>
命名空间
namespace iot {
命名空间内的enum枚举类型
enum ValueType { kValueTypeBoolean, kValueTypeNumber, kValueTypeString };
内涵的几个类
class Property {
私有成员变量
private: std::string name_; std::string description_; ValueType type_; std::function<bool()> boolean_getter_; std::function<int()> number_getter_; std::function<std::string()> string_getter_;
重载过的构造函数
public: Property(const std::string& name, const std::string& description, std::function<bool()> getter) : name_(name), description_(description), type_(kValueTypeBoolean), boolean_getter_(getter) {} Property(const std::string& name, const std::string& description, std::function<int()> getter) : name_(name), description_(description), type_(kValueTypeNumber), number_getter_(getter) {} Property(const std::string& name, const std::string& description, std::function<std::string()> getter) : name_(name), description_(description), type_(kValueTypeString), string_getter_(getter) {}
name description type 名称描述类型
const std::string& name() const { return name_; } const std::string& description() const { return description_; } ValueType type() const { return type_; } bool boolean() const { return boolean_getter_(); } int number() const { return number_getter_(); } std::string string() const { return string_getter_(); }
获取描述json字符串
//布尔类型属性:{"description":"这是一个布尔属性","type":"boolean"} //数值类型属性:{"description":"这是一个数值属性","type":"number"} //字符串类型属性:{"description":"这是一个字符串属性","type":"string"} std::string GetDescriptorJson() { //创建一个 std::string 类型的变量 json_str,并将其初始化为 {,这是 JSON 对象的起始符号。 std::string json_str = "{"; //向 json_str 中添加 description 字段,格式为 "description":"属性描述信息"。 //description_ 是 Property 类的私有成员变量,存储着属性的描述信息。 json_str += "\"description\":\"" + description_ + "\","; //依据 type_(Property 类的私有成员变量,代表属性的类型)的值,向 json_str 中添加 type 字段: //若 type_ 为 kValueTypeBoolean,添加 "type":"boolean"。 //若 type_ 为 kValueTypeNumber,添加 "type":"number"。 //若 type_ 为 kValueTypeString,添加 "type":"string"。 if (type_ == kValueTypeBoolean) { json_str += "\"type\":\"boolean\""; } else if (type_ == kValueTypeNumber) { json_str += "\"type\":\"number\""; } else if (type_ == kValueTypeString) { json_str += "\"type\":\"string\""; } //向 json_str 中添加 },这是 JSON 对象的结束符号。 json_str += "}"; //返回生成好的包含属性描述信息和类型信息的 JSON 字符串。 return json_str; }
获取状态JSON字符串
//GetStateJson 函数根据属性的类型,调用对应的取值函数获取属性当前值,并将其转换为符合 JSON 格式的字符串返回。若属性类型无效,则返回 "null"。示例输出如下: //布尔类型属性:true 或 false //数值类型属性:123 //字符串类型属性:"hello" //无效类型属性:null std::string GetStateJson() { // 检查属性类型是否为布尔类型 if (type_ == kValueTypeBoolean) { // 调用布尔值获取函数,根据返回结果返回 "true" 或 "false" return boolean_getter_() ? "true" : "false"; } // 检查属性类型是否为数值类型 else if (type_ == kValueTypeNumber) { // 调用数值获取函数,将返回的整数值转换为字符串返回 return std::to_string(number_getter_()); } // 检查属性类型是否为字符串类型 else if (type_ == kValueTypeString) { // 调用字符串获取函数,将返回的字符串用双引号包裹后返回,以符合 JSON 字符串格式 return "\"" + string_getter_() + "\""; } // 若属性类型不匹配上述任何一种有效类型,则返回表示空值的 "null" 字符串 return "null"; }
PropertyList类
这个类需要前面的类
但是不需要前向声明
class PropertyList {
私有变量就一个property容器
private: std::vector<Property> properties_;
构造函数很有趣,C++11特性 default构造
public: PropertyList() = default; PropertyList(const std::vector<Property>& properties) : properties_(properties) {}
选中的代码是 PropertyList 类中的两个成员函数,用于向 PropertyList 对象添加不同类型的属性。下面详细解释:
//该函数的作用是向 PropertyList 对象中添加一个布尔类型的属性。 void AddBooleanProperty(const std::string& name, const std::string& description, std::function<bool()> getter) { properties_.push_back(Property(name, description, getter)); } void AddNumberProperty(const std::string& name, const std::string& description, std::function<int()> getter) { properties_.push_back(Property(name, description, getter)); } void AddStringProperty(const std::string& name, const std::string& description, std::function<std::string()> getter) { properties_.push_back(Property(name, description, getter)); }
选中的代码是 PropertyList 类中的 operator[] 重载函数,其主要功能是通过属性名称来获取 Property 对象的常量引用。
const Property&:函数返回一个Property对象的常量引用。使用常量引用意味着调用者不能修改返回的Property对象,同时避免了对象的复制,提高性能。operator[]:这是对[]运算符的重载,使得PropertyList对象可以像数组或std::map一样,通过[]运算符来访问其中的元素。const std::string& name:传入的参数是一个常量引用类型的字符串,代表要查找的属性名称。使用常量引用可以避免不必要的字符串复制,提高性能。const:函数末尾的const关键字表明这是一个常量成员函数,意味着该函数不会修改调用对象的任何成员变量。
const Property& operator[](const std::string& name) const { for (auto& property : properties_) { if (property.name() == name) { return property; } } throw std::runtime_error("Property not found: " + name); }
std::string GetDescriptorJson() { std::string json_str = "{"; for (auto& property : properties_) { //对于每个 Property 对象,将其名称用双引号包裹,后面加上 :,接着调用 property.GetDescriptorJson() 方法获取该属性的描述信息 JSON 字符串,最后添加逗号 ,,并将这些内容追加到 json_str 中。 json_str += "\"" + property.name() + "\":" + property.GetDescriptorJson() + ","; } //检查 json_str 的最后一个字符是否为逗号 ,,如果是,则使用 pop_back() 方法移除该逗号,以保证生成的 JSON 字符串格式正确。 if (json_str.back() == ',') { json_str.pop_back(); } json_str += "}"; return json_str; }
假设 PropertyList 中有两个属性,一个布尔类型属性 power 和一个数值类型属性 temperature,生成的 JSON 字符串可能如下:
{
"power": true,
"temperature": 25
}
//选中的代码是 PropertyList 类里的 GetStateJson 成员函数,其功能是生成一个包含所有属性当前状态信息的 JSON 对象字符串。 std::string GetStateJson() { std::string json_str = "{"; for (auto& property : properties_) { json_str += "\"" + property.name() + "\":" + property.GetStateJson() + ","; } if (json_str.back() == ',') { json_str.pop_back(); } json_str += "}"; return json_str; } };
parameter类
class Parameter { private: std::string name_; std::string description_; ValueType type_; bool required_; bool boolean_; int number_; std::string string_;
class Parameter { private: std::string name_; std::string description_; ValueType type_; bool required_; bool boolean_; int number_; std::string string_; public: //选中的代码是 Parameter 类的构造函数,其作用是创建 Parameter 对象并初始化其成员变量。下面详细解释: Parameter(const std::string& name, const std::string& description, ValueType type, bool required = true) : name_(name), description_(description), type_(type), required_(required) {} //选中的代码是 Parameter 类中的两个成员函数,它们均为常量成员函数,作用是获取 Parameter 对象的名称和描述信息。 const std::string& name() const { return name_; } const std::string& description() const { return description_; } ValueType type() const { return type_; } bool required() const { return required_; } bool boolean() const { return boolean_; } int number() const { return number_; } const std::string& string() const { return string_; } void set_boolean(bool value) { boolean_ = value; } void set_number(int value) { number_ = value; } void set_string(const std::string& value) { string_ = value; } //选中的代码是 Parameter 类的 GetDescriptorJson 成员函数,其功能是生成一个描述当前 Parameter 对象信息的 JSON 字符串。 //{"description":"Enable the device","type":"boolean"} 假设 Parameter 对象的名称为 enable,描述信息为 "Enable the device",类型为布尔类型,生成的 JSON 字符串如下: std::string GetDescriptorJson() { std::string json_str = "{"; json_str += "\"description\":\"" + description_ + "\","; if (type_ == kValueTypeBoolean) { json_str += "\"type\":\"boolean\""; } else if (type_ == kValueTypeNumber) { json_str += "\"type\":\"number\""; } else if (type_ == kValueTypeString) { json_str += "\"type\":\"string\""; } json_str += "}"; return json_str; } };
选中的代码是 ParameterList 类中的 operator[] 运算符重载函数,其主要功能是通过参数名称来获取 Parameter 对象的常量引用。
该函数为 ParameterList 类提供了一种便捷的参数访问方式,允许用户通过参数名称来获取对应的 Parameter 对象。若参数存在,返回其常量引用;若不存在,则抛出异常。示例使用如下:
选中的代码是 ParameterList 类中的 operator[] 运算符重载函数,其主要功能是通过参数名称来获取 Parameter 对象的常量引用。
- 调用
parameter对象的name()成员函数获取其名称,并与传入的name参数进行比较。 - 如果名称匹配,则返回该
Parameter对象的常量引用。
class ParameterList { private: std::vector<Parameter> parameters_; public: ParameterList() = default; ParameterList(const std::vector<Parameter>& parameters) : parameters_(parameters) {} void AddParameter(const Parameter& parameter) { parameters_.push_back(parameter); } const Parameter& operator[](const std::string& name) const { for (auto& parameter : parameters_) { if (parameter.name() == name) { return parameter; } } throw std::runtime_error("Parameter not found: " + name); } // iterator auto begin() { return parameters_.begin(); } auto end() { return parameters_.end(); } std::string GetDescriptorJson() { std::string json_str = "{"; for (auto& parameter : parameters_) { json_str += "\"" + parameter.name() + "\":" + parameter.GetDescriptorJson() + ","; } if (json_str.back() == ',') { json_str.pop_back(); } json_str += "}"; return json_str; } };
Method类
class Method { private: std::string name_; std::string description_; ParameterList parameters_; std::function<void(const ParameterList&)> callback_;
还带一个回调参数
description和parameter两个层次了
class Method { private: std::string name_; std::string description_; ParameterList parameters_; std::function<void(const ParameterList&)> callback_; public: //选中的代码是 Method 类的构造函数,作用是创建 Method 类的对象并初始化其成员变量。 Method(const std::string& name, const std::string& description, const ParameterList& parameters, std::function<void(const ParameterList&)> callback) : name_(name), description_(description), parameters_(parameters), callback_(callback) {} const std::string& name() const { return name_; } const std::string& description() const { return description_; } ParameterList& parameters() { return parameters_; } //选中的代码是 Method 类里的 GetDescriptorJson 成员函数,其作用是生成一个描述当前 Method 对象信息的 JSON 字符串。 // std::string GetDescriptorJson() { std::string json_str = "{"; json_str += "\"description\":\"" + description_ + "\","; json_str += "\"parameters\":" + parameters_.GetDescriptorJson(); json_str += "}"; return json_str; } void Invoke() { callback_(parameters_); } };
假设 Method 对象的描述信息为 "This is an example method",其参数列表包含一个名为 enable 的布尔类型参数,生成的 JSON 字符串如下
{ "description":"This is an example method", "parameters":{ "enable":{ "description":"Enable the device", "type":"boolean" } } }
方法列表
选中的代码是 MethodList 类里的 AddMethod 成员函数,其功能是向 MethodList 对象添加一个新的 Method 对象。
class MethodList { private: std::vector<Method> methods_; public: MethodList() = default; MethodList(const std::vector<Method>& methods) : methods_(methods) {} void AddMethod(const std::string& name, const std::string& description, const ParameterList& parameters, std::function<void(const ParameterList&)> callback) { methods_.push_back(Method(name, description, parameters, callback)); } Method& operator[](const std::string& name) { for (auto& method : methods_) { if (method.name() == name) { return method; } } throw std::runtime_error("Method not found: " + name); } std::string GetDescriptorJson() { std::string json_str = "{"; for (auto& method : methods_) { json_str += "\"" + method.name() + "\":" + method.GetDescriptorJson() + ","; } if (json_str.back() == ',') { json_str.pop_back(); } json_str += "}"; return json_str; } };
Thing类型
虽然是核心类,但是没什么好注释的
class Thing { public: Thing(const std::string& name, const std::string& description) : name_(name), description_(description) {} virtual ~Thing() = default; virtual std::string GetDescriptorJson(); virtual std::string GetStateJson(); virtual void Invoke(const cJSON* command); const std::string& name() const { return name_; } const std::string& description() const { return description_; } protected: PropertyList properties_; MethodList methods_; private: std::string name_; std::string description_; };
这段代码定义了两个函数声明和一个宏,用于实现 Thing 类及其派生类的动态注册与创建功能。
void RegisterThing(const std::string& type, std::function<Thing*()> creator); Thing* CreateThing(const std::string& type); #define DECLARE_THING(TypeName) \ static iot::Thing* Create##TypeName() { \ return new iot::TypeName(); \ } \ static bool Register##TypeNameHelper = []() { \ RegisterThing(#TypeName, Create##TypeName); \ return true; \ }(); } // namespace iot #endif // THING_H
- 功能:将
Thing类或其派生类的类型名和对应的创建函数注册到系统中,方便后续根据类型名动态创建对象。 - 参数:
const std::string& type:表示Thing类或其派生类的类型名,使用常量引用避免字符串复制。std::function<Thing*()> creator:一个函数对象,该对象不接受参数,返回一个Thing*指针,用于创建对应类型的对象。
浙公网安备 33010602011771号