From 509a79e5f6baf859db281511133e5e9ffa553a69 Mon Sep 17 00:00:00 2001 From: Staars Date: Thu, 13 Feb 2020 17:16:32 +0100 Subject: [PATCH 1/2] more lsfr-LUT-entries and PDU-types --- tasmota/xsns_61_MI_NRF24.ino | 859 +++++++++++++++++++++++++++++++++++ 1 file changed, 859 insertions(+) create mode 100644 tasmota/xsns_61_MI_NRF24.ino diff --git a/tasmota/xsns_61_MI_NRF24.ino b/tasmota/xsns_61_MI_NRF24.ino new file mode 100644 index 000000000..8527c9749 --- /dev/null +++ b/tasmota/xsns_61_MI_NRF24.ino @@ -0,0 +1,859 @@ +/* + xsns_61_MI_NRF24.ino - MI-BLE-sensors via nrf24l01 support for Tasmota + + 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.2.0 20200212 integrate - "backports" from MI-HM10, change reading pattern, + add missing PDU-types, renaming driver + --- + 0.9.1.0 20200117 integrate - Added support for the LYWSD02 + --- + 0.9.0.0 20191127 started - further development by Christian Baars + base - code base from cbm80amiga, floe, Dmitry.GR + forked - from arendst/tasmota - https://github.com/arendst/Tasmota + +*/ + +#ifdef USE_SPI +#ifdef USE_NRF24 +#ifdef USE_MIBLE + +#ifdef DEBUG_TASMOTA_SENSOR + #define MINRF_LOG_BUFFER(x) MINRFshowBuffer(x); +#else + #define MINRF_LOG_BUFFER(x) +#endif + + +/*********************************************************************************************\ +* MINRF +* BLE-Sniffer/Bridge for MIJIA/XIAOMI Temperatur/Humidity-Sensor, Mi Flora, LYWSD02 +* +* Usage: Configure NRF24 +\*********************************************************************************************/ + +#define XSNS_61 61 + +#include + +#define FLORA 1 +#define MJ_HT_V1 2 +#define LYWSD02 3 +#define LYWSD03 4 + +uint8_t kMINRFSlaveID[4][3] = { 0xC4,0x7C,0x8D, // Flora + 0x58,0x2D,0x34, // MJ_HT_V1 + 0xE7,0x2E,0x00, // LYWSD02 + 0xA4,0xC1,0x38, // LYWSD03 + }; + +const char kMINRFSlaveType1[] PROGMEM = "Flora"; +const char kMINRFSlaveType2[] PROGMEM = "MJ_HT_V1"; +const char kMINRFSlaveType3[] PROGMEM = "LYWSD02"; +const char kMINRFSlaveType4[] PROGMEM = "LYWSD03"; +const char * kMINRFSlaveType[] PROGMEM = {kMINRFSlaveType1,kMINRFSlaveType2,kMINRFSlaveType3,kMINRFSlaveType4}; + +// PDU's or different channels 37-39 +const uint32_t kMINRFFloPDU[3] = {0x3eaa857d,0xef3b8730,0x71da7b46}; +const uint32_t kMINRFMJPDU[3] = {0x4760cd66,0xdbcc0cd3,0x33048df5}; +const uint32_t kMINRFL2PDU[3] = {0x3eaa057d,0xef3b0730,0x71da7646}; // 1 and 3 unsure +// const uint32_t kMINRFL3PDU[3] = {0x4760dd78,0xdbcc1ccd,0xffffffff}; //encrypted - 58 58 +const uint32_t kMINRFL3PDU[3] = {0x4760cb78,0xdbcc0acd,0x33048beb}; //unencrypted - 30 58 + +// start-LSFR for different channels 37-39 +const uint8_t kMINRFlsfrList_A[3] = {0x4b,0x17,0x23}; // Flora, LYWSD02 +const uint8_t kMINRFlsfrList_B[3] = {0x21,0x72,0x43}; // MJ_HT_V1, LYWSD03 + + +#pragma pack(1) // important!! +struct MJ_HT_V1Header_t {// related to the payload + uint8_t padding[3]; + uint8_t mesSize; // 3 + uint8_t padding2; + uint16_t uuid; // 5,6 -> 0xFE95 + uint16_t type; // 7,8 -> 0x2050 MI-TH-V1 + uint8_t padding3[2]; + uint8_t counter; // 11 - counts up with every sent record + uint8_t serial[6]; // 12 - 17 + uint8_t mode; // 18 + uint8_t padding5; + uint8_t effectiveDataLength; + }; + +struct FlowerHeader_t { // related to the payload + uint8_t padding[4]; + uint8_t padding2; + uint16_t uuid; // 5,6 -> 0xFE95 + uint8_t mesSize; + uint8_t padding22; + uint16_t uuid2; // 9,10 -> 0xFE95 + uint16_t type; // 11,12 -> 0x7120 Flowercare + uint8_t padding3[2]; + uint8_t counter; // 15 - counts up with every sent record + uint8_t serial[6]; // 16 - 21 + uint8_t padding4; //22 + uint8_t mode; // 23 + }; + +union floraPacket_t { // related to the whole 32-byte-packet/buffer + struct { + uint16_t idWord; + uint8_t padding; + uint8_t serial[6]; + uint8_t padding4; + uint8_t mode; + uint8_t valueTen; + uint8_t effectiveDataLength; // 1 + uint16_t data; + } T; // mode 04 + struct { + uint16_t idWord; + uint8_t padding; + uint8_t serial[6]; + uint8_t padding4; + uint8_t mode; + uint8_t valueTen; + uint8_t effectiveDataLength; // 3 + uint32_t data:24; // it is probably a real uint24_t + } L; // mode 07 + struct { + uint8_t padding[3]; + uint8_t serial[6]; + uint8_t padding4; + uint8_t mode; + uint8_t valueTen; + uint8_t effectiveDataLength; // 1 + uint8_t data; + } M; // mode 08 + struct { + uint8_t padding[3]; + uint8_t serial[6]; + uint8_t padding4; + uint8_t mode; + uint8_t valueTen; + uint8_t effectiveDataLength; // 2 + uint16_t data; + } F; // mode 09 +}; + +union MJ_HT_V1Packet_t { // related to the whole 32-byte-packet/buffer + struct { + uint16_t idWord; + uint8_t padding; + uint8_t serial[6]; + uint8_t mode; + uint8_t valueTen; + uint8_t effectiveDataLength; // 4 + uint16_t temp; + uint16_t hum; + } TH; // mode 0d + struct { + uint8_t padding[3]; + uint8_t serial[6]; + uint8_t mode; + uint8_t valueTen; + uint8_t effectiveDataLength; // 1 + uint8_t battery; + } B; // mode 0a + // We do NOT need the isolated T and H packet +}; + +union LYWSD02Packet_t { // related to the whole 32-byte-packet/buffer + struct { + uint16_t idWord; + uint8_t padding; + uint8_t serial[6]; + uint8_t padding4; + uint8_t mode; + uint8_t valueTen; + uint8_t effectiveDataLength; + uint16_t data; + } TH; // mode 04 or 06 +}; + +struct bleAdvPacket_t { // for nRF24L01 max 32 bytes = 2+6+24 + uint8_t pduType; + uint8_t payloadSize; + uint8_t mac[6]; + union { + uint8_t payload[24]; + MJ_HT_V1Header_t header; + FlowerHeader_t flowerHeader; + struct { + uint8_t padding[21]; + uint16_t temp; + uint8_t hum_lb; // the high byte does not fit into the RX_buffer + } TH; // mode 0d + struct { + uint8_t padding[21]; + uint16_t temp; + } T; // mode 04 + struct { + uint8_t padding[21]; + uint16_t hum; + } H; // mode 06 + struct { + uint8_t padding[21]; + uint8_t battery; + } B; // mode 0a + struct { + uint8_t padding[2]; + uint8_t mode; + uint16_t size; // 2 + uint16_t data; + } F_T; // mode 04 + struct { + uint8_t padding[2]; + uint8_t mode; + uint16_t size; // 3 + uint16_t data; + uint8_t data2; // unknown meaning, maybe it is a real uint24_t (data with data2) + } F_L; // mode 07 + struct { + uint8_t padding[2]; + uint8_t mode; + uint16_t size; // 1 + uint8_t data; + } F_M; // mode 08 + struct { + uint8_t padding[2]; + uint8_t mode; + uint16_t size; // 2 + uint16_t data; + } F_F; // mode 09 + }; +}; + +union FIFO_t{ + bleAdvPacket_t bleAdv; + floraPacket_t floraPacket; + MJ_HT_V1Packet_t MJ_HT_V1Packet; + LYWSD02Packet_t LYWSD02Packet; + uint8_t raw[32]; +}; + +#pragma pack(0) + +struct { + const uint8_t channel[3] = {37,38,39}; // BLE advertisement channel number + const uint8_t frequency[3] = { 2,26,80}; // real frequency (2400+x MHz) + + uint16_t timer; + uint8_t currentChan=0; + FIFO_t buffer; + uint8_t packetMode; // 0 - normal BLE-advertisements, 1 - special "flora"-packet, 2 - special "MJ_HT_V1"-packet + +#ifdef DEBUG_TASMOTA_SENSOR + uint8_t streamBuffer[sizeof(buffer)]; // raw data stream bytes + uint8_t lsfrBuffer[sizeof(buffer)]; // correpsonding lfsr-bytes for the buffer, probably only useful for a BLE-packet +#endif // DEBUG_TASMOTA_SENSOR + +} MINRF; + +struct mi_sensor_t{ + uint8_t type; //Flora = 1; MJ_HT_V1=2; LYWSD02=3; LYWSD03=4 + uint8_t serial[6]; + uint8_t showedUp; + float temp; //Flora, MJ_HT_V1, LYWSD0x + union { + struct { + float moisture; + float fertility; + uint32_t lux; + }; // Flora + struct { + float hum; + uint8_t bat; + }; // MJ_HT_V1, LYWSD0x + }; +}; + +std::vector MIBLEsensors; + +/********************************************************************************************/ + + +bool MINRFinitBLE(uint8_t _mode) +{ + if (MINRF.timer%1000 == 0){ // only re-init every 20 seconds + NRF24radio.begin(pin[GPIO_SPI_CS],pin[GPIO_SPI_DC]); + NRF24radio.setAutoAck(false); + NRF24radio.setDataRate(RF24_1MBPS); + NRF24radio.disableCRC(); + NRF24radio.setChannel( MINRF.frequency[MINRF.currentChan] ); + NRF24radio.setRetries(0,0); + NRF24radio.setPALevel(RF24_PA_MIN); // we only receive + NRF24radio.setAddressWidth(4); + // NRF24radio.openReadingPipe(0,0x6B7D9171); // advertisement address: 0x8E89BED6 (bit-reversed -> 0x6B7D9171) + // NRF24radio.openWritingPipe( 0x6B7D9171); // not used ATM + NRF24radio.powerUp(); + } + if(NRF24radio.isChipConnected()){ + // DEBUG_SENSOR_LOG(PSTR("MINRF chip connected")); + MINRFchangePacketModeTo(_mode); + return true; + } + // DEBUG_SENSOR_LOG(PSTR("MINRF chip NOT !!!! connected")); + return false; +} + +void MINRFhopChannel() +{ + MINRF.currentChan++; + if(MINRF.currentChan >= sizeof(MINRF.channel)) { + MINRF.currentChan = 0; + } + NRF24radio.setChannel( MINRF.frequency[MINRF.currentChan] ); +} + +/** + * @brief Read out FIFO-buffer, swap buffer and whiten + * + * @return true - If something is in the buffer + * @return false - Nothing is in the buffer + */ +bool MINRFreceivePacket(void) +{ + if(!NRF24radio.available()) { + return false; + } + while(NRF24radio.available()) { + // static uint8_t _lsfr = 0; //-> for testing out suitable lsfr-start-values for yet unknown packets + // _lsfr++; + NRF24radio.read( &MINRF.buffer, sizeof(MINRF.buffer) ); +#ifdef DEBUG_TASMOTA_SENSOR + memcpy(&MINRF.streamBuffer, &MINRF.buffer, sizeof(MINRF.buffer)); +#endif // DEBUG_TASMOTA_SENSOR + MINRFswapbuf( sizeof(MINRF.buffer) ); + // MINRF_LOG_BUFFER(); + + // AddLog_P2(LOG_LEVEL_INFO,PSTR("MINRF: _lsfrlist: %x, chan: %u, mode: %u"),_lsfrlist[MINRF.currentChan],MINRF.currentChan, MINRF.packetMode); + switch (MINRF.packetMode) { + case 0: + MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), MINRF.channel[MINRF.currentChan] | 0x40); + break; + case 1: + MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), kMINRFlsfrList_A[MINRF.currentChan]); // "flora" mode + break; + case 2: + MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), kMINRFlsfrList_B[MINRF.currentChan]); // "MJ_HT_V1" mode + break; + case 3: + MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), kMINRFlsfrList_A[MINRF.currentChan]); // "LYWSD02" mode + break; + case 4: + MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), kMINRFlsfrList_B[MINRF.currentChan]); // "LYWSD03" mode + break; + } + // DEBUG_SENSOR_LOG(PSTR("MINRF: LSFR:%x"),_lsfr); + // if (_lsfr>254) _lsfr=0; + } + // DEBUG_SENSOR_LOG(PSTR("MINRF: did read FIFO")); + return true; +} + +#ifdef DEBUG_TASMOTA_SENSOR +void MINRFshowBuffer(uint8_t (&buf)[32]){ // we use this only for the 32-byte-FIFO-buffer, so 32 is hardcoded + // DEBUG_SENSOR_LOG(PSTR("MINRF: Buffer: %c %c %c %c %c %c %c %c" + // " %c %c %c %c %c %c %c %c" + // " %c %c %c %c %c %c %c %c" + // " %c %c %c %c %c %c %c %c") + DEBUG_SENSOR_LOG(PSTR("MINRF: Buffer: %02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x ") + ,buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10],buf[11], + buf[12],buf[13],buf[14],buf[15],buf[16],buf[17],buf[18],buf[19],buf[20],buf[21],buf[22],buf[23], + buf[24],buf[25],buf[26],buf[27],buf[28],buf[29],buf[30],buf[31] + ); +} +#endif // DEBUG_TASMOTA_SENSOR + +/** + * @brief change lsfrBuffer content to "wire bit order" + * + * @param len Buffer lenght (could be hardcoded to 32) + */ +void MINRFswapbuf(uint8_t len) +{ + uint8_t* buf = (uint8_t*)&MINRF.buffer; + while(len--) { + uint8_t a = *buf; + uint8_t v = 0; + if (a & 0x80) v |= 0x01; + if (a & 0x40) v |= 0x02; + if (a & 0x20) v |= 0x04; + if (a & 0x10) v |= 0x08; + if (a & 0x08) v |= 0x10; + if (a & 0x04) v |= 0x20; + if (a & 0x02) v |= 0x40; + if (a & 0x01) v |= 0x80; + *(buf++) = v; + } +} + +/** + * @brief Whiten the packet buffer + * + * @param buf The packet buffer + * @param len Lenght of the packet buffer + * @param lfsr Start lsfr-byte + */ +void MINRFwhiten(uint8_t *buf, uint8_t len, uint8_t lfsr) +{ + while(len--) { + uint8_t res = 0; + // LFSR in "wire bit order" + for (uint8_t i = 1; i; i <<= 1) { + if (lfsr & 0x01) { + lfsr ^= 0x88; + res |= i; + } + lfsr >>= 1; + } + *(buf++) ^= res; +#ifdef DEBUG_TASMOTA_SENSOR + MINRF.lsfrBuffer[31-len] = lfsr; +#endif //DEBUG_TASMOTA_SENSOR + } +} + +void MINRFreverseMAC(uint8_t _mac[]){ + uint8_t _reversedMAC[6]; + for (uint8_t i=0; i<6; i++){ + _reversedMAC[5-i] = _mac[i]; + } + memcpy(_mac,_reversedMAC, sizeof(_reversedMAC)); +} + +/** + * @brief Set packet mode and fitting PDU-type of the NRF24L01 + * + * @param _mode The internal packet mode number + */ +void MINRFchangePacketModeTo(uint8_t _mode) { + uint32_t (_nextchannel) = MINRF.currentChan+1; + if (_nextchannel>2) _nextchannel=0; + + switch(_mode){ + case 0: // normal BLE advertisement + NRF24radio.openReadingPipe(0,0x6B7D9171); // advertisement address: 0x8E89BED6 (bit-reversed -> 0x6B7D9171) + break; + case 1: // special flora packet + NRF24radio.openReadingPipe(0,kMINRFFloPDU[_nextchannel]); // 95 fe 71 20 -> flora + break; + case 2: // special MJ_HT_V1 packet + NRF24radio.openReadingPipe(0,kMINRFMJPDU[_nextchannel]); // 95 fe 50 20 -> MJ_HT_V1 + break; + case 3: // special LYWSD02 packet + NRF24radio.openReadingPipe(0,kMINRFL2PDU[_nextchannel]);// 95 fe 70 20 -> LYWSD02 + break; + case 4: // special LYWSD03 packet + if(kMINRFL3PDU[_nextchannel]==0xffffffff) break; + NRF24radio.openReadingPipe(0,kMINRFL3PDU[_nextchannel]);// 95 fe 58 30 -> LYWSD03 (= no data message) + break; + } + // DEBUG_SENSOR_LOG(PSTR("MINRF: Change Mode to %u"),_mode); + MINRF.packetMode = _mode; +} + +/** + * @brief Return the slot number of a known sensor or return create new sensor slot + * + * @param _serial BLE address of the sensor + * @param _type Type number of the sensor, 0xff for Auto-type + * @return uint32_t Known or new slot in the sensors-vector + */ +uint32_t MINRFgetSensorSlot(uint8_t (&_serial)[6], uint8_t _type){ + if(_type==0xff){ + DEBUG_SENSOR_LOG(PSTR("MINRF: will test MAC-type")); + for (uint32_t i=0;i<4;i++){ + if(memcmp(_serial,kMINRFSlaveID+i,3)==0){ + DEBUG_SENSOR_LOG(PSTR("MINRF: MAC is type %u"), i); + _type = i+1; + } + else { + DEBUG_SENSOR_LOG(PSTR("MINRF: MAC-type is unknown")); + } + } + } + if(_type==0xff) return _type; // error + + DEBUG_SENSOR_LOG(PSTR("MINRF: vector size %u"), MIBLEsensors.size()); + for(uint32_t i=0; i6000){ // happens every 6000/20 = 300 seconds + DEBUG_SENSOR_LOG(PSTR("MINRF: check for FAKE sensors")); + MINRFpurgeFakeSensors(); + MINRF.timer=0; + } + MINRF.timer++; + + if (!MINRFreceivePacket()){ + // DEBUG_SENSOR_LOG(PSTR("MINRF: nothing received")); + } + + else if(MINRF.buffer.bleAdv.header.uuid==0xfe95){ // XIAOMI-BLE-Packet + MINRF_LOG_BUFFER(MINRF.streamBuffer); + MINRF_LOG_BUFFER(MINRF.lsfrBuffer); + MINRF_LOG_BUFFER(MINRF.buffer.raw); + DEBUG_SENSOR_LOG(PSTR("MINRF: Type: %x"), MINRF.buffer.bleAdv.header.type); + switch(MINRF.buffer.bleAdv.header.type){ + case 0x2050: + DEBUG_SENSOR_LOG(PSTR("MINRF: MJ_HT_V1 Packet")); + break; + case 0x1613:case 0x1614:case 0x1615: + DEBUG_SENSOR_LOG(PSTR("MINRF: Flora Packet")); + break; + default: + DEBUG_SENSOR_LOG(PSTR("MINRF: unknown Packet")); + break; + } + } + else if (MINRF.packetMode == FLORA){ + MINRFhandleFloraPacket(); + } + else if (MINRF.packetMode == MJ_HT_V1){ + MINRFhandleMJ_HT_V1Packet(); + } + else if (MINRF.packetMode == LYWSD02){ + MINRFhandleLYWSD02Packet(); + } + else if (MINRF.packetMode == LYWSD03){ + MINRFhandleLYWSD03Packet(); + } + + // DEBUG_SENSOR_LOG(PSTR("MINRF: Change packet mode every 50 msec")); + if (MINRF.packetMode == LYWSD03){ + MINRFinitBLE(1); // no real ble packets in release mode, otherwise for developing use 0 + } + else { + MINRFinitBLE(++MINRF.packetMode); + } + + MINRFhopChannel(); + NRF24radio.startListening(); +} +/*********************************************************************************************\ + * Presentation +\*********************************************************************************************/ + +const char HTTP_BATTERY[] PROGMEM = "{s}%s" " Battery" "{m}%u%%{e}"; +const char HTTP_MINRF_MAC[] PROGMEM = "{s}%s %s{m}%02x:%02x:%02x:%02x:%02x:%02x%{e}"; +const char HTTP_MINRF_FLORA_DATA[] PROGMEM = "{s}%s" " Fertility" "{m}%sus/cm{e}"; +const char HTTP_MINRF_HL[] PROGMEM = "{s}
{m}
{e}"; + +void MINRFShow(bool json) +{ + if (json) { + for (uint32_t i = 0; i < MIBLEsensors.size(); i++) { + if(MIBLEsensors.at(i).showedUp < 3){ + DEBUG_SENSOR_LOG(PSTR("MINRF: sensor not fully registered yet")); + break; + } + char slave[33]; + sprintf_P(slave,"%s-%02x%02x%02x",kMINRFSlaveType[MIBLEsensors.at(i).type-1],MIBLEsensors.at(i).serial[3],MIBLEsensors.at(i).serial[4],MIBLEsensors.at(i).serial[5]); + char temperature[33]; // all sensors have temperature + dtostrfd(MIBLEsensors.at(i).temp, Settings.flag2.temperature_resolution, temperature); + + ResponseAppend_P(PSTR(",\"%s\":{"),slave); + if(MIBLEsensors.at(i).temp!=-1000.0f){ // this is the error code -> no temperature + ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%s"), temperature); + } + if (MIBLEsensors.at(i).type==FLORA){ + char lux[33]; + char moisture[33]; + char fertility[33]; + dtostrfd((float)MIBLEsensors.at(i).lux, 0, lux); + dtostrfd(MIBLEsensors.at(i).moisture, 0, moisture); + dtostrfd(MIBLEsensors.at(i).fertility, 0, fertility); + if(MIBLEsensors.at(i).lux!=0xffff){ // this is the error code -> no temperature + ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%s"), lux); + } + if(MIBLEsensors.at(i).moisture!=-1000.0f){ // this is the error code -> no moisture + ResponseAppend_P(PSTR(",\"" D_JSON_MOISTURE "\":%s"), moisture); + } + if(MIBLEsensors.at(i).fertility!=-1000.0f){ // this is the error code -> no fertility + ResponseAppend_P(PSTR(",\"Fertility\":%s"), fertility); + } + } + if (MIBLEsensors.at(i).type>FLORA){ + char humidity[33]; + dtostrfd(MIBLEsensors.at(i).hum, Settings.flag2.humidity_resolution, humidity); + if(MIBLEsensors.at(i).hum!=-1.0f){ // this is the error code -> no humidity + ResponseAppend_P(PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity); + } + if(MIBLEsensors.at(i).bat!=0xff){ // this is the error code -> no battery + ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors.at(i).bat); + } + } + ResponseAppend_P(PSTR("}")); + } +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_NRF24, NRF24type, NRF24.chipType); + for (uint32_t i = 0; i < MIBLEsensors.size(); i++) { + if(MIBLEsensors.at(i).showedUp < 3){ + DEBUG_SENSOR_LOG(PSTR("MINRF: sensor not fully registered yet")); + break; + } + WSContentSend_PD(HTTP_MINRF_HL); + WSContentSend_PD(HTTP_MINRF_MAC, kMINRFSlaveType[MIBLEsensors.at(i).type-1], D_MAC_ADDRESS, MIBLEsensors.at(i).serial[0], MIBLEsensors.at(i).serial[1],MIBLEsensors.at(i).serial[2],MIBLEsensors.at(i).serial[3],MIBLEsensors.at(i).serial[4],MIBLEsensors.at(i).serial[5]); + if(MIBLEsensors.at(i).temp!=-1000.0f){ + char temperature[33]; + dtostrfd(MIBLEsensors.at(i).temp, Settings.flag2.temperature_resolution, temperature); + WSContentSend_PD(HTTP_SNS_TEMP, kMINRFSlaveType[MIBLEsensors.at(i).type-1], temperature, TempUnit()); + } + if (MIBLEsensors.at(i).type==FLORA){ + if(MIBLEsensors.at(i).lux!=0x00ffffff){ // this is the error code -> no valid value + WSContentSend_PD(HTTP_SNS_ILLUMINANCE, kMINRFSlaveType[MIBLEsensors.at(i).type-1], MIBLEsensors.at(i).lux); + } + if(MIBLEsensors.at(i).moisture!=-1000.0f){ // this is the error code -> no valid value + WSContentSend_PD(HTTP_SNS_MOISTURE, kMINRFSlaveType[MIBLEsensors.at(i).type-1], MIBLEsensors.at(i).moisture); + } + if(MIBLEsensors.at(i).fertility!=-1000.0f){ // this is the error code -> no valid value + char fertility[33]; + dtostrfd(MIBLEsensors.at(i).fertility, 0, fertility); + WSContentSend_PD(HTTP_MINRF_FLORA_DATA, kMINRFSlaveType[MIBLEsensors.at(i).type-1], fertility); + } + } + if (MIBLEsensors.at(i).type>FLORA){ // everything "above" Flora + if(MIBLEsensors.at(i).hum!=-1.0f){ // this is the error code -> no humidity + char humidity[33]; + dtostrfd(MIBLEsensors.at(i).hum, Settings.flag2.humidity_resolution, humidity); + WSContentSend_PD(HTTP_SNS_HUM, kMINRFSlaveType[MIBLEsensors.at(i).type-1], humidity); + } + if(MIBLEsensors.at(i).bat!=0xff){ + WSContentSend_PD(HTTP_BATTERY, kMINRFSlaveType[MIBLEsensors.at(i).type-1], MIBLEsensors.at(i).bat); + } + } + } +#endif // USE_WEBSERVER + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns61(uint8_t function) +{ + bool result = false; + + if (NRF24.chipType) { + switch (function) { + case FUNC_INIT: + MINRFinitBLE(1); + AddLog_P2(LOG_LEVEL_INFO,PSTR("MINRF: started")); + break; + case FUNC_EVERY_50_MSECOND: + MINRF_EVERY_50_MSECOND(); + break; + case FUNC_JSON_APPEND: + MINRFShow(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + MINRFShow(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_MIBLE +#endif // USE_NRF24 +#endif // USE_SPI + + From 39d100e1d199f4d0d660aa60a7322f1c7117f15f Mon Sep 17 00:00:00 2001 From: Staars Date: Thu, 13 Feb 2020 19:48:38 +0100 Subject: [PATCH 2/2] rename driver --- tasmota/xsns_61_MI_BLE.ino | 858 ------------------------------------- 1 file changed, 858 deletions(-) delete mode 100644 tasmota/xsns_61_MI_BLE.ino diff --git a/tasmota/xsns_61_MI_BLE.ino b/tasmota/xsns_61_MI_BLE.ino deleted file mode 100644 index c07323684..000000000 --- a/tasmota/xsns_61_MI_BLE.ino +++ /dev/null @@ -1,858 +0,0 @@ -/* - xsns_61_Ml_BLE.ino - MI-BLE-sensors via nrf24l01 support for Tasmota - - 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.1.0 20200117 integrate - Added support for the LYWSD02 - --- - 0.9.0.0 20191127 started - further development by Christian Baars - base - code base from cbm80amiga, floe, Dmitry.GR - forked - from arendst/tasmota - https://github.com/arendst/Tasmota - -*/ - -#ifdef USE_SPI -#ifdef USE_NRF24 -#ifdef USE_MIBLE - -#ifdef DEBUG_TASMOTA_SENSOR - #define MIBLE_LOG_BUFFER(x) MIBLEshowBuffer(x); -#else - #define MIBLE_LOG_BUFFER(x) -#endif - - -/*********************************************************************************************\ -* MIBLE -* BLE-Sniffer/Bridge for MIJIA/XIAOMI Temperatur/Humidity-Sensor, Mi Flora -* -* Usage: Configure NRF24 -\*********************************************************************************************/ - -#define XSNS_61 61 - -#include - -const char MIBLESlaveFlora[] PROGMEM = "Flora"; -const char MIBLESlaveMJ_HT_V1[] PROGMEM = "MJ_HT_V1"; -const char MIBLESlaveLYWSD02[] PROGMEM = "LYWSD02"; - -#pragma pack(1) // important!! -struct MJ_HT_V1Header_t {// related to the payload - uint8_t padding[3]; - uint8_t mesSize; // 3 - uint8_t padding2; - uint16_t uuid; // 5,6 -> 0xFE95 - uint16_t type; // 7,8 -> 0x2050 MI-TH-V1 - uint8_t padding3[2]; - uint8_t counter; // 11 - counts up with every sent record - uint8_t serial[6]; // 12 - 17 - uint8_t mode; // 18 - uint8_t padding5; - uint8_t effectiveDataLength; - }; - -struct FlowerHeader_t { // related to the payload - uint8_t padding[4]; - uint8_t padding2; - uint16_t uuid; // 5,6 -> 0xFE95 - uint8_t mesSize; - uint8_t padding22; - uint16_t uuid2; // 9,10 -> 0xFE95 - uint16_t type; // 11,12 -> 0x7120 Flowercare - uint8_t padding3[2]; - uint8_t counter; // 15 - counts up with every sent record - uint8_t serial[6]; // 16 - 21 - uint8_t padding4; //22 - uint8_t mode; // 23 - }; - -union floraPacket_t { // related to the whole 32-byte-packet/buffer - struct { - uint16_t idWord; - uint8_t padding; - uint8_t serial[6]; - uint8_t padding4; - uint8_t mode; - uint8_t valueTen; - uint8_t effectiveDataLength; // 1 - uint16_t data; - } T; // mode 04 - struct { - uint16_t idWord; - uint8_t padding; - uint8_t serial[6]; - uint8_t padding4; - uint8_t mode; - uint8_t valueTen; - uint8_t effectiveDataLength; // 3 - uint16_t data; - uint8_t data2; // unknown meaning, maybe it is a real uint24_t (data with data2) - } L; // mode 07 - struct { - uint8_t padding[3]; - uint8_t serial[6]; - uint8_t padding4; - uint8_t mode; - uint8_t valueTen; - uint8_t effectiveDataLength; // 1 - uint8_t data; - } M; // mode 08 - struct { - uint8_t padding[3]; - uint8_t serial[6]; - uint8_t padding4; - uint8_t mode; - uint8_t valueTen; - uint8_t effectiveDataLength; // 2 - uint16_t data; - } F; // mode 09 -}; - -union MJ_HT_V1Packet_t { // related to the whole 32-byte-packet/buffer - struct { - uint16_t idWord; - uint8_t padding; - uint8_t serial[6]; - uint8_t mode; - uint8_t valueTen; - uint8_t effectiveDataLength; // 4 - uint16_t temp; - uint16_t hum; - } TH; // mode 0d - struct { - uint8_t padding[3]; - uint8_t serial[6]; - uint8_t mode; - uint8_t valueTen; - uint8_t effectiveDataLength; // 1 - uint8_t battery; - } B; // mode 0a - // We do NOT need the isolated T and H packet -}; - -union LYWSD02Packet_t { // related to the whole 32-byte-packet/buffer - struct { - uint16_t idWord; - uint8_t padding; - uint8_t serial[6]; - uint8_t padding4; - uint8_t mode; - uint8_t valueTen; - uint8_t effectiveDataLength; - uint16_t data; - } TH; // mode 04 or 06 -}; - -struct bleAdvPacket_t { // for nRF24L01 max 32 bytes = 2+6+24 - uint8_t pduType; - uint8_t payloadSize; - uint8_t mac[6]; - union { - uint8_t payload[24]; - MJ_HT_V1Header_t header; - FlowerHeader_t flowerHeader; - struct { - uint8_t padding[21]; - uint16_t temp; - uint8_t hum_lb; // the high byte does not fit into the RX_buffer - } TH; // mode 0d - struct { - uint8_t padding[21]; - uint16_t temp; - } T; // mode 04 - struct { - uint8_t padding[21]; - uint16_t hum; - } H; // mode 06 - struct { - uint8_t padding[21]; - uint8_t battery; - } B; // mode 0a - struct { - uint8_t padding[2]; - uint8_t mode; - uint16_t size; // 2 - uint16_t data; - } F_T; // mode 04 - struct { - uint8_t padding[2]; - uint8_t mode; - uint16_t size; // 3 - uint16_t data; - uint8_t data2; // unknown meaning, maybe it is a real uint24_t (data with data2) - } F_L; // mode 07 - struct { - uint8_t padding[2]; - uint8_t mode; - uint16_t size; // 1 - uint8_t data; - } F_M; // mode 08 - struct { - uint8_t padding[2]; - uint8_t mode; - uint16_t size; // 2 - uint16_t data; - } F_F; // mode 09 - }; -}; - -union FIFO_t{ - bleAdvPacket_t bleAdv; - floraPacket_t floraPacket; - MJ_HT_V1Packet_t MJ_HT_V1Packet; - LYWSD02Packet_t LYWSD02Packet; - uint8_t raw[32]; -}; - -#pragma pack(0) - -struct { - const uint8_t channel[3] = {37,38,39}; // BLE advertisement channel number - const uint8_t frequency[3] = { 2,26,80}; // real frequency (2400+x MHz) - - uint16_t timer; - uint8_t currentChan=0; - FIFO_t buffer; - uint8_t packetMode; // 0 - normal BLE-advertisements, 1 - special "flora"-packet, 2 - special "MJ_HT_V1"-packet - -#ifdef DEBUG_TASMOTA_SENSOR - uint8_t streamBuffer[sizeof(buffer)]; // raw data stream bytes - uint8_t lsfrBuffer[sizeof(buffer)]; // correpsonding lfsr-bytes for the buffer, probably only useful for a BLE-packet -#endif // DEBUG_TASMOTA_SENSOR - -} MIBLE; - -struct mi_sensor_t{ - uint8_t type; //flora = 1; MI-HT_V1=2; LYWSD02=3 - uint8_t serial[6]; - uint8_t showedUp; - union { - struct { - float temp; - float moisture; - float fertility; - uint16_t lux; - } Flora; - struct { - float temp; - float hum; - uint8_t bat; - } MJ_HT_V1; - struct { - float temp; - float hum; - } LYWSD02; - }; -}; - -std::vector MIBLEsensors; - -/********************************************************************************************/ - - -bool MIBLEinitBLE(uint8_t _mode) -{ - NRF24radio.begin(pin[GPIO_SPI_CS],pin[GPIO_SPI_DC]); - NRF24radio.setAutoAck(false); - NRF24radio.setDataRate(RF24_1MBPS); - NRF24radio.disableCRC(); - NRF24radio.setChannel( MIBLE.frequency[MIBLE.currentChan] ); - NRF24radio.setRetries(0,0); - NRF24radio.setPALevel(RF24_PA_MIN); // we only receive - NRF24radio.setAddressWidth(4); - // NRF24radio.openReadingPipe(0,0x6B7D9171); // advertisement address: 0x8E89BED6 (bit-reversed -> 0x6B7D9171) - // NRF24radio.openWritingPipe( 0x6B7D9171); // not used ATM - NRF24radio.powerUp(); - - if(NRF24radio.isChipConnected()){ - DEBUG_SENSOR_LOG(PSTR("MIBLE chip connected")); - MIBLEchangePacketModeTo(_mode); - return true; - } - DEBUG_SENSOR_LOG(PSTR("MIBLE chip NOT !!!! connected")); - return false; -} - -void MIBLEhopChannel() -{ - MIBLE.currentChan++; - if(MIBLE.currentChan >= sizeof(MIBLE.channel)) { - MIBLE.currentChan = 0; - } - NRF24radio.setChannel( MIBLE.frequency[MIBLE.currentChan] ); -} - -/** - * @brief Read out FIFO-buffer, swap buffer and whiten - * - * @return true - If something is in the buffer - * @return false - Nothing is in the buffer - */ -bool MIBLEreceivePacket(void) -{ - if(!NRF24radio.available()) { - return false; - } - while(NRF24radio.available()) { - // static uint8_t _lsfr = 0; //-> for testing out suitable lsfr-start-values for yet unknown packets - // _lsfr++; - NRF24radio.read( &MIBLE.buffer, sizeof(MIBLE.buffer) ); -#ifdef DEBUG_TASMOTA_SENSOR - memcpy(&MIBLE.streamBuffer, &MIBLE.buffer, sizeof(MIBLE.buffer)); -#endif // DEBUG_TASMOTA_SENSOR - MIBLEswapbuf( sizeof(MIBLE.buffer) ); - // MIBLE_LOG_BUFFER(); - switch (MIBLE.packetMode) { - case 0: - MIBLEwhiten((uint8_t *)&MIBLE.buffer, sizeof(MIBLE.buffer), MIBLE.channel[MIBLE.currentChan] | 0x40); - break; - case 1: - MIBLEwhiten((uint8_t *)&MIBLE.buffer, sizeof(MIBLE.buffer), 0x17); // "flora" mode 0x17 - break; - case 2: - MIBLEwhiten((uint8_t *)&MIBLE.buffer, sizeof(MIBLE.buffer), 0x72); // "MJ_HT_V1" mode 0x72 - break; - case 3: - MIBLEwhiten((uint8_t *)&MIBLE.buffer, sizeof(MIBLE.buffer), 0x17); // "LYWSD02" mode 0x17 - break; - } - // DEBUG_SENSOR_LOG(PSTR("MIBLE: LSFR:%x"),_lsfr); - // if (_lsfr>254) _lsfr=0; - } - // DEBUG_SENSOR_LOG(PSTR("MIBLE: did read FIFO")); - return true; -} - -#ifdef DEBUG_TASMOTA_SENSOR -void MIBLEshowBuffer(uint8_t (&buf)[32]){ // we use this only for the 32-byte-FIFO-buffer, so 32 is hardcoded - // DEBUG_SENSOR_LOG(PSTR("MIBLE: Buffer: %c %c %c %c %c %c %c %c" - // " %c %c %c %c %c %c %c %c" - // " %c %c %c %c %c %c %c %c" - // " %c %c %c %c %c %c %c %c") - DEBUG_SENSOR_LOG(PSTR("MIBLE: Buffer: %02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x ") - ,buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10],buf[11], - buf[12],buf[13],buf[14],buf[15],buf[16],buf[17],buf[18],buf[19],buf[20],buf[21],buf[22],buf[23], - buf[24],buf[25],buf[26],buf[27],buf[28],buf[29],buf[30],buf[31] - ); -} -#endif // DEBUG_TASMOTA_SENSOR - -/** - * @brief change lsfrBuffer content to "wire bit order" - * - * @param len Buffer lenght (could be hardcoded to 32) - */ -void MIBLEswapbuf(uint8_t len) -{ - uint8_t* buf = (uint8_t*)&MIBLE.buffer; - while(len--) { - uint8_t a = *buf; - uint8_t v = 0; - if (a & 0x80) v |= 0x01; - if (a & 0x40) v |= 0x02; - if (a & 0x20) v |= 0x04; - if (a & 0x10) v |= 0x08; - if (a & 0x08) v |= 0x10; - if (a & 0x04) v |= 0x20; - if (a & 0x02) v |= 0x40; - if (a & 0x01) v |= 0x80; - *(buf++) = v; - } -} - -/** - * @brief Whiten the packet buffer - * - * @param buf The packet buffer - * @param len Lenght of the packet buffer - * @param lfsr Start lsfr-byte - */ -void MIBLEwhiten(uint8_t *buf, uint8_t len, uint8_t lfsr) -{ - while(len--) { - uint8_t res = 0; - // LFSR in "wire bit order" - for (uint8_t i = 1; i; i <<= 1) { - if (lfsr & 0x01) { - lfsr ^= 0x88; - res |= i; - } - lfsr >>= 1; - } - *(buf++) ^= res; -#ifdef DEBUG_TASMOTA_SENSOR - MIBLE.lsfrBuffer[31-len] = lfsr; -#endif //DEBUG_TASMOTA_SENSOR - } -} - - -/** - * @brief Set packet mode and fitting PDU-type of the NRF24L01 - * - * @param _mode The internal packet mode number - */ -void MIBLEchangePacketModeTo(uint8_t _mode) { - switch(_mode){ - case 0: // normal BLE advertisement - NRF24radio.openReadingPipe(0,0x6B7D9171); // advertisement address: 0x8E89BED6 (bit-reversed -> 0x6B7D9171) - break; - case 1: // special flora packet - NRF24radio.openReadingPipe(0,0xef3b8730); // 95 fe 71 20 -> flora, needs lfsr 0x17 - break; - case 2: // special MJ_HT_V1 packet - NRF24radio.openReadingPipe(0,0xdbcc0cd3); // 95 fe 50 20 -> MJ_HT_V1, needs lsfr 0x72 - break; - case 3: // special LYWSD02 packet - NRF24radio.openReadingPipe(0,0xef3b0730); // 95 fe 70 20 -> LYWSD02, needs lfsr 0x17 - break; - } - DEBUG_SENSOR_LOG(PSTR("MIBLE: Change Mode to %u"),_mode); - MIBLE.timer = 0; - MIBLE.packetMode = _mode; -} - -/** - * @brief Return the slot number of a known sensor or return create new sensor slot - * - * @param _serial BLE address of the sensor - * @param _type Type number of the sensor - * @return uint32_t Known or new slot in the sensors-vector - */ -uint32_t MIBLEgetSensorSlot(uint8_t (&_serial)[6], uint8_t _type){ - DEBUG_SENSOR_LOG(PSTR("MIBLE: vector size %u"), MIBLEsensors.size()); - for(uint32_t i=0; i600){ // Change read mode every n/10 seconds - if(++_purgeCounter>8){ // happens every 8 x 600 = 4800 seconds - DEBUG_SENSOR_LOG(PSTR("MIBLE: check for FAKE sensors")); - MIBLEpurgeFakeSensors(); - } - DEBUG_SENSOR_LOG(PSTR("MIBLE: Change packet mode after 60 seconds, MIBLE.timer: %u"),MIBLE.timer); - if (MIBLE.packetMode == 3){ - MIBLEinitBLE(1); // no real ble packets in release mode, otherwise for developing use 0 - } - else { - MIBLEinitBLE(MIBLE.packetMode + 1); - } - } - MIBLE.timer++; - - if (!MIBLEreceivePacket()){ - MIBLEhopChannel(); - NRF24radio.startListening(); - return; - } - - if(MIBLE.buffer.bleAdv.header.uuid==0xfe95){ // XIAOMI-BLE-Packet - MIBLE_LOG_BUFFER(MIBLE.streamBuffer); - MIBLE_LOG_BUFFER(MIBLE.lsfrBuffer); - MIBLE_LOG_BUFFER(MIBLE.buffer.raw); - DEBUG_SENSOR_LOG(PSTR("MIBLE: Type: %x"), MIBLE.buffer.bleAdv.header.type); - switch(MIBLE.buffer.bleAdv.header.type){ - case 0x2050: - DEBUG_SENSOR_LOG(PSTR("MIBLE: MJ_HT_V1 Packet")); - break; - case 0x1613:case 0x1614:case 0x1615: - DEBUG_SENSOR_LOG(PSTR("MIBLE: Flora Packet")); - break; - default: - DEBUG_SENSOR_LOG(PSTR("MIBLE: unknown Packet")); - break; - } - } - if (MIBLE.packetMode == 1){ // "flora" mode - MIBLEhandleFloraPacket(); - } - if (MIBLE.packetMode == 2){ // "MJ_HT_V1" mode - MIBLEhandleMJ_HT_V1Packet(); - } - if (MIBLE.packetMode == 3){ // "LYWSD02" mode - MIBLEhandleLYWSD02Packet(); - } - - MIBLEhopChannel(); - NRF24radio.startListening(); -} - -const char HTTP_MIBLE_SERIAL[] PROGMEM = - "{s}%s" " Address" "{m}%02x:%02x:%02x:%02x:%02x:%02x%{e}"; -const char HTTP_BATTERY[] PROGMEM = - "{s}%s" " Battery" "{m}%u%%{e}"; - -const char HTTP_MIBLE_FLORA_DATA[] PROGMEM = - "{s}%s" " Fertility" "{m}%sus/cm{e}"; - - -void MIBLEShow(bool json) -{ - if (json) { - if (!MIBLEsensors.size()) { return; } - - for (uint32_t i = 0; i < MIBLEsensors.size(); i++) { - char slave[33]; - switch(MIBLEsensors.at(i).type){ - case 1: - if(MIBLEsensors.at(i).showedUp < 3){ - DEBUG_SENSOR_LOG(PSTR("MIBLE: sensor not fully registered yet")); - break; - } - sprintf_P(slave,"%s-%02x%02x%02x",MIBLESlaveFlora,MIBLEsensors.at(i).serial[2],MIBLEsensors.at(i).serial[1],MIBLEsensors.at(i).serial[0]); - char temperature_flora[33]; - dtostrfd(MIBLEsensors.at(i).Flora.temp, Settings.flag2.temperature_resolution, temperature_flora); - char lux_flora[33]; - dtostrfd((float)MIBLEsensors.at(i).Flora.lux, 0, lux_flora); - char moisture_flora[33]; - dtostrfd(MIBLEsensors.at(i).Flora.moisture, 0, moisture_flora); - char fertility_flora[33]; - dtostrfd(MIBLEsensors.at(i).Flora.fertility, 0, fertility_flora); - ResponseAppend_P(PSTR(",\"%s\":{"),slave); - if(MIBLEsensors.at(i).Flora.temp!=-1000.0f){ // this is the error code -> no temperature - ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%s"), temperature_flora); - } - if(MIBLEsensors.at(i).Flora.lux!=0xffff){ // this is the error code -> no temperature - ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%s"), lux_flora); - } - if(MIBLEsensors.at(i).Flora.moisture!=-1000.0f){ // this is the error code -> no temperature - ResponseAppend_P(PSTR(",\"" D_JSON_MOISTURE "\":%s"), moisture_flora); - } - if(MIBLEsensors.at(i).Flora.fertility!=-1000.0f){ // this is the error code -> no temperature - ResponseAppend_P(PSTR(",\"Fertility\":%s"), fertility_flora); - } - ResponseAppend_P(PSTR("}")); - break; - case 2: - if(MIBLEsensors.at(i).showedUp < 3){ - DEBUG_SENSOR_LOG(PSTR("MIBLE: sensor not fully registered yet")); - break; - } - sprintf_P(slave,"%s-%02x%02x%02x",MIBLESlaveMJ_HT_V1,MIBLEsensors.at(i).serial[2],MIBLEsensors.at(i).serial[1],MIBLEsensors.at(i).serial[0]); - char temperature[33]; - dtostrfd(MIBLEsensors.at(i).MJ_HT_V1.temp, Settings.flag2.temperature_resolution, temperature); - char humidity[33]; - dtostrfd(MIBLEsensors.at(i).MJ_HT_V1.hum, 1, humidity); - ResponseAppend_P(PSTR(",\"%s\":{"),slave); - if(MIBLEsensors.at(i).MJ_HT_V1.temp!=-1000.0f){ // this is the error code -> no temperature - ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%s"), temperature); - } - if(MIBLEsensors.at(i).MJ_HT_V1.hum!=-1000.0f){ // this is the error code -> no temperature - ResponseAppend_P(PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity); - } - if(MIBLEsensors.at(i).MJ_HT_V1.bat!=0xff){ // this is the error code -> no temperature - ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors.at(i).MJ_HT_V1.bat); - } - ResponseAppend_P(PSTR("}")); - break; - case 3: - if(MIBLEsensors.at(i).showedUp < 3){ - DEBUG_SENSOR_LOG(PSTR("MIBLE: sensor not fully registered yet")); - break; - } - sprintf_P(slave,"%s-%02x%02x%02x",MIBLESlaveLYWSD02,MIBLEsensors.at(i).serial[2],MIBLEsensors.at(i).serial[1],MIBLEsensors.at(i).serial[0]); - dtostrfd(MIBLEsensors.at(i).LYWSD02.temp, Settings.flag2.temperature_resolution, temperature); - dtostrfd(MIBLEsensors.at(i).LYWSD02.hum, 1, humidity); - ResponseAppend_P(PSTR(",\"%s\":{"),slave); - if(MIBLEsensors.at(i).LYWSD02.temp!=-1000.0f){ // this is the error code -> no temperature - ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%s"), temperature); - } - if(MIBLEsensors.at(i).LYWSD02.hum!=-1000.0f){ // this is the error code -> no temperature - ResponseAppend_P(PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity); - } - ResponseAppend_P(PSTR("}")); - break; - } - } -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_NRF24, NRF24type, NRF24.chipType); - - if (!MIBLEsensors.size()) { return; } - - for (uint32_t i = 0; i < MIBLEsensors.size(); i++) { - switch(MIBLEsensors.at(i).type){ - case 1: - if(MIBLEsensors.at(i).showedUp < 3){ - DEBUG_SENSOR_LOG(PSTR("MIBLE: sensor not fully registered yet")); - break; - } - char temperature_flora[33]; - dtostrfd(MIBLEsensors.at(i).Flora.temp, Settings.flag2.temperature_resolution, temperature_flora); - char lux_flora[33]; - dtostrfd((float)MIBLEsensors.at(i).Flora.lux, 0, lux_flora); - char fertility_flora[33]; - dtostrfd(MIBLEsensors.at(i).Flora.fertility, 0, fertility_flora); - - WSContentSend_PD(HTTP_MIBLE_SERIAL, F("Flora "), MIBLEsensors.at(i).serial[5], MIBLEsensors.at(i).serial[4],MIBLEsensors.at(i).serial[3],MIBLEsensors.at(i).serial[2],MIBLEsensors.at(i).serial[1],MIBLEsensors.at(i).serial[0]); - if(MIBLEsensors.at(i).Flora.temp!=-1000.0f){ // this is the error code -> no temperature - WSContentSend_PD(HTTP_SNS_TEMP, MIBLESlaveFlora, temperature_flora, TempUnit()); - } - if(MIBLEsensors.at(i).Flora.lux!=0xffff){ // this is the error code -> no temperature - WSContentSend_PD(HTTP_SNS_ILLUMINANCE, MIBLESlaveFlora, MIBLEsensors.at(i).Flora.lux); - } - if(MIBLEsensors.at(i).Flora.moisture!=-1000.0f){ // this is the error code -> no temperature - WSContentSend_PD(HTTP_SNS_MOISTURE, MIBLESlaveFlora, MIBLEsensors.at(i).Flora.moisture); - } - if(MIBLEsensors.at(i).Flora.fertility!=-1000.0f){ // this is the error code -> no temperature - WSContentSend_PD(HTTP_MIBLE_FLORA_DATA, MIBLESlaveFlora, fertility_flora); - } - break; - case 2: - if(MIBLEsensors.at(i).showedUp < 3){ - DEBUG_SENSOR_LOG(PSTR("MIBLE: sensor not fully registered yet")); - break; - } - char temperature[33]; - dtostrfd(MIBLEsensors.at(i).MJ_HT_V1.temp, Settings.flag2.temperature_resolution, temperature); - char humidity[33]; - dtostrfd(MIBLEsensors.at(i).MJ_HT_V1.hum, 1, humidity); - - WSContentSend_PD(HTTP_MIBLE_SERIAL, MIBLESlaveMJ_HT_V1, MIBLEsensors.at(i).serial[5], MIBLEsensors.at(i).serial[4],MIBLEsensors.at(i).serial[3],MIBLEsensors.at(i).serial[2],MIBLEsensors.at(i).serial[1],MIBLEsensors.at(i).serial[0]); - if(MIBLEsensors.at(i).MJ_HT_V1.temp!=-1000.0f){ - WSContentSend_PD(HTTP_SNS_TEMP, MIBLESlaveMJ_HT_V1, temperature, TempUnit()); - } - if(MIBLEsensors.at(i).MJ_HT_V1.hum!=-1.0f){ - WSContentSend_PD(HTTP_SNS_HUM, MIBLESlaveMJ_HT_V1, humidity); - } - if(MIBLEsensors.at(i).MJ_HT_V1.bat!=0xff){ - WSContentSend_PD(HTTP_BATTERY, MIBLESlaveMJ_HT_V1, MIBLEsensors.at(i).MJ_HT_V1.bat); - } - break; - case 3: - if(MIBLEsensors.at(i).showedUp < 3){ - DEBUG_SENSOR_LOG(PSTR("MIBLE: sensor not fully registered yet")); - break; - } - dtostrfd(MIBLEsensors.at(i).LYWSD02.temp, Settings.flag2.temperature_resolution, temperature); - dtostrfd(MIBLEsensors.at(i).LYWSD02.hum, 1, humidity); - - WSContentSend_PD(HTTP_MIBLE_SERIAL, MIBLESlaveLYWSD02, MIBLEsensors.at(i).serial[5], MIBLEsensors.at(i).serial[4],MIBLEsensors.at(i).serial[3],MIBLEsensors.at(i).serial[2],MIBLEsensors.at(i).serial[1],MIBLEsensors.at(i).serial[0]); - if(MIBLEsensors.at(i).LYWSD02.temp!=-1000.0f){ - WSContentSend_PD(HTTP_SNS_TEMP, MIBLESlaveLYWSD02, temperature, TempUnit()); - } - if(MIBLEsensors.at(i).LYWSD02.hum!=-1.0f){ - WSContentSend_PD(HTTP_SNS_HUM, MIBLESlaveLYWSD02, humidity); - } - break; - } - } - } -#endif // USE_WEBSERVER -} - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -bool Xsns61(uint8_t function) -{ - bool result = false; - - if (NRF24.chipType) { - switch (function) { - case FUNC_INIT: - MIBLEinitBLE(1); - AddLog_P2(LOG_LEVEL_INFO,PSTR("MIBLE: started")); - break; - case FUNC_EVERY_100_MSECOND: - MIBLE_EVERY_100_MSECOND(); - break; - case FUNC_JSON_APPEND: - MIBLEShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - MIBLEShow(0); - break; -#endif // USE_WEBSERVER - } - } - return result; -} - -#endif // USE_MIBLE -#endif // USE_NRF24 -#endif // USE_SPI -