Revert "tasmota EPS-Now mesh driver"

This reverts commit 90ee6f3995.
This commit is contained in:
Staars 2020-10-20 15:22:23 +02:00
parent 414e5f382c
commit e3d3e76d61
3 changed files with 0 additions and 911 deletions

View File

@ -1,283 +0,0 @@
/*
support_tasmesh.ino - mesh via ESP-Now support for Sonoff-Tasmota
Copyright (C) 2020 Theo Arends & Christian Baars
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------
Version Date Action Description
--------------------------------------------------------------------------------------------
*/
#define USE_TASMESH
#ifdef USE_TASMESH
#include <queue>
#include <t_bearssl_block.h>
#ifdef ESP32
#include <esp_now.h>
#include <esp_wifi.h>
#else
#include <espnow.h> //ESP8266 ... why Espressif, why??
#endif //ESP32
#define MESH_PAYLOAD_SIZE 160 // default 180 - with header of 20 bytes, stays at 200 bytes, which is reported to work with ESP8266
#define MESH_TOPICSZ 64 // max supported topic size
#define MESH_BUFFERS 4 // max buffers number for splitted messages
struct mesh_packet_t{
uint8_t sender[6]; //MAC
uint8_t receiver[6]; //MAC
uint32_t counter:4; //endless counter to identify a packet
uint32_t type:6; //command,mqtt,...
uint32_t chunks:6; //number of chunks
uint32_t chunk:6; //chunk number
uint32_t chunkSize:8; //chunk size
uint32_t TTL:2; //time to live, counting down
union{
uint32_t senderTime; //UTC-timestamp from every sender in the MESH
uint32_t peerIndex; //only for resending in the MESH
};
uint8_t tag[16]; //tag for de/encryption
uint8_t payload[MESH_PAYLOAD_SIZE];
} __attribute__((packed));
struct mesh_packet_header_t{
uint8_t sender[6]; //MAC
uint8_t receiver[6]; //MAC
uint32_t counter:4; //endless counter to identify a packet
uint32_t type:6; //command,mqtt,...
uint32_t chunks:6; //number of chunks
uint32_t chunk:6; //chunk number
uint32_t chunkSize:8; //chunk size
uint32_t TTL:2; //time to live, counting down
union{
uint32_t senderTime; //UTC-timestamp from every sender in the MESH
uint32_t peerIndex; //only for resending in the MESH
};
uint8_t tag[16]; //tag for de/encryption
} __attribute__((packed));
struct mesh_peer_t{
uint8_t MAC[6];
uint32_t lmfp; //time of last message from peer
#ifdef ESP32
char topic[MESH_TOPICSZ];
#endif //ESP32
};
struct mesh_broker_flags_t{
uint8_t brokerNeedsTopic:1;
};
struct mesh_packet_combined_t{
mesh_packet_header_t header;
uint8_t receivedChunks;
char raw[MESH_PAYLOAD_SIZE*6];
};
struct{
uint8_t broker[6];
uint8_t role;
uint8_t channel; //Wifi channel
uint8_t counter; //for every message
uint32_t lmfb; //time of last message from broker
uint32_t lmfap; //time of last message from any peer
uint8_t pmk[32];
mesh_broker_flags_t flags;
mesh_packet_t sendPacket;
std::vector<mesh_peer_t> peers;
std::queue<mesh_packet_t> packetToResend;
std::queue<mesh_packet_t> packetToConsume;
std::vector<mesh_packet_header_t> packetsAlreadySended;
std::vector<mesh_packet_combined_t> multiPackets;
}MESH;
/*********************************************************************************************\
* declarations for functions with custom types
\*********************************************************************************************/
void MESHsendPacket(mesh_packet_t *_packet);
bool MESHencryptPayload(mesh_packet_t *_packet, int _encrypt); // 1 encryption; 0 decryption
/*********************************************************************************************\
* enumerations
\*********************************************************************************************/
enum MESH_Role {
ROLE_NONE = 0, // not initialized
ROLE_BROKER, // ESP32 will connect mesh to WLAN
ROLE_NODE_SMALL, // Node will only talk to the broker
ROLE_NODE_FULL // Node will listen and resend every message for MESH functionality
};
enum MESH_Packet_Type { // Type of packet
PACKET_TYPE_TIME = 0, //
PACKET_TYPE_SENSOR, //
PACKET_TYPE_COMMAND, //
PACKET_TYPE_TOPIC, // announce mqtt topic to ESP32-proxy
PACKET_TYPE_MQTT //
};
/*********************************************************************************************\
*
\*********************************************************************************************/
#ifdef ESP32
void MESHsendTime(uint32_t _peerNumber){ //only from broker to nodes
MESH.sendPacket.counter++;
MESH.sendPacket.type = PACKET_TYPE_TIME;
MESH.sendPacket.TTL = 3;
memcpy(MESH.sendPacket.receiver,MESH.peers[_peerNumber].MAC,6);
MESH.sendPacket.senderTime = Rtc.utc_time;
MESH.sendPacket.payload[0] = 0;
mesh_broker_flags_t *_flags = (mesh_broker_flags_t *)MESH.sendPacket.payload;
if(MESH.peers[_peerNumber].topic[0]==0){
AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: broker wants topic from peer: %u"), _peerNumber);
_flags->brokerNeedsTopic = 1;
}
MESH.sendPacket.chunkSize = 0;
MESHsendPacket(&MESH.sendPacket);
// esp_now_send(MESH.sendPacket.receiver, (uint8_t *)&MESH.sendPacket, sizeof(MESH.sendPacket)-MESH_PAYLOAD_SIZE+1);
}
#endif //ESP32
void MESHcheckPeerList(const uint8_t *MAC){
for(auto &_peer : MESH.peers){
if(memcmp(_peer.MAC,MAC,6)==0){
_peer.lmfp = millis();
return;
}
}
MESHaddPeer((uint8_t *)MAC);
}
void MESHcountPeers(void){
#ifdef ESP32
esp_now_peer_num_t _num;
esp_now_get_peer_num(&_num);
AddLog_P2(LOG_LEVEL_INFO, PSTR("TAS-MESH peers: %u"),_num.total_num);
#else
uint8_t _num;
uint8_t _numEnc;
esp_now_get_cnt_info(&_num,&_numEnc);
AddLog_P2(LOG_LEVEL_INFO, PSTR("TAS-MESH peers: %u"),_num);
#endif
}
void MESHaddPeer(uint8_t *_MAC ){
mesh_peer_t _newPeer;
memcpy(_newPeer.MAC,_MAC,6);
_newPeer.lmfp = millis();
#ifdef ESP32
_newPeer.topic[0] = 0;
#endif
MESH.peers.push_back(_newPeer);
int err;
#ifdef ESP32
esp_now_peer_info_t _peer;
_peer.channel = WiFi.channel();
_peer.encrypt = false;
_peer.ifidx = ESP_IF_WIFI_AP;
memcpy(_peer.peer_addr, _MAC, 6);
err = esp_now_add_peer(&_peer);
#else
err = esp_now_add_peer(_MAC, ESP_NOW_ROLE_COMBO, MESH.channel, NULL, 0);
#endif
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MESH: peer added, err: %d"), err);
AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t *)_MAC,6);
#ifdef ESP32
if(MESH.role == ROLE_BROKER) MESHsendTime(MESH.peers.size()-1);
#endif //ESP32
}
//helper functions
void MESHstripColon(char* _string){
uint32_t _length = strlen(_string);
uint32_t _index = 0;
while (_index < _length) {
char c = _string[_index];
if(c==':'){
memmove(_string+_index,_string+_index+1,_length-_index);
}
_index++;
}
_string[_index] = 0;
}
void MESHMACStringToBytes(char* _string,uint8_t _MAC[]) { //uppercase
uint32_t index = 0;
uint32_t _end = 12;
while (index < _end) {
char c = _string[index];
uint8_t value = 0;
if(c >= '0' && c <= '9')
value = (c - '0');
else if (c >= 'A' && c <= 'F')
value = (10 + (c - 'A'));
_MAC[(index/2)] += value << (((index + 1) % 2) * 4);
index++;
}
}
void MESHsendPacket(mesh_packet_t *_packet){
MESHencryptPayload(_packet,1);
esp_now_send(_packet->receiver, (uint8_t *)_packet, sizeof(MESH.sendPacket) - MESH_PAYLOAD_SIZE + _packet->chunkSize);
}
void MESHsetPMK(uint8_t* _key){ // must be 32 bytes!!!
char* _pw = SettingsText(SET_STAPWD1 + Settings.sta_active);
size_t _length = strlen(_pw);
memset(_key,0,32);
if(_length>32) _length = 32;
memcpy(_key,_pw,_length);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MESH: set crypto key to PASSWORD1"));
}
bool MESHencryptPayload(mesh_packet_t *_packet, int _encrypt){
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MESH: will encrypt: %u"), _encrypt);
size_t _size = _packet->chunkSize;
char _tag[16];
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("cc: %u, _size: %u"), _counter,_size);
// AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*)_tag,16);
br_chacha20_run bc = br_chacha20_ct_run;
br_poly1305_ctmul32_run((void*)MESH.pmk, (const void *)_packet,
(void *)_packet->payload, _size, (void*)&_packet->senderTime, 4,
_tag, bc, _encrypt);
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MESH: encryption done "));
if(_encrypt==1){
memcpy(_packet->tag,_tag,16);
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MESH: payload encrypted"));
return true;
}
if(memcmp(_packet->tag,_tag,16)==0){
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MESH: payload decrypted"));
return true;
}
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MESH: payload decryption error"));
return false;
}
#endif //USE_TASMESH

