2018-04-20 13:31:09 +01:00
/*
2019-10-27 10:13:24 +00:00
xsns_22_sr04 . ino - SR04 ultrasonic sensor support for Tasmota
2018-04-20 13:31:09 +01:00
2021-01-01 12:44:04 +00:00
Copyright ( C ) 2021 Nuno Ferreira and Theo Arends
2018-04-20 13:31:09 +01:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# ifdef USE_SR04
2018-11-28 09:33:59 +00:00
# include <NewPing.h>
2019-11-15 22:10:07 +00:00
# include <TasmotaSerial.h>
2018-04-20 13:31:09 +01:00
/*********************************************************************************************\
* HC - SR04 , HC - SR04 + , JSN - SR04T - Ultrasonic distance sensor
*
* Code for SR04 family of ultrasonic distance sensors
* References :
* - https : //www.dfrobot.com/wiki/index.php/Weather-proof_Ultrasonic_Sensor_SKU_:_SEN0207
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-03-11 15:49:59 +00:00
# define XSNS_22 22
2019-11-15 22:10:07 +00:00
uint8_t sr04_type = 1 ;
2018-11-28 09:33:59 +00:00
real64_t distance ;
2018-04-20 13:31:09 +01:00
2019-03-26 17:26:50 +00:00
NewPing * sonar = nullptr ;
2019-11-15 22:10:07 +00:00
TasmotaSerial * sonar_serial = nullptr ;
uint8_t Sr04TModeDetect ( void )
2019-12-31 13:23:34 +00:00
{
2019-11-15 22:10:07 +00:00
sr04_type = 0 ;
2020-04-27 16:16:52 +01:00
if ( ! PinUsed ( GPIO_SR04_ECHO ) ) { return sr04_type ; }
2018-04-20 13:31:09 +01:00
2020-04-27 11:54:07 +01:00
int sr04_echo_pin = Pin ( GPIO_SR04_ECHO ) ;
int sr04_trig_pin = ( PinUsed ( GPIO_SR04_TRIG ) ) ? Pin ( GPIO_SR04_TRIG ) : Pin ( GPIO_SR04_ECHO ) ; // if GPIO_SR04_TRIG is not configured use single PIN mode with GPIO_SR04_ECHO only
2019-11-15 22:10:07 +00:00
sonar_serial = new TasmotaSerial ( sr04_echo_pin , sr04_trig_pin , 1 ) ;
2019-12-31 13:23:34 +00:00
if ( sonar_serial - > begin ( 9600 , 1 ) ) {
2019-11-15 22:10:07 +00:00
DEBUG_SENSOR_LOG ( PSTR ( " SR04: Detect mode " ) ) ;
2019-12-31 13:23:34 +00:00
2020-04-15 15:22:20 +01:00
if ( sr04_trig_pin ! = - 1 ) {
sr04_type = ( Sr04TMiddleValue ( Sr04TMode3Distance ( ) , Sr04TMode3Distance ( ) , Sr04TMode3Distance ( ) ) ! = NO_ECHO ) ? 3 : 1 ;
2019-11-15 22:10:07 +00:00
} else {
2020-04-15 15:22:20 +01:00
sr04_type = 2 ;
2019-11-15 22:10:07 +00:00
}
} else {
sr04_type = 1 ;
}
if ( sr04_type < 2 ) {
2020-04-15 15:22:20 +01:00
delete sonar_serial ;
sonar_serial = nullptr ;
if ( - 1 = = sr04_trig_pin ) {
2020-04-27 11:54:07 +01:00
sr04_trig_pin = Pin ( GPIO_SR04_ECHO ) ; // if GPIO_SR04_TRIG is not configured use single PIN mode with GPIO_SR04_ECHO only
2020-04-15 15:22:20 +01:00
}
sonar = new NewPing ( sr04_trig_pin , sr04_echo_pin , 300 ) ;
2019-11-15 22:10:07 +00:00
} else {
if ( sonar_serial - > hardwareSerial ( ) ) {
ClaimSerial ( ) ;
}
}
2020-11-06 16:09:13 +00:00
AddLog_P ( LOG_LEVEL_INFO , PSTR ( " SR04: Mode %d " ) , sr04_type ) ;
2019-11-15 22:10:07 +00:00
return sr04_type ;
}
uint16_t Sr04TMiddleValue ( uint16_t first , uint16_t second , uint16_t third )
{
uint16_t ret = first ;
if ( first > second ) {
first = second ;
second = ret ;
}
if ( third < first ) {
return first ;
} else if ( third > second ) {
return second ;
} else {
return third ;
2019-12-31 13:23:34 +00:00
}
2019-11-15 22:10:07 +00:00
}
uint16_t Sr04TMode3Distance ( ) {
2019-12-31 13:23:34 +00:00
2019-11-15 22:10:07 +00:00
sonar_serial - > write ( 0x55 ) ;
sonar_serial - > flush ( ) ;
return Sr04TMode2Distance ( ) ;
}
2019-12-31 13:23:34 +00:00
uint16_t Sr04TMode2Distance ( void )
{
2019-11-15 22:10:07 +00:00
sonar_serial - > setTimeout ( 300 ) ;
const char startByte = 0xff ;
2019-12-31 13:23:34 +00:00
2019-11-15 22:10:07 +00:00
if ( ! sonar_serial - > find ( startByte ) ) {
//DEBUG_SENSOR_LOG(PSTR("SR04: No start byte"));
return NO_ECHO ;
2019-12-31 13:23:34 +00:00
}
2019-11-15 22:10:07 +00:00
delay ( 5 ) ;
uint8_t crc = sonar_serial - > read ( ) ;
//read high byte
2019-12-31 13:23:34 +00:00
uint16_t distance = ( ( uint16_t ) crc ) < < 8 ;
2019-11-15 22:10:07 +00:00
2019-12-31 13:23:34 +00:00
//read low byte
2019-11-15 22:10:07 +00:00
distance + = sonar_serial - > read ( ) ;
crc + = distance & 0x00ff ;
crc + = 0x00FF ;
//check crc sum
if ( crc ! = sonar_serial - > read ( ) ) {
2020-11-06 16:09:13 +00:00
AddLog_P ( LOG_LEVEL_ERROR , PSTR ( " SR04: Reading CRC error. " ) ) ;
2019-11-15 22:10:07 +00:00
return NO_ECHO ;
2019-12-31 13:23:34 +00:00
}
2019-11-15 22:10:07 +00:00
//DEBUG_SENSOR_LOG(PSTR("SR04: Distance: %d"), distance);
2019-12-31 13:23:34 +00:00
return distance ;
2019-11-15 22:10:07 +00:00
}
void Sr04TReading ( void ) {
2019-12-31 13:23:34 +00:00
2019-11-15 22:10:07 +00:00
if ( sonar_serial = = nullptr & & sonar = = nullptr ) {
Sr04TModeDetect ( ) ;
}
switch ( sr04_type ) {
case 3 :
2019-12-31 13:23:34 +00:00
distance = ( real64_t ) ( Sr04TMiddleValue ( Sr04TMode3Distance ( ) , Sr04TMode3Distance ( ) , Sr04TMode3Distance ( ) ) ) / 10 ; //convert to cm
2019-11-15 22:10:07 +00:00
break ;
case 2 :
//empty input buffer first
while ( sonar_serial - > available ( ) ) sonar_serial - > read ( ) ;
distance = ( real64_t ) ( Sr04TMiddleValue ( Sr04TMode2Distance ( ) , Sr04TMode2Distance ( ) , Sr04TMode2Distance ( ) ) ) / 10 ;
break ;
case 1 :
distance = ( real64_t ) ( sonar - > ping_median ( 5 ) ) / US_ROUNDTRIP_CM ;
break ;
default :
distance = NO_ECHO ;
}
return ;
2018-04-20 13:31:09 +01:00
}
# ifdef USE_WEBSERVER
const char HTTP_SNS_DISTANCE [ ] PROGMEM =
2019-03-19 16:31:43 +00:00
" {s}SR04 " D_DISTANCE " {m}%s " D_UNIT_CENTIMETER " {e} " ; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
2018-04-20 13:31:09 +01:00
# endif // USE_WEBSERVER
2019-01-28 13:08:33 +00:00
void Sr04Show ( bool json )
2019-12-31 13:23:34 +00:00
{
2018-11-28 09:33:59 +00:00
if ( distance ! = 0 ) { // Check if read failed
2018-12-21 15:17:06 +00:00
char distance_chr [ 33 ] ;
2018-11-28 09:33:59 +00:00
dtostrfd ( distance , 3 , distance_chr ) ;
2018-04-20 13:31:09 +01:00
if ( json ) {
2019-03-23 16:57:31 +00:00
ResponseAppend_P ( PSTR ( " , \" SR04 \" :{ \" " D_JSON_DISTANCE " \" :%s} " ) , distance_chr ) ;
2018-11-11 12:21:46 +00:00
# ifdef USE_DOMOTICZ
2020-10-29 12:37:09 +00:00
if ( 0 = = TasmotaGlobal . tele_period ) {
2018-11-28 09:33:59 +00:00
DomoticzSensor ( DZ_COUNT , distance_chr ) ; // Send distance as Domoticz Counter value
2018-11-11 12:21:46 +00:00
}
# endif // USE_DOMOTICZ
2018-04-20 13:31:09 +01:00
# ifdef USE_WEBSERVER
} else {
2019-03-19 16:31:43 +00:00
WSContentSend_PD ( HTTP_SNS_DISTANCE , distance_chr ) ;
2018-04-20 13:31:09 +01:00
# endif // USE_WEBSERVER
}
}
}
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-01-28 13:08:33 +00:00
bool Xsns22 ( uint8_t function )
2018-04-20 13:31:09 +01:00
{
2019-01-28 13:08:33 +00:00
bool result = false ;
2018-04-20 13:31:09 +01:00
2019-11-15 22:10:07 +00:00
if ( sr04_type ) {
2018-04-20 13:31:09 +01:00
switch ( function ) {
case FUNC_INIT :
2020-04-27 11:54:07 +01:00
result = ( PinUsed ( GPIO_SR04_ECHO ) ) ;
2019-11-15 22:10:07 +00:00
break ;
case FUNC_EVERY_SECOND :
Sr04TReading ( ) ;
result = true ;
2018-04-20 13:31:09 +01:00
break ;
case FUNC_JSON_APPEND :
Sr04Show ( 1 ) ;
break ;
# ifdef USE_WEBSERVER
2019-03-19 16:31:43 +00:00
case FUNC_WEB_SENSOR :
2018-04-20 13:31:09 +01:00
Sr04Show ( 0 ) ;
break ;
# endif // USE_WEBSERVER
}
}
return result ;
}
# endif // USE_SR04