diff --git a/tasmota/xsns_76_dyp.ino b/tasmota/xsns_76_dyp.ino new file mode 100644 index 000000000..7e873fe30 --- /dev/null +++ b/tasmota/xsns_76_dyp.ino @@ -0,0 +1,158 @@ +/* + xsns_76_dyp.ino - DYP ME007 serial interface + + Copyright (C) 2020 Janusz Kostorz + + This program is free software: you can reDYPDistanceribute 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 DYPDistanceributed 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 . +*/ + +#ifdef USE_DYP + +/*********************************************************************************************\ + * DYP ME007 ultrasonic distanceance sensor (300...4000mm), serial version + * + * Every one second code check last received value from sensor via serial port and return: + * -1 for checksum error + * 0 for distance below 300mm + * 300...4000 for measured distance + * 4999 for distance above 4000mm + * 5999 for not connected sensor + * +\*********************************************************************************************/ + +#define XSNS_76 76 + +#include + +TasmotaSerial *DYPSerial = nullptr; + +#define DYP_CRCERROR -1 +#define DYP_BELOWMIN 0 +#define DYP_MIN 300 +#define DYP_MAX 4000 +#define DYP_ABOVEMAX 4999 +#define DYP_NOSENSOR 5999 + +uint16_t DYPDistance = 0; // distance in milimeters +bool DYPSensor = false; // sensor available + +/*********************************************************************************************/ + +void DYPInit(void) +{ + DYPSensor = false; + if (PinUsed(GPIO_DYP_RX)) + { + DYPSerial = new TasmotaSerial(Pin(GPIO_DYP_RX), -1, 1); + if (DYPSerial->begin(9600)) + { + if (DYPSerial->hardwareSerial()) + ClaimSerial(); + DYPSensor = true; + } + } +} + +void DYPEverySecond(void) +{ + if (!DYPSensor) + return; + + // check for serial data + if (DYPSerial->available() < 6) + { + DYPDistance = DYP_NOSENSOR; + return; + } + + + // trash old data (only 7 last bytes are nedded for calculate DYPDistance) + while (DYPSerial->available() > 7) + DYPSerial->read(); + + + // read data from serial port - * 0xFF MSB LSB CRC * + while (DYPSerial->available() > 3) + { + // check for start byte signature + if (DYPSerial->read() != 0xFF) + continue; + + // check for data bytes + if (DYPSerial->available() > 2) + { + uint8_t msb = DYPSerial->read(); + uint8_t lsb = DYPSerial->read(); + if (((uint16_t)(0xFF + msb + lsb) & 0xFF) == DYPSerial->read()) { + uint16_t data = (msb << 8) | lsb; + if (data < DYP_MIN) + data = DYP_BELOWMIN; + if (data > DYP_MAX) + data = DYP_ABOVEMAX; + DYPDistance = data; + } + else { + DYPDistance = DYP_CRCERROR; + } + } + } + + +} + +void DYPShow(bool json) +{ + char types[5] = "DYP"; + if (json) + { + ResponseAppend_P(PSTR(",\"%s\":{\"" D_DISTANCE "\":%d}"), types, DYPDistance); + #ifdef USE_WEBSERVER + } + else + { + WSContentSend_PD(HTTP_SNS_RANGE, types, DYPDistance); + #endif // USE_WEBSERVER + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns76(uint8_t function) +{ + if (!PinUsed(GPIO_DYP_RX)) + return false; + + switch (function) + { + case FUNC_INIT: + DYPInit(); + break; + case FUNC_EVERY_SECOND: + DYPEverySecond(); + break; + case FUNC_JSON_APPEND: + DYPShow(1); + break; + #ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + DYPShow(0); + break; + #endif // USE_WEBSERVER + } + return false; +} + +#endif // USE_DYP