From 90ee6f3995bcd468ef6e7f6c21451b24238fad39 Mon Sep 17 00:00:00 2001 From: Staars Date: Mon, 19 Oct 2020 19:03:47 +0200 Subject: [PATCH 1/5] tasmota EPS-Now mesh driver --- tasmota/support_tasmesh.ino | 283 +++++++++++++++++ tasmota/xdrv_02_mqtt.ino | 15 + tasmota/xdrv_44_tasmesh.ino | 613 ++++++++++++++++++++++++++++++++++++ 3 files changed, 911 insertions(+) create mode 100644 tasmota/support_tasmesh.ino create mode 100644 tasmota/xdrv_44_tasmesh.ino diff --git a/tasmota/support_tasmesh.ino b/tasmota/support_tasmesh.ino new file mode 100644 index 000000000..5b6336068 --- /dev/null +++ b/tasmota/support_tasmesh.ino @@ -0,0 +1,283 @@ +/* + 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 . + + -------------------------------------------------------------------------------------------- + Version Date Action Description + -------------------------------------------------------------------------------------------- +*/ + +#define USE_TASMESH +#ifdef USE_TASMESH + +#include +#include + +#ifdef ESP32 +#include +#include +#else +#include //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 peers; + std::queue packetToResend; + std::queue packetToConsume; + std::vector packetsAlreadySended; + std::vector 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 diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino index 58fd04c2c..70d83df77 100644 --- a/tasmota/xdrv_02_mqtt.ino +++ b/tasmota/xdrv_02_mqtt.ino @@ -214,6 +214,13 @@ 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 @@ -245,6 +252,14 @@ 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); } diff --git a/tasmota/xdrv_44_tasmesh.ino b/tasmota/xdrv_44_tasmesh.ino new file mode 100644 index 000000000..c88cfce31 --- /dev/null +++ b/tasmota/xdrv_44_tasmesh.ino @@ -0,0 +1,613 @@ +/* + 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 . + + -------------------------------------------------------------------------------------------- + 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(_peerNumber3){ + 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:
")); + WSContentSend_PD(PSTR("Broker MAC: %s
"),WiFi.softAPmacAddress().c_str()); + WSContentSend_PD(PSTR("Broker Channel: %u
"),WiFi.channel()); + for(auto &_peer : MESH.peers){ + char _MAC[18]; + ToHex_P(_peer.MAC,6,_MAC,18,':'); + WSContentSend_PD(PSTR("Node MAC: %s
"),_MAC); + WSContentSend_PD(PSTR("Node last message: %u
"),_peer.lmfp); + WSContentSend_PD(PSTR("Node MQTT topic: %s
"),_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 From 968fda65caf19d32a9996f35073f327e3f36abb1 Mon Sep 17 00:00:00 2001 From: Staars Date: Mon, 19 Oct 2020 19:07:22 +0200 Subject: [PATCH 2/5] adapt bearsll-esp8266 to ESP32 --- lib/bearssl-esp8266/src/rand/sysrng.c | 19 +++++++++++++++++++ .../src/symcipher/chacha20_ct.c | 4 ++++ lib/bearssl-esp8266/src/t_inner.h | 8 ++++---- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/lib/bearssl-esp8266/src/rand/sysrng.c b/lib/bearssl-esp8266/src/rand/sysrng.c index c8268de72..8fa4f3403 100644 --- a/lib/bearssl-esp8266/src/rand/sysrng.c +++ b/lib/bearssl-esp8266/src/rand/sysrng.c @@ -140,6 +140,24 @@ seeder_win32(const br_prng_class **ctx) #endif #if BR_USE_ESP8266_RAND +#ifdef ESP32 +extern uint32_t esp_random(void); + +static int +seeder_esp8266(const br_prng_class **ctx) //TODO: rename/refactor it to ESP32 +{ + uint32_t tmp[32 / sizeof(uint32_t)]; + size_t i; + + for (i=0; iupdate(ctx, tmp, sizeof tmp); + + return 1; +} +#else extern uint32_t phy_get_rand(void); // From the ESP8266 SDK static int @@ -157,6 +175,7 @@ seeder_esp8266(const br_prng_class **ctx) return 1; } #endif +#endif /* see bearssl_rand.h */ diff --git a/lib/bearssl-esp8266/src/symcipher/chacha20_ct.c b/lib/bearssl-esp8266/src/symcipher/chacha20_ct.c index 84ea79a1e..da4024cd1 100644 --- a/lib/bearssl-esp8266/src/symcipher/chacha20_ct.c +++ b/lib/bearssl-esp8266/src/symcipher/chacha20_ct.c @@ -33,7 +33,11 @@ br_chacha20_ct_run(const void *key, uint32_t kw[8], ivw[3]; size_t u; +#ifdef ESP32 + static const uint32_t CW[] = { +#else static const uint32_t CW[] PROGMEM = { +#endif 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 }; diff --git a/lib/bearssl-esp8266/src/t_inner.h b/lib/bearssl-esp8266/src/t_inner.h index 8dca0c09b..435c67c49 100644 --- a/lib/bearssl-esp8266/src/t_inner.h +++ b/lib/bearssl-esp8266/src/t_inner.h @@ -132,7 +132,7 @@ * Set BR_LOMUL on platforms where it makes sense. */ #ifndef BR_LOMUL -#if BR_ARMEL_CORTEXM_GCC || (defined(ESP8266) && !defined(ESP8266M32)) +#if BR_ARMEL_CORTEXM_GCC || ((defined(ESP8266) || defined(ESP32)) && !defined(ESP8266M32)) #define BR_LOMUL 1 #endif #endif @@ -315,7 +315,7 @@ * Use ESP8266 hardware random generator when possible. */ #ifndef BR_USE_ESP8266_RAND -#if defined(ESP8266) +#if (defined(ESP8266) || defined(ESP32)) #define BR_USE_ESP8266_RAND 1 #endif #endif @@ -433,7 +433,7 @@ */ #ifndef BR_USE_UNIX_TIME -#if defined __unix__ || defined __linux__ || defined ESP8266 \ +#if defined __unix__ || defined __linux__ || defined ESP8266 || defined ESP32\ || defined _POSIX_SOURCE || defined _POSIX_C_SOURCE \ || (defined __APPLE__ && defined __MACH__) #define BR_USE_UNIX_TIME 1 @@ -2568,7 +2568,7 @@ br_cpuid(uint32_t mask_eax, uint32_t mask_ebx, #endif -#ifdef ESP8266 +#if (defined(ESP8266)|| defined(ESP32)) #ifdef __cplusplus extern "C" { From 4e7e6ce7d3a59109be4f604407cee4b81f40da6b Mon Sep 17 00:00:00 2001 From: Staars Date: Tue, 20 Oct 2020 14:49:10 +0200 Subject: [PATCH 3/5] update xsns_62_MI_ESP32.ino --- tasmota/xsns_62_MI_ESP32.ino | 132 +++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 61 deletions(-) diff --git a/tasmota/xsns_62_MI_ESP32.ino b/tasmota/xsns_62_MI_ESP32.ino index 941f52950..eec8a79a8 100644 --- a/tasmota/xsns_62_MI_ESP32.ino +++ b/tasmota/xsns_62_MI_ESP32.ino @@ -20,6 +20,8 @@ -------------------------------------------------------------------------------------------- Version yyyymmdd Action Description -------------------------------------------------------------------------------------------- + 0.9.1.4 20201020 changed - use BearSSL for decryption, revert to old TELEPERIOD-cycle as default + ------- 0.9.1.3 20200926 changed - Improve HA discovery, make key+MAC case insensitive ------- 0.9.1.3 20200916 changed - add ATC (custom FW for LYWSD03MMC), API adaption for NimBLE-Arduino 1.0.2 @@ -47,7 +49,7 @@ #include #include #ifdef USE_MI_DECRYPTION -#include +#include #endif //USE_MI_DECRYPTION void MI32scanEndedCB(NimBLEScanResults results); @@ -81,11 +83,12 @@ struct { uint8_t sensor; // points to to the number 0...255 } state; struct { - uint32_t allwaysAggregate:1; + uint32_t allwaysAggregate:1; // always show all known values of one sensor in brdigemode + uint32_t noSummary:1; // no sensor values at TELE-period + uint32_t minimalSummary:1; // DEPRECATED!! + uint32_t directBridgeMode:1; // send every received BLE-packet as a MQTT-message in real-time uint32_t showRSSI:1; uint32_t ignoreBogusBattery:1; - uint32_t noSummary:1; - uint32_t minimalSummary:1; } option; } MI32; @@ -465,77 +468,71 @@ void MI32KeyMACStringToBytes(char* _string,uint8_t _keyMAC[]) { //uppercase * @brief Decrypts payload in place * * @param _buf - pointer to the buffer at position of PID - * @param _bufSize - buffersize (last position is last byte of TAG) + * @param _bufSize - buffersize (last position is two bytes behind last byte of TAG) * @param _type - sensor type * @return int - error code, 0 for success */ int MI32_decryptPacket(char *_buf, uint16_t _bufSize, uint32_t _type){ encPacket_t *packet = (encPacket_t*)_buf; - // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("to decrypt: %02x %02x %02x %02x %02x %02x %02x %02x"),(uint8_t)_buf[0],(uint8_t)_buf[1],(uint8_t)_buf[2],(uint8_t)_buf[3],(uint8_t)_buf[4],(uint8_t)_buf[5],(uint8_t)_buf[6],(uint8_t)_buf[7]); - // AddLog_P2(LOG_LEVEL_DEBUG,PSTR(" : %02x %02x %02x %02x %02x %02x %02x %02x"),(uint8_t)_buf[8],(uint8_t)_buf[9],(uint8_t)_buf[10],(uint8_t)_buf[11],(uint8_t)_buf[12],(uint8_t)_buf[13],(uint8_t)_buf[14],(uint8_t)_buf[15]); - // AddLog_P2(LOG_LEVEL_DEBUG,PSTR(" : %02x %02x %02x %02x %02x %02x %02x %02x"),(uint8_t)_buf[16],(uint8_t)_buf[17],(uint8_t)_buf[18],(uint8_t)_buf[19],(uint8_t)_buf[20],(uint8_t)_buf[21],(uint8_t)_buf[22],(uint8_t)_buf[23]); - // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("as packet: MAC: %02x %02x %02x %02x %02x %02x"), packet->MAC[0], packet->MAC[1], packet->MAC[2], packet->MAC[3], packet->MAC[4], packet->MAC[5]); - - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Decrypt Size of Buffer: %u"), _bufSize); + uint8_t payload[8]; + size_t data_len = _bufSize - 9 - 4 - 3 - 1 - 1 ; // _bufsize - header - tag - ext.counter - RSSI - spare(?) int ret = 0; - unsigned char output[10] = {0}; uint8_t nonce[12]; - uint8_t tag[4 ]; + uint32_t tag; const unsigned char authData[1] = {0x11}; + // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Decrypt Size of Buffer: %u, payload length: %u"), _bufSize, data_len); + // AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*)_buf, _bufSize); + // nonce: device MAC, device type, frame cnt, ext. cnt for (uint32_t i = 0; i<6; i++){ nonce[i] = packet->MAC[i]; } memcpy((uint8_t*)&nonce+6,(uint8_t*)&packet->PID,2); nonce[8] = packet->frameCnt; - memcpy((uint8_t*)&nonce+9,(char*)&_buf[_bufSize-9],3); + memcpy((uint8_t*)&nonce+9,(uint8_t*)&_buf[_bufSize-9],3); // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("nonceCnt1 and 2: %02x %02x %02x"),nonce[9],nonce[10],nonce[11]); - memcpy((uint8_t*)&tag,(char*)&_buf[_bufSize-6],4); + memcpy((uint8_t*)&tag,(uint8_t*)&_buf[_bufSize-6],4); // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("tag: %02x %02x %02x %02x"),tag[0],tag[1],tag[2],tag[3]); MI32_ReverseMAC(packet->MAC); uint8_t _bindkey[16] = {0x0}; + bool foundNoKey = true; + AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MI32: search key for MAC: %02x %02x %02x %02x %02x %02x"), packet->MAC[0], packet->MAC[1], packet->MAC[2], packet->MAC[3], packet->MAC[4], packet->MAC[5]); for(uint32_t i=0; iMAC,MIBLEbindKeys[i].MAC,sizeof(packet->MAC))==0){ - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("have key")); memcpy(_bindkey,MIBLEbindKeys[i].key,sizeof(_bindkey)); - } - else{ - // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mac in packet: %02x %02x %02x %02x %02x %02x"), packet->MAC[0], packet->MAC[1], packet->MAC[2], packet->MAC[3], packet->MAC[4], packet->MAC[5]); - // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mac in vector: %02x %02x %02x %02x %02x %02x"), MIBLEbindKeys[i].MAC[0], MIBLEbindKeys[i].MAC[1], MIBLEbindKeys[i].MAC[2], MIBLEbindKeys[i].MAC[3], MIBLEbindKeys[i].MAC[4], MIBLEbindKeys[i].MAC[5]); + AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MI32: decryption Key found")); + foundNoKey = false; + break; } } + if(foundNoKey){ + AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MI32: no Key found !!")); + return -2; + } - // init - mbedtls_ccm_context ctx; - mbedtls_ccm_init(&ctx); - // set bind key - ret = mbedtls_ccm_setkey(&ctx, - MBEDTLS_CIPHER_ID_AES, - _bindkey, - 16 * 8 //bits - ); - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("set key: %i, MAC: %02x %02x %02x %02x %02x %02x"),ret, packet->MAC[0], packet->MAC[1], packet->MAC[2], packet->MAC[3], packet->MAC[4], packet->MAC[5]); + br_aes_small_ctrcbc_keys keyCtx; + br_aes_small_ctrcbc_init(&keyCtx, _bindkey, sizeof(_bindkey)); -/*int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, - const unsigned char *iv, size_t iv_len, - const unsigned char *add, size_t add_len, - const unsigned char *input, unsigned char *output, - const unsigned char *tag, size_t tag_len ) -*/ - ret = mbedtls_ccm_auth_decrypt(&ctx,_bufSize-18, - (const unsigned char*)&nonce, sizeof(nonce), - authData, sizeof(authData), - (const unsigned char*)packet->payload, output, - tag,sizeof(tag)); + br_ccm_context ctx; + br_ccm_init(&ctx, &keyCtx.vtable); + br_ccm_reset(&ctx, nonce, sizeof(nonce), sizeof(authData), data_len, sizeof(tag)); + br_ccm_aad_inject(&ctx, authData, sizeof(authData)); + br_ccm_flip(&ctx); - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Decrypted %i: %02x %02x %02x %02x %02x %02x %02x"), ret, output[0],output[1],output[2],output[3],output[4],output[5],output[6]); - // put decrypted data in place - memcpy((uint8_t*)(packet->payload)+1,output,_bufSize-18); - // clean up - mbedtls_ccm_free(&ctx); - return ret; + + memcpy(payload,packet->payload,data_len); //we want to be sure about 4-byte alignement + br_ccm_run(&ctx, 0, payload, data_len); + memcpy((uint8_t*)packet->payload+1,payload,data_len); //back to the packet + + // br_ccm_get_tag(&ctx, &checkTag); + ret = br_ccm_check_tag(&ctx, &tag); + // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("packetTag: %08x"),tag); + // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("computedTag: %08x"),checkTag); + + AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MI32: Err:%i, Decrypted : %02x %02x %02x %02x %02x "), ret, packet->payload[1],packet->payload[2],packet->payload[3],packet->payload[4],packet->payload[5]); + return ret-1; } #endif // USE_MI_DECRYPTION @@ -651,6 +648,9 @@ void MI32triggerTele(void){ \*********************************************************************************************/ void MI32Init(void) { + +MIBLEsensors.reserve(10); +MIBLEbindKeys.reserve(10); MI32.mode.init = false; if (!MI32.mode.init) { NimBLEDevice::init(""); @@ -661,10 +661,11 @@ void MI32Init(void) { //test section for options MI32.option.allwaysAggregate = 1; + MI32.option.noSummary = 0; + MI32.option.minimalSummary = 0; + MI32.option.directBridgeMode = 0; MI32.option.showRSSI = 1; MI32.option.ignoreBogusBattery = 1; // from advertisements - MI32.option.noSummary = 0; - MI32.option.minimalSummary = 1; MI32StartScanTask(); // Let's get started !! } @@ -1125,10 +1126,12 @@ void MI32parseMiBeacon(char * _buf, uint32_t _slot, uint16_t _bufSize){ MIBLEsensors[_slot].lastCnt = _beacon.counter; #ifdef USE_MI_DECRYPTION + int decryptRet = 0; switch(MIBLEsensors[_slot].type){ case LYWSD03MMC: case MHOC401: if (_beacon.frame == 0x5858){ - int decryptRet = MI32_decryptPacket((char*)&_beacon.productID,_bufSize, LYWSD03MMC); //start with PID + decryptRet = MI32_decryptPacket((char*)&_beacon.productID,_bufSize, LYWSD03MMC); //start with PID + // AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*)&_beacon.productID,_bufSize); } break; case MJYD2S: @@ -1138,9 +1141,10 @@ void MI32parseMiBeacon(char * _buf, uint32_t _slot, uint16_t _bufSize){ memcpy((uint8_t*)&_beacon.MAC,MIBLEsensors[_slot].MAC,6); // now insert the real MAC from our internal vector _bufSize+=6; // the packet has grown MI32_ReverseMAC(_beacon.MAC); // payload MAC is always reversed + AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MJYD2S: special packet")); } if (_beacon.frame != 0x5910){ - int decryptRet = MI32_decryptPacket((char*)&_beacon.productID,_bufSize,MJYD2S); //start with PID + decryptRet = MI32_decryptPacket((char*)&_beacon.productID,_bufSize,MJYD2S); //start with PID } else{ // This seems to be some kind of wake-up packet only, as it shows up before all kinds of messages, not only motion @@ -1156,22 +1160,22 @@ void MI32parseMiBeacon(char * _buf, uint32_t _slot, uint16_t _bufSize){ } break; } -#endif //USE_MI_DECRYPTION - -if (MIBLEsensors[_slot].type==NLIGHT){ - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MiBeacon type:%02x: %02x %02x %02x %02x %02x %02x %02x %02x"),_beacon.type, (uint8_t)_buf[0],(uint8_t)_buf[1],(uint8_t)_buf[2],(uint8_t)_buf[3],(uint8_t)_buf[4],(uint8_t)_buf[5],(uint8_t)_buf[6],(uint8_t)_buf[7]); - AddLog_P2(LOG_LEVEL_DEBUG,PSTR(" type:%02x: %02x %02x %02x %02x %02x %02x %02x %02x"),_beacon.type, (uint8_t)_buf[8],(uint8_t)_buf[9],(uint8_t)_buf[10],(uint8_t)_buf[11],(uint8_t)_buf[12],(uint8_t)_buf[13],(uint8_t)_buf[14],(uint8_t)_buf[15]); +if(decryptRet!=0){ + AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MI32: decryption failed with error: %d"),decryptRet); + return; } +#endif //USE_MI_DECRYPTION if(MIBLEsensors[_slot].type==6){ DEBUG_SENSOR_LOG(PSTR("CGD1 no support for MiBeacon, type %u"),MIBLEsensors[_slot].type); return; } - AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s at slot %u"), kMI32DeviceType[MIBLEsensors[_slot].type-1],_slot); + AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s at slot %u with payload type: %02x"), kMI32DeviceType[MIBLEsensors[_slot].type-1],_slot,_beacon.type); switch(_beacon.type){ case 0x01: MIBLEsensors[_slot].Btn=_beacon.Btn.num + (_beacon.Btn.longPress/2)*6; MIBLEsensors[_slot].eventType.Btn = 1; + MI32.mode.shallTriggerTele = 1; // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode 1: U16: %u Button"), MIBLEsensors[_slot].Btn ); break; case 0x04: @@ -1247,12 +1251,14 @@ if (MIBLEsensors[_slot].type==NLIGHT){ MIBLEsensors[_slot].events++; MIBLEsensors[_slot].lux = _beacon.lux; MIBLEsensors[_slot].eventType.lux = 1; - MIBLEsensors[_slot].NMT = 0; + MIBLEsensors[_slot].NMT = 0; + MI32.mode.shallTriggerTele = 1; // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("PIR: primary"),MIBLEsensors[_slot].lux ); break; case 0x17: MIBLEsensors[_slot].NMT = _beacon.NMT; MIBLEsensors[_slot].eventType.NMT = 1; + MI32.mode.shallTriggerTele = 1; // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode 17: NMT: %u seconds"), _beacon.NMT); break; #endif //USE_MI_DECRYPTION @@ -1262,13 +1268,17 @@ if (MIBLEsensors[_slot].type==NLIGHT){ MIBLEsensors[_slot].events++; MIBLEsensors[_slot].NMT = 0; MIBLEsensors[_slot].lastTime = millis(); + MI32.mode.shallTriggerTele = 1; // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("PIR: primary"),MIBLEsensors[_slot].lux ); } + else{ + AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*)_buf,_bufSize); + } break; } if(MIBLEsensors[_slot].eventType.raw == 0) return; MIBLEsensors[_slot].shallSendMQTT = 1; - MI32.mode.shallTriggerTele = 1; + if(MI32.option.directBridgeMode) MI32.mode.shallTriggerTele = 1; } void MI32ParseATCPacket(char * _buf, uint32_t length, uint8_t addr[6], int rssi){ @@ -1286,7 +1296,7 @@ void MI32ParseATCPacket(char * _buf, uint32_t length, uint8_t addr[6], int rssi) MIBLEsensors[_slot].eventType.bat = 1; MIBLEsensors[_slot].shallSendMQTT = 1; - MI32.mode.shallTriggerTele = 1; + if(MI32.option.directBridgeMode) MI32.mode.shallTriggerTele = 1; } @@ -1328,7 +1338,7 @@ void MI32parseCGD1Packet(char * _buf, uint32_t length, uint8_t addr[6], int rssi } if(MIBLEsensors[_slot].eventType.raw == 0) return; MIBLEsensors[_slot].shallSendMQTT = 1; - MI32.mode.shallTriggerTele = 1; + if(MI32.option.directBridgeMode) MI32.mode.shallTriggerTele = 1; } void MI32ParseResponse(char *buf, uint16_t bufsize, uint8_t addr[6], int rssi) { From 414e5f382c3be207ad7446497e2ad3b520b45ca0 Mon Sep 17 00:00:00 2001 From: Staars Date: Tue, 20 Oct 2020 14:50:13 +0200 Subject: [PATCH 4/5] more adaptions for ESP32-compatibility of BearSSL --- lib/bearssl-esp8266/src/pgmspace_bearssl.h | 2 ++ lib/bearssl-esp8266/src/t_bearssl_tasmota_config.h | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/bearssl-esp8266/src/pgmspace_bearssl.h b/lib/bearssl-esp8266/src/pgmspace_bearssl.h index e616ffe2e..cb3ef8a2a 100644 --- a/lib/bearssl-esp8266/src/pgmspace_bearssl.h +++ b/lib/bearssl-esp8266/src/pgmspace_bearssl.h @@ -14,6 +14,7 @@ extern "C" { #endif +#ifndef ESP32 #ifndef ICACHE_RODATA_ATTR #define ICACHE_RODATA_ATTR __attribute__((section(".irom.text"))) #endif @@ -29,6 +30,7 @@ extern "C" { // Place each progmem object into its own named section, avoiding conflicts #define PROGMEM __attribute__((section( "\".irom.text." __FILE__ "." __STRINGIZE(__LINE__) "." __STRINGIZE(__COUNTER__) "\""))) #endif +#endif //ESP32 #ifndef PGM_P #define PGM_P const char * #endif diff --git a/lib/bearssl-esp8266/src/t_bearssl_tasmota_config.h b/lib/bearssl-esp8266/src/t_bearssl_tasmota_config.h index 732cdf9e6..312e3d94f 100644 --- a/lib/bearssl-esp8266/src/t_bearssl_tasmota_config.h +++ b/lib/bearssl-esp8266/src/t_bearssl_tasmota_config.h @@ -7,13 +7,19 @@ #define __ets__ #endif +#ifndef ESP32 #ifndef ICACHE_FLASH #define ICACHE_FLASH #endif - -#ifndef ESP8266 -#define ESP8266 +#else +#ifndef PROGMEM +#define PROGMEM #endif +#endif + +// #ifndef ESP8266 +// #define ESP8266 +// #endif #ifndef BR_SLOW_MUL15 #define BR_SLOW_MUL15 1 // shrinks EC code by 8.5k From e3d3e76d6169baeb0b804114f843de94e77bc738 Mon Sep 17 00:00:00 2001 From: Staars Date: Tue, 20 Oct 2020 15:22:23 +0200 Subject: [PATCH 5/5] Revert "tasmota EPS-Now mesh driver" This reverts commit 90ee6f3995bcd468ef6e7f6c21451b24238fad39. --- tasmota/support_tasmesh.ino | 283 ----------------- tasmota/xdrv_02_mqtt.ino | 15 - tasmota/xdrv_44_tasmesh.ino | 613 ------------------------------------ 3 files changed, 911 deletions(-) delete mode 100644 tasmota/support_tasmesh.ino delete mode 100644 tasmota/xdrv_44_tasmesh.ino diff --git a/tasmota/support_tasmesh.ino b/tasmota/support_tasmesh.ino deleted file mode 100644 index 5b6336068..000000000 --- a/tasmota/support_tasmesh.ino +++ /dev/null @@ -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 . - - -------------------------------------------------------------------------------------------- - Version Date Action Description - -------------------------------------------------------------------------------------------- -*/ - -#define USE_TASMESH -#ifdef USE_TASMESH - -#include -#include - -#ifdef ESP32 -#include -#include -#else -#include //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 peers; - std::queue packetToResend; - std::queue packetToConsume; - std::vector packetsAlreadySended; - std::vector 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 diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino index 70d83df77..58fd04c2c 100644 --- a/tasmota/xdrv_02_mqtt.ino +++ b/tasmota/xdrv_02_mqtt.ino @@ -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); } diff --git a/tasmota/xdrv_44_tasmesh.ino b/tasmota/xdrv_44_tasmesh.ino deleted file mode 100644 index c88cfce31..000000000 --- a/tasmota/xdrv_44_tasmesh.ino +++ /dev/null @@ -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 . - - -------------------------------------------------------------------------------------------- - 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(_peerNumber3){ - 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:
")); - WSContentSend_PD(PSTR("Broker MAC: %s
"),WiFi.softAPmacAddress().c_str()); - WSContentSend_PD(PSTR("Broker Channel: %u
"),WiFi.channel()); - for(auto &_peer : MESH.peers){ - char _MAC[18]; - ToHex_P(_peer.MAC,6,_MAC,18,':'); - WSContentSend_PD(PSTR("Node MAC: %s
"),_MAC); - WSContentSend_PD(PSTR("Node last message: %u
"),_peer.lmfp); - WSContentSend_PD(PSTR("Node MQTT topic: %s
"),_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