mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-09-13 01:56:19 +00:00
This is a macro for: ``` #define addLogMove(L, S) addToLogMove(L, std::move(S)) ``` This will then try to move the constructed string to the log buffer. If it cannot be moved (e.g. log level is not active), the string will be cleared to free up memory.
321 lines
9.4 KiB
C++
321 lines
9.4 KiB
C++
#include "src/Helpers/_CPlugin_Helper.h"
|
|
#ifdef USES_C013
|
|
|
|
# include "src/Globals/Nodes.h"
|
|
# include "src/DataStructs/C013_p2p_dataStructs.h"
|
|
# include "src/ESPEasyCore/ESPEasyRules.h"
|
|
# include "src/Helpers/Misc.h"
|
|
# include "src/Helpers/Network.h"
|
|
|
|
// #######################################################################################################
|
|
// ########################### Controller Plugin 013: ESPEasy P2P network ################################
|
|
// #######################################################################################################
|
|
|
|
# define CPLUGIN_013
|
|
# define CPLUGIN_ID_013 13
|
|
# define CPLUGIN_NAME_013 "ESPEasy P2P Networking"
|
|
|
|
WiFiUDP C013_portUDP;
|
|
|
|
// Forward declarations
|
|
void C013_SendUDPTaskInfo(uint8_t destUnit, uint8_t sourceTaskIndex, uint8_t destTaskIndex);
|
|
void C013_SendUDPTaskData(uint8_t destUnit, uint8_t sourceTaskIndex, uint8_t destTaskIndex);
|
|
void C013_sendUDP(uint8_t unit, const uint8_t *data, uint8_t size);
|
|
void C013_Receive(struct EventStruct *event);
|
|
|
|
|
|
bool CPlugin_013(CPlugin::Function function, struct EventStruct *event, String& string)
|
|
{
|
|
bool success = false;
|
|
|
|
switch (function)
|
|
{
|
|
case CPlugin::Function::CPLUGIN_PROTOCOL_ADD:
|
|
{
|
|
Protocol[++protocolCount].Number = CPLUGIN_ID_013;
|
|
Protocol[protocolCount].usesMQTT = false;
|
|
Protocol[protocolCount].usesTemplate = false;
|
|
Protocol[protocolCount].usesAccount = false;
|
|
Protocol[protocolCount].usesPassword = false;
|
|
Protocol[protocolCount].defaultPort = 65501;
|
|
Protocol[protocolCount].usesID = false;
|
|
Protocol[protocolCount].Custom = true;
|
|
break;
|
|
}
|
|
|
|
case CPlugin::Function::CPLUGIN_GET_DEVICENAME:
|
|
{
|
|
string = F(CPLUGIN_NAME_013);
|
|
break;
|
|
}
|
|
|
|
case CPlugin::Function::CPLUGIN_TASK_CHANGE_NOTIFICATION:
|
|
{
|
|
C013_SendUDPTaskInfo(0, event->TaskIndex, event->TaskIndex);
|
|
break;
|
|
}
|
|
|
|
case CPlugin::Function::CPLUGIN_PROTOCOL_SEND:
|
|
{
|
|
C013_SendUDPTaskData(0, event->TaskIndex, event->TaskIndex);
|
|
break;
|
|
}
|
|
|
|
case CPlugin::Function::CPLUGIN_UDP_IN:
|
|
{
|
|
C013_Receive(event);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
case CPlugin::Function::CPLUGIN_FLUSH:
|
|
{
|
|
process_c013_delay_queue(event->ControllerIndex);
|
|
delay(0);
|
|
break;
|
|
}
|
|
*/
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
// ********************************************************************************
|
|
// Generic UDP message
|
|
// ********************************************************************************
|
|
void C013_SendUDPTaskInfo(uint8_t destUnit, uint8_t sourceTaskIndex, uint8_t destTaskIndex)
|
|
{
|
|
if (!NetworkConnected(10)) {
|
|
return;
|
|
}
|
|
|
|
if (!validTaskIndex(sourceTaskIndex) || !validTaskIndex(destTaskIndex)) {
|
|
return;
|
|
}
|
|
pluginID_t pluginID = Settings.TaskDeviceNumber[sourceTaskIndex];
|
|
|
|
if (!validPluginID_fullcheck(pluginID)) {
|
|
return;
|
|
}
|
|
|
|
struct C013_SensorInfoStruct infoReply;
|
|
|
|
infoReply.sourceUnit = Settings.Unit;
|
|
infoReply.sourceTaskIndex = sourceTaskIndex;
|
|
infoReply.destTaskIndex = destTaskIndex;
|
|
infoReply.deviceNumber = pluginID;
|
|
LoadTaskSettings(infoReply.sourceTaskIndex);
|
|
safe_strncpy(infoReply.taskName, getTaskDeviceName(infoReply.sourceTaskIndex), sizeof(infoReply.taskName));
|
|
|
|
for (uint8_t x = 0; x < VARS_PER_TASK; x++) {
|
|
safe_strncpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x], sizeof(infoReply.ValueNames[x]));
|
|
}
|
|
|
|
if (destUnit != 0)
|
|
{
|
|
infoReply.destUnit = destUnit;
|
|
C013_sendUDP(destUnit, reinterpret_cast<const uint8_t *>(&infoReply), sizeof(C013_SensorInfoStruct));
|
|
delay(10);
|
|
} else {
|
|
for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it) {
|
|
if (it->first != Settings.Unit) {
|
|
infoReply.destUnit = it->first;
|
|
C013_sendUDP(it->first, reinterpret_cast<const uint8_t *>(&infoReply), sizeof(C013_SensorInfoStruct));
|
|
delay(10);
|
|
}
|
|
}
|
|
}
|
|
delay(50);
|
|
}
|
|
|
|
void C013_SendUDPTaskData(uint8_t destUnit, uint8_t sourceTaskIndex, uint8_t destTaskIndex)
|
|
{
|
|
if (!NetworkConnected(10)) {
|
|
return;
|
|
}
|
|
struct C013_SensorDataStruct dataReply;
|
|
|
|
dataReply.sourceUnit = Settings.Unit;
|
|
dataReply.sourceTaskIndex = sourceTaskIndex;
|
|
dataReply.destTaskIndex = destTaskIndex;
|
|
|
|
for (uint8_t x = 0; x < VARS_PER_TASK; x++) {
|
|
const userVarIndex_t userVarIndex = dataReply.sourceTaskIndex * VARS_PER_TASK + x;
|
|
|
|
if (validUserVarIndex(userVarIndex)) {
|
|
dataReply.Values[x] = UserVar[userVarIndex];
|
|
}
|
|
}
|
|
|
|
if (destUnit != 0)
|
|
{
|
|
dataReply.destUnit = destUnit;
|
|
C013_sendUDP(destUnit, reinterpret_cast<const uint8_t *>(&dataReply), sizeof(C013_SensorDataStruct));
|
|
delay(10);
|
|
} else {
|
|
for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it) {
|
|
if (it->first != Settings.Unit) {
|
|
dataReply.destUnit = it->first;
|
|
C013_sendUDP(it->first, reinterpret_cast<const uint8_t *>(&dataReply), sizeof(C013_SensorDataStruct));
|
|
delay(10);
|
|
}
|
|
}
|
|
}
|
|
delay(50);
|
|
}
|
|
|
|
/*********************************************************************************************\
|
|
Send UDP message (unit 255=broadcast)
|
|
\*********************************************************************************************/
|
|
void C013_sendUDP(uint8_t unit, const uint8_t *data, uint8_t size)
|
|
{
|
|
if (!NetworkConnected(10)) {
|
|
return;
|
|
}
|
|
NodesMap::iterator it;
|
|
|
|
if (unit != 255) {
|
|
it = Nodes.find(unit);
|
|
|
|
if (it == Nodes.end()) {
|
|
return;
|
|
}
|
|
|
|
if (it->second.ip[0] == 0) {
|
|
return;
|
|
}
|
|
}
|
|
# ifndef BUILD_NO_DEBUG
|
|
|
|
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
|
|
String log = F("C013 : Send UDP message to ");
|
|
log += unit;
|
|
addLogMove(LOG_LEVEL_DEBUG_MORE, log);
|
|
}
|
|
# endif // ifndef BUILD_NO_DEBUG
|
|
|
|
statusLED(true);
|
|
|
|
IPAddress remoteNodeIP;
|
|
|
|
if (unit == 255) {
|
|
remoteNodeIP = { 255, 255, 255, 255 };
|
|
}
|
|
else {
|
|
remoteNodeIP = it->second.ip;
|
|
}
|
|
|
|
if (!beginWiFiUDP_randomPort(C013_portUDP)) { return; }
|
|
|
|
FeedSW_watchdog();
|
|
if (C013_portUDP.beginPacket(remoteNodeIP, Settings.UDPPort) == 0) { return; }
|
|
C013_portUDP.write(data, size);
|
|
C013_portUDP.endPacket();
|
|
C013_portUDP.stop();
|
|
FeedSW_watchdog();
|
|
delay(0);
|
|
}
|
|
|
|
void C013_Receive(struct EventStruct *event) {
|
|
if (event->Par2 < 6) { return; }
|
|
# ifndef BUILD_NO_DEBUG
|
|
|
|
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
|
|
if ((event->Data != nullptr) &&
|
|
(event->Data[1] > 1) && (event->Data[1] < 6))
|
|
{
|
|
String log = (F("C013 : msg "));
|
|
|
|
for (uint8_t x = 1; x < 6; x++)
|
|
{
|
|
log += ' ';
|
|
log += static_cast<int>(event->Data[x]);
|
|
}
|
|
addLogMove(LOG_LEVEL_DEBUG_MORE, log);
|
|
}
|
|
}
|
|
# endif // ifndef BUILD_NO_DEBUG
|
|
|
|
switch (event->Data[1]) {
|
|
case 2: // sensor info pull request
|
|
{
|
|
// SendUDPTaskInfo(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
|
break;
|
|
}
|
|
|
|
case 3: // sensor info
|
|
{
|
|
struct C013_SensorInfoStruct infoReply;
|
|
int count = sizeof(C013_SensorInfoStruct);
|
|
|
|
if (event->Par2 < count) { count = event->Par2; }
|
|
|
|
memcpy(reinterpret_cast<uint8_t *>(&infoReply), event->Data, count);
|
|
|
|
if (infoReply.isValid()) {
|
|
// to prevent flash wear out (bugs in communication?) we can only write to an empty task
|
|
// so it will write only once and has to be cleared manually through webgui
|
|
// Also check the receiving end does support the plugin ID.
|
|
if (!validPluginID_fullcheck(Settings.TaskDeviceNumber[infoReply.destTaskIndex]) &&
|
|
supportedPluginID(infoReply.deviceNumber))
|
|
{
|
|
taskClear(infoReply.destTaskIndex, false);
|
|
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
|
|
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = infoReply.sourceUnit; // remote feed store unit nr sending the data
|
|
|
|
for (controllerIndex_t x = 0; x < CONTROLLER_MAX; x++) {
|
|
Settings.TaskDeviceSendData[x][infoReply.destTaskIndex] = false;
|
|
}
|
|
safe_strncpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName, sizeof(infoReply.taskName));
|
|
|
|
for (uint8_t x = 0; x < VARS_PER_TASK; x++) {
|
|
safe_strncpy(ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x], sizeof(infoReply.ValueNames[x]));
|
|
}
|
|
ExtraTaskSettings.TaskIndex = infoReply.destTaskIndex;
|
|
SaveTaskSettings(infoReply.destTaskIndex);
|
|
SaveSettings();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 4: // sensor data pull request
|
|
{
|
|
// SendUDPTaskData(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
|
break;
|
|
}
|
|
|
|
case 5: // sensor data
|
|
{
|
|
struct C013_SensorDataStruct dataReply;
|
|
int count = sizeof(C013_SensorDataStruct);
|
|
|
|
if (event->Par2 < count) { count = event->Par2; }
|
|
memcpy(reinterpret_cast<uint8_t *>(&dataReply), event->Data, count);
|
|
|
|
if (dataReply.isValid()) {
|
|
// only if this task has a remote feed, update values
|
|
const uint8_t remoteFeed = Settings.TaskDeviceDataFeed[dataReply.destTaskIndex];
|
|
|
|
if ((remoteFeed != 0) && (remoteFeed == dataReply.sourceUnit))
|
|
{
|
|
for (uint8_t x = 0; x < VARS_PER_TASK; x++)
|
|
{
|
|
UserVar[dataReply.destTaskIndex * VARS_PER_TASK + x] = dataReply.Values[x];
|
|
}
|
|
|
|
if (Settings.UseRules) {
|
|
struct EventStruct TempEvent(dataReply.destTaskIndex);
|
|
createRuleEvents(&TempEvent);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // ifdef USES_C013
|