View File

@ -214,13 +214,6 @@ bool MqttPublishLib(const char* topic, bool retained)
mqtt_cmnd_blocked++;
}
}
#ifdef USE_TASMESH
if(MESH.role == ROLE_NODE_SMALL){
MESHredirectMQTT(topic, mqtt_data, retained);
yield();
return true;
}
#endif //USE_TASMESH
bool result = MqttClient.publish(topic, mqtt_data, retained);
yield(); // #3313
@ -252,14 +245,6 @@ void MqttDataHandler(char* mqtt_topic, uint8_t* mqtt_data, unsigned int data_len
char data[data_len +1];
memcpy(data, mqtt_data, sizeof(data));
#ifdef USE_TASMESH
#ifdef ESP32
if(MESH.role == ROLE_BROKER){
if (MESHinterceptMQTT(topic, (uint8_t*)data, data_len+1)) return;
}
#endif //ESP32
#endif //USE_TASMESH
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_MQTT D_RECEIVED_TOPIC " \"%s\", " D_DATA_SIZE " %d, " D_DATA " \"%s\""), topic, data_len, data);
// if (LOG_LEVEL_DEBUG_MORE <= seriallog_level) { Serial.println(data); }

View File

@ -1,613 +0,0 @@
/*
xdrv_44_tasmesh.ino - Mesh support for Tasmota using ESP-Now
Copyright (C) 2020 Christian Baars and Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------
Version yyyymmdd Action Description
--------------------------------------------------------------------------------------------
0.9.0.0 20200927 started - from scratch
*/
#ifdef USE_TASMESH
/*********************************************************************************************\
* Build a mesh of nodes using ESP-Now
* Connect it through an ESP32-broker to WLAN
\*********************************************************************************************/
#define XDRV_44 44
/*********************************************************************************************\
* constants
\*********************************************************************************************/
#define D_CMND_MESH "MESH"
const char S_JSON_MESH_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_MESH "%s\":%d}";
const char S_JSON_MESH_COMMAND[] PROGMEM = "{\"" D_CMND_MESH "%s\"}";
const char kMESH_Commands[] PROGMEM = "Broker|Node|Peer|Channel";
/*********************************************************************************************\
* enumerations
\*********************************************************************************************/
enum MESH_Commands { // commands useable in console or rules
CMND_MESH_BROKER, // start broker on ESP32
CMND_MESH_NODE, // start node and connect to broker based on MAC address
CMND_MESH_PEER, // add node to peer list of a broker or node
CMND_MESH_CHANNEL}; // set wifi channel on node
/*********************************************************************************************\
* Callbacks
\*********************************************************************************************/
#ifdef ESP32
void CB_MESHDataSent(const uint8_t *MAC, esp_now_send_status_t sendStatus);
void CB_MESHDataSent(const uint8_t *MAC, esp_now_send_status_t sendStatus) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BROKER sended packet"));
}
void CB_MESHDataReceived(const uint8_t *MAC, const uint8_t *packet, int len) {
MESH.lmfap = millis();
MESHcheckPeerList((const uint8_t *)MAC);
mesh_packet_t *_recvPacket = (mesh_packet_t*)packet;
MESH.packetToConsume.push(*_recvPacket);
}
#else //ESP8266
void CB_MESHDataSent( uint8_t *MAC, uint8_t sendStatus) {
}
void CB_MESHDataReceived(uint8_t *MAC, uint8_t *packet, uint8_t len) {
MESH.lmfap = millis(); //any peer
if(memcmp(MAC,MESH.broker,6)==0) MESH.lmfb = millis(); //directly from the broker
mesh_packet_t *_recvPacket = (mesh_packet_t*)packet;
if(memcmp(_recvPacket->receiver,MESH.sendPacket.sender,6)!=0){ //MESH.sendPacket.sender simply stores the MAC of the node
//pass packet back to the MESH
_recvPacket->peerIndex = 0;
MESH.packetToResend.push(*_recvPacket);
return;
}
switch(_recvPacket->type){
case PACKET_TYPE_TIME:
Rtc.utc_time = _recvPacket->senderTime;
Rtc.user_time_entry = true;
memcpy((uint8_t*)&MESH.flags,_recvPacket->payload,1);
break;
default:
MESH.packetToConsume.push(*_recvPacket);
break;
}
}
#endif //ESP32
/*********************************************************************************************\
* init driver
\*********************************************************************************************/
void MESHInit(void) {
MESH.role == ROLE_NONE;
AddLog_P2(LOG_LEVEL_INFO, PSTR("TAS-MESH initialized: %u"),Settings.tele_period);
MESH.sendPacket.counter = 0;
MESH.sendPacket.chunks = 1;
MESH.sendPacket.chunk = 0;
MESH.sendPacket.type = PACKET_TYPE_TIME;
MESH.sendPacket.TTL = 2;
}
/*********************************************************************************************\
* MQTT proxy functions
\*********************************************************************************************/
#ifdef ESP32
/**
* @brief Subscribes as a proxy
*
* @param topic - received from the referring node
*/
void MESHsubscribe(char *topic){
char stopic[TOPSZ];
GetTopic_P(stopic, CMND, topic, PSTR("#"));
MqttSubscribe(stopic);
}
void MESHunsubscribe(char *topic){
char stopic[TOPSZ];
GetTopic_P(stopic, CMND, topic, PSTR("#"));
MqttUnsubscribe(stopic);
}
void MESHconnectMQTT(void){
for(auto &_peer : MESH.peers){
AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: reconnect topic: %s"),_peer.topic);
if(_peer.topic[0]!=0){
MESHsubscribe(_peer.topic);
}
}
}
/**
* @brief Intercepts mqtt message, that the broker (ESP32) subscribes to as a proxy for a node.
* Is called from xdrv_02_mqtt.ino. Will send the message in the payload via ESP-NOW.
*
* @param _topic
* @param _data
* @param data_len
* @return true
* @return false
*/
bool MESHinterceptMQTT(char* _topic, uint8_t* _data, unsigned int data_len){
char stopic[TOPSZ];
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MESH: Intercept topic: %s"),_topic);
for(auto &_peer : MESH.peers){
GetTopic_P(stopic, CMND, _peer.topic, PSTR("")); //cmnd/topic/
if(strlen(_topic)!= strlen(_topic)) return false; // prevent false result when _topic is the leading substring of stopic
if(memcmp(_topic, stopic,strlen(stopic)) == 0){
MESH.sendPacket.chunkSize = strlen(_topic)+1;
memcpy(MESH.sendPacket.payload,_topic,MESH.sendPacket.chunkSize);
memcpy(MESH.sendPacket.payload+MESH.sendPacket.chunkSize,_data,data_len);
MESH.sendPacket.chunkSize += data_len;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MESH: Intercept payload: %s"),MESH.sendPacket.payload);
MESH.sendPacket.type = PACKET_TYPE_MQTT;
MESH.sendPacket.senderTime = Rtc.utc_time;
MESHsendPacket(&MESH.sendPacket);
// int result = esp_now_send(MESH.sendPacket.receiver, (uint8_t *)&MESH.sendPacket, (sizeof(MESH.sendPacket))-(MESH_PAYLOAD_SIZE-MESH.sendPacket.chunkSize));
//send to Node
return true;
}
}
return false;
}
#else //ESP8266
void MESHreceiveMQTT(mesh_packet_t *_packet);
void MESHreceiveMQTT(mesh_packet_t *_packet){
uint32_t _slength = strlen((char*)_packet->payload);
if(_packet->chunks==1){ //single chunk message
MqttDataHandler((char*)_packet->payload, (uint8_t*)(_packet->payload)+_slength+1, (_packet->chunkSize)-_slength);
}
else{
AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: multiple chunks: %u"),_packet->chunks);
// TODO: reconstruct message in buffer
}
}
#endif //ESP32
/**
* @brief Redirects the mqtt message on the node just before it would have been sended to
* the broker via ESP-NOW
*
* @param _topic
* @param _data
* @param _retained - currently unused
* @return true
* @return false
*/
bool MESHredirectMQTT(const char* _topic, char* _data, bool _retained){
size_t _bytesLeft = strlen(_topic)+strlen(_data)+2;
MESH.sendPacket.counter++;
MESH.sendPacket.chunk = 0;
MESH.sendPacket.chunks = ((_bytesLeft+2)/MESH_PAYLOAD_SIZE)+1;
memcpy(MESH.sendPacket.receiver,MESH.broker,6);
MESH.sendPacket.type = PACKET_TYPE_MQTT;
MESH.sendPacket.chunkSize = MESH_PAYLOAD_SIZE;
MESH.sendPacket.peerIndex = 0;
AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: chunks: %u, counter: %u"),MESH.sendPacket.chunks,MESH.sendPacket.counter);
size_t _topicSize = strlen(_topic)+1;
size_t _offsetData = 0;
while(_bytesLeft>0){
size_t _byteLeftInChunk = MESH_PAYLOAD_SIZE;
// MESH.sendPacket.chunkSize = MESH_PAYLOAD_SIZE;
if(MESH.sendPacket.chunk == 0){
memcpy(MESH.sendPacket.payload,_topic,_topicSize);
MESH.sendPacket.chunkSize = _topicSize;
_bytesLeft -= _topicSize;
_byteLeftInChunk -= _topicSize;
// AddLog_P2(LOG_LEVEL_INFO, PSTR("topic in payload %s"),(char*)MESH.sendPacket.payload);
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: after topic -> chunk:%u, pre-size: %u"),MESH.sendPacket.chunk,MESH.sendPacket.chunkSize);
}
if(_byteLeftInChunk>0){
if(_byteLeftInChunk>_bytesLeft){
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: only last chunk bL:%u bLiC:%u oSD:%u"),_bytesLeft,_byteLeftInChunk,_offsetData);
_byteLeftInChunk = _bytesLeft;
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: only last chunk after correction -> chunk:%u, pre-size: %u"),MESH.sendPacket.chunk,MESH.sendPacket.chunkSize);
}
if(MESH.sendPacket.chunk>0) _topicSize = 0;
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: %u"),_offsetPayload);
memcpy(MESH.sendPacket.payload + _topicSize, _data + _offsetData,_byteLeftInChunk);
// AddLog_P2(LOG_LEVEL_INFO, PSTR("data in payload %s"),(char*)MESH.sendPacket.payload + _offsetPayload);
_offsetData += _byteLeftInChunk;
_bytesLeft -= _byteLeftInChunk;
}
MESH.sendPacket.chunkSize += _byteLeftInChunk;
MESH.packetToResend.push(MESH.sendPacket);
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: chunk:%u, size: %u"),MESH.sendPacket.chunk,MESH.sendPacket.chunkSize);
// AddLogBuffer(LOG_LEVEL_INFO, (uint8_t*)MESH.sendPacket.payload, MESH.sendPacket.chunkSize);
if(MESH.sendPacket.chunk==MESH.sendPacket.chunks){
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: too many chunks: %u"),MESH.sendPacket.chunk+1);
}
MESH.sendPacket.chunk++;
MESH.sendPacket.chunkSize = 0;
}
//send to pipeline
return true;
}
/**
* @brief The node sends its mqtt topic to the broker
*
*/
void MESHanounceTopic(){
memset(MESH.sendPacket.payload,0,MESH_PAYLOAD_SIZE);
strcpy((char*)MESH.sendPacket.payload,mqtt_topic);
AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: topic: %s"),(char*)MESH.sendPacket.payload);
MESH.sendPacket.chunkSize = strlen((char*)MESH.sendPacket.payload) + 1;
MESH.sendPacket.type = PACKET_TYPE_TOPIC;
MESHsendPacket(&MESH.sendPacket);
// int result = esp_now_send(MESH.sendPacket.receiver, (uint8_t *)&MESH.sendPacket, (sizeof(MESH.sendPacket))-(MESH_PAYLOAD_SIZE-MESH.sendPacket.chunkSize-1));
}
/*********************************************************************************************\
* generic functions
\*********************************************************************************************/
void MESHstartNode(int32_t _channel){
MESH.channel = _channel;
WiFi.mode(WIFI_STA);
WiFi.begin("","",MESH.channel, nullptr, false); //fake connection attempt to set channel
WiFi.disconnect();
if (esp_now_init() != 0) {
return;
}
AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: Node initialized, channel: %u"),MESH.channel);
#ifdef ESP8266
esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
#endif //ESP8266
esp_now_register_send_cb(CB_MESHDataSent);
esp_now_register_recv_cb(CB_MESHDataReceived);
MESHsetPMK(MESH.pmk);
memcpy(MESH.sendPacket.receiver,MESH.broker,6);
WiFi.macAddress(MESH.sendPacket.sender);
MESHaddPeer(MESH.broker); //must always be peer 0!!
MESHcountPeers();
MESH.role = ROLE_NODE_SMALL;
MESHanounceTopic();
}
void MESHstartBroker(){
#ifdef ESP32
WiFi.mode(WIFI_AP_STA);
// WiFi.softAP("SSID_NOW","PASSWORD_NOW",9,1);
// AddLogBuffer(LOG_LEVEL_INFO,(uint8_t *)WiFi.softAPmacAddress(),6);
AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: Broker MAC: %s"),WiFi.softAPmacAddress().c_str());
WiFi.softAPmacAddress(MESH.broker);
uint32_t _channel = WiFi.channel();
esp_wifi_set_promiscuous(true);
esp_wifi_set_channel(_channel, WIFI_SECOND_CHAN_NONE);
esp_wifi_set_promiscuous(false);
if (esp_now_init() != 0) {
return;
}
AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: Broker initialized on channel: %u"), _channel);
esp_now_register_send_cb(CB_MESHDataSent);
esp_now_register_recv_cb(CB_MESHDataReceived);
MESHsetPMK(MESH.pmk);
MESHcountPeers();
memcpy(MESH.sendPacket.sender,MESH.broker,6);
MESH.role = ROLE_BROKER;
#endif //ESP32
}
/*********************************************************************************************\
* main loops
\*********************************************************************************************/
#ifdef ESP32
void MESHevery50MSecond(){
// if(MESH.packetToResend.size()>0){
// // pass the packets
// }
if(MESH.packetToConsume.size()>0){
// do something on the node
MESHencryptPayload(&MESH.packetToConsume.front(),0);
switch(MESH.packetToConsume.front().type){
case PACKET_TYPE_TOPIC:
AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: received topic: %s"), (char*)MESH.packetToConsume.front().payload);
AddLogBuffer(LOG_LEVEL_INFO,(uint8_t *)&MESH.packetToConsume.front().payload,MESH.packetToConsume.front().chunkSize+5);
for(auto &_peer : MESH.peers){
if(memcmp(_peer.MAC,MESH.packetToConsume.front().sender,6)==0){
strcpy(_peer.topic,(char*)MESH.packetToConsume.front().payload);
MESHsubscribe((char*)&_peer.topic);
}
}
break;
// case PACKET_TYPE_SENSOR:
// for(auto &_peer : MESH.peers){
// if(memcmp(_peer.MAC,MESH.packetToConsume.front().sender,6)==0){
// // AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: received sensor output: %s"), (char*)MESH.packetToConsume.front().payload);
// char stopic[MESH_TOPICSZ];
// GetTopic_P(stopic, TELE, _peer.topic, PSTR("SENSOR"));
// MqttClient.publish(stopic, (char*)MESH.packetToConsume.front().payload);
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: topic: %s output: %s"), stopic, (char*)MESH.packetToConsume.front().payload);
// yield(); // #3313
// break;
// }
// }
case PACKET_TYPE_MQTT: // redirected MQTT from node in packet [char* _space_ char*]
{
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: received node output: %s"), (char*)MESH.packetToConsume.front().payload);
if(MESH.packetToConsume.front().chunks>1){
bool _foundMultiPacket = false;
for(auto &_packet_combined : MESH.multiPackets){
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: append to multipacket"));
if(memcmp(_packet_combined.header.sender,MESH.packetToConsume.front().sender,12)==0){
if(_packet_combined.header.counter == MESH.packetToConsume.front().counter){
memcpy(_packet_combined.raw+(MESH.packetToConsume.front().chunk * MESH_PAYLOAD_SIZE),MESH.packetToConsume.front().payload,MESH.packetToConsume.front().chunkSize);
bitSet(_packet_combined.receivedChunks,MESH.packetToConsume.front().chunk);
_foundMultiPacket = true;
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: recChunks= %u"),_packet_combined.receivedChunks);
}
}
uint32_t _temp = (1 << (uint8_t)MESH.packetToConsume.front().chunks)-1 ; //example: 1+2+4 == (2^3)-1
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: _temp: %u = %u"),_temp,_packet_combined.receivedChunks);
if(_packet_combined.receivedChunks==_temp){
char * _data = (char*)_packet_combined.raw + strlen((char*)_packet_combined.raw) + 1;
MqttClient.publish((char*)_packet_combined.raw, _data);
AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: combined done: %s = %s"),(char*)_packet_combined.raw,_data);
// AddLogBuffer(LOG_LEVEL_INFO,(uint8_t*)_packet_combined.raw,50);
}
}
if(!_foundMultiPacket){
mesh_packet_combined_t _packet;
memcpy(_packet.header.sender,MESH.packetToConsume.front().sender,sizeof(_packet.header));
memcpy(_packet.raw+(MESH.packetToConsume.front().chunk*MESH_PAYLOAD_SIZE),MESH.packetToConsume.front().payload,MESH.packetToConsume.front().chunkSize);
_packet.receivedChunks = 0;
bitSet(_packet.receivedChunks,MESH.packetToConsume.front().chunk);
MESH.multiPackets.push_back(_packet);
// AddLog_P2(LOG_LEVEL_INFO, PSTR("new multipacket with chunks: %u"),_packet.header.chunks);
}
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: no support yet for multiple chunks: %u"),MESH.packetToConsume.front().chunks);
break;
}
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: chunk: %u size: %u"), MESH.packetToConsume.front().chunk, MESH.packetToConsume.front().chunkSize);
// if (MESH.packetToConsume.front().chunk==0) AddLogBuffer(LOG_LEVEL_INFO,(uint8_t *)&MESH.packetToConsume.front().payload,MESH.packetToConsume.front().chunkSize);
char * _data = (char*)MESH.packetToConsume.front().payload + strlen((char*)MESH.packetToConsume.front().payload)+1;
MqttClient.publish((char*)MESH.packetToConsume.front().payload, _data);
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: topic: %s output: %s"), (char*)MESH.packetToConsume.front().payload, _data);
// AddLogBuffer(LOG_LEVEL_INFO,(uint8_t *)&MESH.packetToConsume.front().payload,MESH.packetToConsume.front().chunkSize);
yield(); // #3313
}
break;
default:
AddLogBuffer(LOG_LEVEL_INFO,(uint8_t *)&MESH.packetToConsume.front(),MESH.packetToConsume.front().chunkSize+5);
break;
}
MESH.packetToConsume.pop();
}
}
void MESHEverySecond(){
static uint32_t _second = 0;
_second++;
// send a time packet every x seconds
uint32_t _peerNumber = _second%60;
if(_peerNumber<MESH.peers.size()) {
MESHsendTime(_peerNumber);
return;
}
if(MESH.multiPackets.size()>3){
AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: multi packets in buffer: %u"),MESH.multiPackets.size());
MESH.multiPackets.erase(MESH.multiPackets.begin());
}
}
#else //ESP8266
void MESHevery50MSecond(){
if(MESH.packetToResend.size()>0){
uint32_t _tempIndex = MESH.packetToResend.front().peerIndex;
if(MESH.peers.size()>_tempIndex){
MESH.packetToResend.front().senderTime = Rtc.utc_time;
if (MESH.packetToResend.front().TTL>0){
MESH.packetToResend.front().TTL--;
if(memcmp(MESH.packetToResend.front().sender,MESH.broker,6) != 0){ //do not send back the packet to the broker TODO: guarantee that peer[0] is always the broker
MESHsendPacket(&MESH.packetToResend.front());
// int result = esp_now_send(MESH.packetToResend.front().receiver, (uint8_t *)&MESH.packetToResend.front(), (sizeof(MESH.sendPacket))-(MESH_PAYLOAD_SIZE-MESH.packetToResend.front().chunkSize));
}
}
MESH.packetToResend.front().peerIndex = _tempIndex + 1;
}
else{
MESH.packetToResend.pop();
}
// pass the packets
}
if(MESH.packetToConsume.size()>0){
MESHencryptPayload(&MESH.packetToConsume.front(),0);
switch(MESH.packetToConsume.front().type){
case PACKET_TYPE_MQTT:
if(memcmp(MESH.packetToConsume.front().sender,MESH.sendPacket.sender,6)==0){
//discard echo
break;
}
AddLog_P2(LOG_LEVEL_INFO, PSTR("MESH: node received topic: %s"), (char*)MESH.packetToConsume.front().payload);
MESHreceiveMQTT(&MESH.packetToConsume.front());
break;
default:
break;
}
MESH.packetToConsume.pop();
}
}
void MESHEverySecond(){
static uint32_t _second = 0;
static uint32_t _tele_period = Settings.tele_period;
if (MESH.role == ROLE_NODE_SMALL){
_tele_period--;
if(_tele_period == 0){
// uint8_t broadcastAddress[6] = {0x30,0xAE,0xA4,0x26,0xE7,0x29};
// memcpy(MESH.sendPacket.receiver,MESH.broker,6);
// _tele_period = Settings.tele_period;
// mqtt_data[0] = 0;
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("SENSOR: %s %u"), mqtt_data, strlen(mqtt_data));
// MESH.sendPacket.chunkSize = strlen(mqtt_data);
// memcpy(MESH.sendPacket.payload,mqtt_data,MESH.sendPacket.chunkSize);
// MESH.sendPacket.type = PACKET_TYPE_SENSOR;
// MESH.sendPacket.senderTime = Rtc.utc_time;
// int result = esp_now_send(MESH.sendPacket.receiver, (uint8_t *)&MESH.sendPacket, (sizeof(MESH.sendPacket))-(MESH_PAYLOAD_SIZE-MESH.sendPacket.chunkSize));
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("send error: %d, tele: %u"), result, tele_period);
}
if(MESH.flags.brokerNeedsTopic == 1){
MESHanounceTopic();
MESH.flags.brokerNeedsTopic = 0;
}
}
}
#endif //ESP8266
/*********************************************************************************************\
* presentation
\*********************************************************************************************/
void MESHshow(bool json){
if (json) {
if(MESH.role != ROLE_NONE){
if(MESH.role != ROLE_BROKER) ResponseAppend_P(PSTR(",\"MESH\":{\"broker\":%u"),MESH.channel);
else ResponseAppend_P(PSTR(",\"MESH\":{\"node\":%u"),MESH.channel);
ResponseJsonEnd();
}
} else {
#ifdef ESP32
if(MESH.role == ROLE_BROKER){
WSContentSend_PD(PSTR("TAS-MESH:<br>"));
WSContentSend_PD(PSTR("Broker MAC: %s <br>"),WiFi.softAPmacAddress().c_str());
WSContentSend_PD(PSTR("Broker Channel: %u <hr>"),WiFi.channel());
for(auto &_peer : MESH.peers){
char _MAC[18];
ToHex_P(_peer.MAC,6,_MAC,18,':');
WSContentSend_PD(PSTR("Node MAC: %s <br>"),_MAC);
WSContentSend_PD(PSTR("Node last message: %u <br>"),_peer.lmfp);
WSContentSend_PD(PSTR("Node MQTT topic: %s <hr>"),_peer.topic);
}
}
#endif //ESP32
}
}
/*********************************************************************************************\
* check the MESH commands
\*********************************************************************************************/
bool MESHCmd(void) {
char command[CMDSZ];
bool serviced = true;
uint8_t disp_len = strlen(D_CMND_MESH);
if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_MESH), disp_len)) { // prefix
int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + disp_len, kMESH_Commands);
switch (command_code) {
case CMND_MESH_BROKER:
MESHstartBroker();
Response_P(S_JSON_MESH_COMMAND_NVALUE, command, MESH.channel);
break;
case CMND_MESH_NODE:
if (XdrvMailbox.data_len > 0) {
MESHstripColon(XdrvMailbox.data);
MESHMACStringToBytes(XdrvMailbox.data,MESH.broker);
MESHstartNode(MESH.channel);
Response_P(S_JSON_MESH_COMMAND_NVALUE, command, MESH.channel);
}
break;
case CMND_MESH_CHANNEL:
if (XdrvMailbox.data_len > 0) {
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("channel: %u"), XdrvMailbox.payload);
MESH.channel = XdrvMailbox.payload;
}
break;
case CMND_MESH_PEER:
if (XdrvMailbox.data_len > 0) {
uint8_t _MAC[6] = {0};
MESHstripColon(XdrvMailbox.data);
MESHMACStringToBytes(XdrvMailbox.data,_MAC);
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MAC-string: %s"), XdrvMailbox.data);
// AddLogBuffer(LOG_LEVEL_INFO,(uint8_t *)_MAC,6);
MESHaddPeer(_MAC);
MESHcountPeers();
}
break;
default:
// else for Unknown command
serviced = false;
break;
}
} else {
return false;
}
return serviced;
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv44(uint8_t function)
{
bool result = false;
switch (function) {
case FUNC_PRE_INIT:
MESHInit(); // TODO: save state
break;
case FUNC_EVERY_50_MSECOND:
MESHevery50MSecond();
break;
case FUNC_EVERY_SECOND:
MESHEverySecond();
break;
case FUNC_COMMAND:
result = MESHCmd();
break;
case FUNC_WEB_SENSOR:
#ifdef USE_WEBSERVER
MESHshow(0);
#endif
break;
case FUNC_JSON_APPEND:
MESHshow(1);
break;
#ifdef ESP32
case FUNC_MQTT_SUBSCRIBE:
MESHconnectMQTT();
break;
#endif //ESP32
// case FUNC_SHOW_SENSOR:
// if(MESH.role == ROLE_NODE_SMALL) MESHsendTeleSensor();
// break;
}
return result;
}
#endif // USE_TASMESH