feat: 全量同步 254 个常用的 Arduino 扩展库文件
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
#ifndef _PAINLESS_MESH_PLUGIN_PERFORMANCE_HPP_
|
||||
#define _PAINLESS_MESH_PLUGIN_PERFORMANCE_HPP_
|
||||
|
||||
#include "painlessmesh/configuration.hpp"
|
||||
|
||||
#include "painlessmesh/logger.hpp"
|
||||
#include "painlessmesh/plugin.hpp"
|
||||
|
||||
namespace painlessmesh {
|
||||
namespace plugin {
|
||||
/** Add performance tracking to the mesh
|
||||
*
|
||||
* Nodes will send out special packages to each other, allowing each node to
|
||||
* keep track of different performance measures
|
||||
*/
|
||||
namespace performance {
|
||||
|
||||
/** Track mean and variance of the given value
|
||||
*
|
||||
* Older values are discounted, so that you keep a rolling average
|
||||
*/
|
||||
class Stats {
|
||||
public:
|
||||
void update(double v, double alpha = 0.1) {
|
||||
if (!init) {
|
||||
mu = v;
|
||||
init = true;
|
||||
return;
|
||||
}
|
||||
auto d = v - mu;
|
||||
mu = mu + alpha * d;
|
||||
var = (1 - alpha) * (var + alpha * pow(d, 2));
|
||||
}
|
||||
|
||||
// Returns the mean and 95% interval based on 1.96*sd? or 2.96*sd
|
||||
TSTRING toString() const {
|
||||
#ifdef PAINLESSMESH_ENABLE_STD_STRING
|
||||
std::stringstream ss;
|
||||
ss << mu << "[" << mu - 1.96 * sqrt(var) << "," << mu + 1.96 * sqrt(var)
|
||||
<< "]";
|
||||
return ss.str();
|
||||
#else
|
||||
return TSTRING(mu) + TSTRING("[") + TSTRING(mu - 1.96 * sqrt(var)) +
|
||||
TSTRING(",") + TSTRING(mu + 1.96 * sqrt(var)) + TSTRING("]");
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
double mu = 0;
|
||||
double var = 0;
|
||||
bool init = false;
|
||||
};
|
||||
|
||||
class PerformancePackage : public plugin::BroadcastPackage {
|
||||
public:
|
||||
int id = 0; // Can see if we missed values
|
||||
int time; // Get an idea of the delay, by comparing it with nodetime
|
||||
int stability; // stability of the sending node
|
||||
int freeMemory; // memory of the sending node
|
||||
#ifdef ESP32
|
||||
TSTRING hardware = "ESP32";
|
||||
#else
|
||||
TSTRING hardware = "ESP8266";
|
||||
#endif
|
||||
PerformancePackage() : plugin::BroadcastPackage(13) {}
|
||||
|
||||
PerformancePackage(JsonObject jsonObj) : plugin::BroadcastPackage(jsonObj) {
|
||||
id = jsonObj["id"];
|
||||
time = jsonObj["time"];
|
||||
stability = jsonObj["stability"];
|
||||
freeMemory = jsonObj["freeMemory"];
|
||||
hardware = jsonObj["hardware"].as<TSTRING>();
|
||||
}
|
||||
|
||||
JsonObject addTo(JsonObject&& jsonObj) const {
|
||||
jsonObj = BroadcastPackage::addTo(std::move(jsonObj));
|
||||
jsonObj["type"] = type;
|
||||
jsonObj["id"] = id;
|
||||
jsonObj["time"] = time;
|
||||
jsonObj["stability"] = stability;
|
||||
jsonObj["freeMemory"] = freeMemory;
|
||||
jsonObj["hardware"] = hardware;
|
||||
return jsonObj;
|
||||
}
|
||||
|
||||
size_t jsonObjectSize() const {
|
||||
return JSON_OBJECT_SIZE(4 + 5) + round(2 * (hardware.length()));
|
||||
}
|
||||
};
|
||||
|
||||
/// Numbers to track for each node we receive PerformancePackages from
|
||||
class Track {
|
||||
public:
|
||||
uint32_t nodeId;
|
||||
TSTRING hardware;
|
||||
uint32_t hits = 0;
|
||||
uint32_t misses = 0;
|
||||
int lastId = 0;
|
||||
Stats delay;
|
||||
Stats stability;
|
||||
Stats freeMemory;
|
||||
uint32_t present = 0; // Every so often check if each node is absent or
|
||||
// present in the layout
|
||||
uint32_t absent = 0;
|
||||
Track() {}
|
||||
|
||||
void addTo(JsonObject& jsonObj) const {
|
||||
jsonObj["nodeId"] = nodeId;
|
||||
jsonObj["hardware"] = hardware;
|
||||
jsonObj["hits"] = hits;
|
||||
jsonObj["misses"] = misses;
|
||||
jsonObj["delay"] = delay.toString();
|
||||
jsonObj["stability"] = stability.toString();
|
||||
jsonObj["freeMemory"] = freeMemory.toString();
|
||||
jsonObj["present"] = present;
|
||||
jsonObj["absent"] = absent;
|
||||
}
|
||||
};
|
||||
|
||||
/// Holds resulst from all the nodes
|
||||
class TrackMap : public protocol::PackageInterface,
|
||||
public std::map<uint32_t, Track> {
|
||||
public:
|
||||
JsonObject addTo(JsonObject&& jsonObj) const {
|
||||
jsonObj["event"] = "performance";
|
||||
// Start array
|
||||
auto jsonArr = jsonObj.createNestedArray("nodes");
|
||||
// for each in map do
|
||||
for (auto&& pair : (*this)) {
|
||||
auto obj = jsonArr.createNestedObject();
|
||||
pair.second.addTo(obj);
|
||||
}
|
||||
return jsonObj;
|
||||
} // namespace performance
|
||||
|
||||
size_t jsonObjectSize() const {
|
||||
return JSON_OBJECT_SIZE(2 + 15) + JSON_ARRAY_SIZE(this->size()) +
|
||||
this->size()*(JSON_OBJECT_SIZE(9) + 4 * 100);
|
||||
}
|
||||
}; // namespace plugin
|
||||
|
||||
template <class T>
|
||||
void begin(T& mesh, double frequency = 2) {
|
||||
auto tracker = std::make_shared<TrackMap>();
|
||||
auto sendPkg = std::make_shared<PerformancePackage>();
|
||||
|
||||
mesh.onPackage(sendPkg->type, [&mesh, tracker](protocol::Variant var) {
|
||||
auto pkg = var.to<PerformancePackage>();
|
||||
// if not in tracker, add it
|
||||
if (!tracker->count(pkg.from)) {
|
||||
tracker->operator[](pkg.from) = Track();
|
||||
if (pkg.id > 0) tracker->operator[](pkg.from).lastId = pkg.id - 1;
|
||||
}
|
||||
// update all the values in the trackmap
|
||||
tracker->operator[](pkg.from).nodeId = pkg.from;
|
||||
tracker->operator[](pkg.from).hardware = pkg.hardware;
|
||||
++tracker->operator[](pkg.from).hits;
|
||||
if (pkg.id < tracker->operator[](pkg.from).lastId) // Node was reset?
|
||||
tracker->operator[](pkg.from).lastId = pkg.id;
|
||||
else {
|
||||
tracker->operator[](pkg.from).misses +=
|
||||
(pkg.id - tracker->operator[](pkg.from).lastId) - 1;
|
||||
}
|
||||
tracker->operator[](pkg.from).lastId = pkg.id;
|
||||
tracker->operator[](pkg.from).delay.update(
|
||||
((int)mesh.getNodeTime() - pkg.time) / 1000);
|
||||
tracker->operator[](pkg.from).stability.update(pkg.stability);
|
||||
tracker->operator[](pkg.from).freeMemory.update(pkg.freeMemory);
|
||||
return false;
|
||||
});
|
||||
|
||||
sendPkg->from = mesh.getNodeId();
|
||||
mesh.addTask(frequency*TASK_SECOND, TASK_FOREVER, [sendPkg, &mesh]() {
|
||||
++sendPkg->id;
|
||||
sendPkg->time = mesh.getNodeTime();
|
||||
sendPkg->stability = mesh.stability;
|
||||
sendPkg->freeMemory = ESP.getFreeHeap();
|
||||
mesh.sendPackage(sendPkg.get());
|
||||
});
|
||||
|
||||
mesh.addTask(TASK_MINUTE, TASK_FOREVER, [tracker, &mesh]() {
|
||||
for (auto&& pair : (*tracker)) {
|
||||
if (mesh.isConnected(pair.first))
|
||||
++pair.second.present;
|
||||
else
|
||||
++pair.second.absent;
|
||||
}
|
||||
protocol::Variant var(tracker.get());
|
||||
TSTRING str;
|
||||
var.printTo(str);
|
||||
#ifdef PAINLESSMESH_ENABLE_STD_STRING
|
||||
std::cout << str << std::endl;
|
||||
#else
|
||||
Serial.println(str);
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace performance
|
||||
} // namespace plugin
|
||||
} // namespace painlessmesh
|
||||
#endif
|
||||
Reference in New Issue
Block a user