Skip to content

Commit

Permalink
Improve cloud4 a bart's rain sensor driver
Browse files Browse the repository at this point in the history
  • Loading branch information
jstrobl committed Mar 16, 2023
1 parent 48723d8 commit 4bb982f
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 28 deletions.
111 changes: 87 additions & 24 deletions src/sensord/bart-rain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,15 @@ namespace rts2sensord
class BartRain: public SensorWeather
{
private:
int ioctlSetRead (int flagsSet, int * flagsRead);

int rain_port;
int flags0, flags1;
const char *rain_detector;

rts2core::ValueBool *rain;
rts2core::ValueInteger *timeoutRain;
rts2core::ValueInteger *timeoutTechnicalProblems;

protected:
virtual int processOption (int _opt);
Expand Down Expand Up @@ -82,61 +86,117 @@ int BartRain::init ()
if (ret)
return ret;
// init rain detector
int flags;
rain_port = open (rain_detector, O_RDWR | O_NOCTTY);
if (rain_port == -1)
{
logStream (MESSAGE_ERROR) << "Bart::init cannot open " << rain_detector << " " << strerror (errno) << sendLog;
logStream (MESSAGE_ERROR) << "BartRain::init cannot open " << rain_detector << " " << strerror (errno) << sendLog;
return -1;
}
ret = ioctl (rain_port, TIOCMGET, &flags);
ret = ioctl (rain_port, TIOCMGET, &flags0);
if (ret)
{
logStream (MESSAGE_ERROR) << "Bart::init cannot get flags: " << strerror (errno) << sendLog;
logStream (MESSAGE_ERROR) << "BartRain::init cannot get flags: " << strerror (errno) << sendLog;
return -1;
}
flags &= ~TIOCM_DTR;
flags |= TIOCM_RTS;
ret = ioctl (rain_port, TIOCMSET, &flags);
flags0 &= ~TIOCM_DTR;
flags0 |= TIOCM_RTS;
ret = ioctl (rain_port, TIOCMSET, &flags0);
if (ret)
{
logStream (MESSAGE_ERROR) << "Bart::init cannot set flags: " << strerror (errno) << sendLog;
logStream (MESSAGE_ERROR) << "BartRain::init cannot set flags: " << strerror (errno) << sendLog;
return -1;
}

// flags1 are same but reversed logic of DTR/RTS, for testing if the rain sensor is really connected
flags1 = flags0 | TIOCM_DTR;
flags1 &= ~TIOCM_RTS;
return 0;
}

int BartRain::info ()
{
int flags;
int flags_actual;
int ret;
ret = ioctl (rain_port, TIOCMGET, &flags);
#ifdef DEBUG_EXTRA
logStream (MESSAGE_DEBUG) << "Bart::isGoodWeather flags: " << flags << " rain: " << (flags & TIOCM_RI) << sendLog;
#endif
// ioctl failed or it's raining..
if (ret || !(flags & TIOCM_RI))

// first, try the "standard" setup, DTR off, RTS on
ret = ioctlSetRead (flags0, &flags_actual);
if (!ret)
{
setWeatherTimeout (timeoutRain->getValueInteger (), "raining");
if (flags_actual & TIOCM_RI) // it's raining (this also implies the device is really connected!)
{
setWeatherTimeout (timeoutRain->getValueInteger (), "raining");
if (!rain->getValueBool ())
{
rain->setValueBool (true);
maskState (WR_RAIN, WR_RAIN, "rain detected from rain sensor");
setIdleInfoInterval (60);
}
}
else // it isn't raining or the device is not connected (let's find out!)
{
// let's try the "reversed" logic, DTR on, RTS off (if the RING state is reversed as well, device is connected)
ret = ioctlSetRead (flags1, &flags_actual);
if(!ret)
{
if (flags_actual & TIOCM_RI) // in reversed logic this means the sensor is connected and dry!
{
if (rain->getValueBool ())
{
rain->setValueBool (false);
maskState (WR_RAIN, 0, "no rain");
setIdleInfoInterval (1);
}
}
else // this means, the sensor device is not physically connected to the serial port
{
setWeatherTimeout (timeoutTechnicalProblems->getValueInteger (), "rain sensor not connected to serial port");
if (!rain->getValueBool ())
{
rain->setValueBool (true);
maskState (WR_RAIN, WR_RAIN, "rain sensor not connected to serial port");
setIdleInfoInterval (60);
}
}
}
}
}
return SensorWeather::info ();
}


int BartRain::ioctlSetRead (int flagsSet, int * flagsRead)
{
int ret;
ret = ioctl (rain_port, TIOCMSET, &flagsSet);
if (ret)
logStream (MESSAGE_ERROR) << "BartRain::ioctlSetRead cannot set flags: " << strerror (errno) << sendLog;
else
{
usleep (USEC_SEC / 5);
ret = ioctl (rain_port, TIOCMGET, flagsRead);
}

if (ret)
{
setWeatherTimeout (timeoutTechnicalProblems->getValueInteger (), "serial port comm problem");
if (!rain->getValueBool ())
{
rain->setValueBool (true);
maskState (WR_RAIN, WR_RAIN, "rain detected from rain sensor");
maskState (WR_RAIN, WR_RAIN, "serial port comm problem");
setIdleInfoInterval (60);
}
return -1;
}
else
{
if (rain->getValueBool ())
{
rain->setValueBool (false);
maskState (WR_RAIN, 0, "no rain");
setIdleInfoInterval (1);
}
#ifdef DEBUG_EXTRA
logStream (MESSAGE_DEBUG) << "BartRain::ioctlSetRead flagsRead: " << *flagsRead << ", DTR: " << (*flagsRead & TIOCM_DTR) << ", RTS: " << (*flagsRead & TIOCM_RTS) << ", RING: " << (*flagsRead & TIOCM_RI) << sendLog;
#endif
return 0;
}
return SensorWeather::info ();
}


BartRain::BartRain (int argc, char **argv):SensorWeather (argc, argv)
{
rain_detector = "/dev/ttyS0";
Expand All @@ -148,6 +208,9 @@ BartRain::BartRain (int argc, char **argv):SensorWeather (argc, argv)
createValue (timeoutRain, "timeout_rain", "rain timeout in seconds", false, RTS2_VALUE_WRITABLE);
timeoutRain->setValueInteger (3600);

createValue (timeoutTechnicalProblems, "timeout_technical_problems", "technical problems timeout in seconds", false, RTS2_VALUE_WRITABLE);
timeoutTechnicalProblems->setValueInteger (600);

addOption ('f', NULL, 1, "/dev/file for rain detector, default to /dev/ttyS0");
addOption ('r', NULL, 1, "rain timeout in seconds. Default to 3600 seconds (= 60 minutes = 1 hour)");

Expand Down
24 changes: 20 additions & 4 deletions src/sensord/cloud4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ int Cloud4::readSensor (bool update)
int x = sscanf (buf_start + 6, "%d %f %f %*d %*d *%2hhx", &tno, &temp0, &temp1, &checksum);
if (x != 4)
{
logStream (MESSAGE_ERROR) << "cannot parse reply from cloud senso, reply was: '" << buf << "', return " << x << sendLog;
logStream (MESSAGE_ERROR) << "cannot parse reply from cloud sensor, reply was: '" << buf << "', return " << x << sendLog;
return -1;
}
}
Expand Down Expand Up @@ -394,9 +394,25 @@ int Cloud4::info ()
ret = readSensor (true);
if (ret)
{
if (getLastInfoTime () > 60)
setWeatherTimeout (60, "cannot read data from device");
return -1;
// OK, this is because of a partially broken hardware we have now, the response is sometimes wrong...
// Before we will solve this the correct way, let's use this hotfix... It isn't a bad thing anyway...?
// We don't need to solve potential errors in other calls of this function, as they are all related to heating - and the heating is being switched of automatically by the device's internal timer.
int retryAttempt;
for ( retryAttempt = 0; retryAttempt < 2; retryAttempt ++)
{
sleep (3);
mrakConn->flushPortIO ();
logStream (MESSAGE_ERROR) << "There was a problem in readSensor (), retrying..." << sendLog;
ret = readSensor (true);
if (!ret)
break;
}
if (retryAttempt >= 2)
{
if (getLastInfoTime () > 60)
setWeatherTimeout (60, "cannot read data from device");
return -1;
}
}
if (tempDiff->getNumMes () >= numVal->getValueInteger ())
{
Expand Down

0 comments on commit 4bb982f

Please sign in to comment.