Added restart as recovery when connection to devices is lost.

Added a heardbeat-file into which a timestamp is written every second.
This commit is contained in:
hg
2014-06-30 22:07:03 +02:00
parent 40d5753edc
commit c2c25dd30e
5 changed files with 238 additions and 9 deletions
+3
View File
@@ -34,7 +34,10 @@ install: bin/growcontrold
mkdir -p /opt/growcontrol/save mkdir -p /opt/growcontrol/save
cp bin/growcontrold /opt/growcontrol/bin cp bin/growcontrold /opt/growcontrol/bin
cp -r config /opt/growcontrol cp -r config /opt/growcontrol
cp -r scripts /opt/growcontrol
chmod a+x /opt/growcontrol/*
uninstall: uninstall:
rm -rf /opt/growcontrol/bin/growcontrold rm -rf /opt/growcontrol/bin/growcontrold
rm -rf /opt/growcontrol/config rm -rf /opt/growcontrol/config
rm -rf /opt/growcontrol/scripts
BIN
View File
Binary file not shown.
+198 -6
View File
@@ -19,6 +19,8 @@
#include "fanprofile/DummyProfile.h" #include "fanprofile/DummyProfile.h"
#include "fanprofile/Dummy2Profile.h" #include "fanprofile/Dummy2Profile.h"
#include "savefile.h" #include "savefile.h"
#include <cstdio>
#include <cerrno>
namespace growcontrol { namespace growcontrol {
@@ -37,9 +39,16 @@ GrowControl::~GrowControl() {
bool GrowControl::connect(std::string workDir, std::string host , uint16_t port, bool retry) { bool GrowControl::connect(std::string workDir, std::string host , uint16_t port, bool retry) {
tfConnection.addListener(*this); tfConnection.addListener(*this);
this->workDirString = workDir; this->workDirString = workDir;
std::ostringstream ss; {
ss << workDir << "/" << "save"; std::ostringstream ss;
saveDirString = ss.str(); ss << workDir << "/" << "save";
saveDirString = ss.str();
}
{
std::ostringstream ss;
ss << workDir << "/" << "scripts";
scriptDirString = ss.str();
}
try { try {
fan1UpperLimit = saveFileRead<unsigned>(saveDirString, "fan1UpperLimit.save"); fan1UpperLimit = saveFileRead<unsigned>(saveDirString, "fan1UpperLimit.save");
@@ -95,8 +104,14 @@ void GrowControl::newDeviceCallback(TfConnection& conn, TfDevice& device) {
case TfDeviceIdentifier::MASTER: case TfDeviceIdentifier::MASTER:
if ( (rootBrick == nullptr || rootBrick->getDeviceState() != TfDeviceState::CONNECTED) if ( (rootBrick == nullptr || rootBrick->getDeviceState() != TfDeviceState::CONNECTED)
&& device.getDeviceState() == TfDeviceState::AVAILABLE && device.getParent() == nullptr ) { && device.getDeviceState() == TfDeviceState::AVAILABLE && device.getParent() == nullptr ) {
if (rootBrick != nullptr) {
rootBrick->removeListener(*this);
}
rootBrick = (TfMasterBrick*)&device; rootBrick = (TfMasterBrick*)&device;
rootBrick->connect(); rootBrick->connect();
rootBrick->addListener(*this);
masterConnectFlag = true;
masterMissingFlag = false;
logger << log4cpp::Priority::INFO << "Added root device " << device.getDeviceName(true) << "."; logger << log4cpp::Priority::INFO << "Added root device " << device.getDeviceName(true) << ".";
} }
break; break;
@@ -124,14 +139,22 @@ void GrowControl::newDeviceCallback(TfConnection& conn, TfDevice& device) {
if (prioNew < prioT1) { // new device has lower priority than current temp1 if (prioNew < prioT1) { // new device has lower priority than current temp1
if (prioT1 < 10000) { // current temp1 is alive and is moved to temp2 if (prioT1 < 10000) { // current temp1 is alive and is moved to temp2
temp2Bricklet = temp1Bricklet; temp2Bricklet = temp1Bricklet;
temp2ConnectFlag =true;
temp2MissingFlag =false;
logger << log4cpp::Priority::INFO << "Moving temp1 to temp2."; logger << log4cpp::Priority::INFO << "Moving temp1 to temp2.";
} }
temp1Bricklet = (TfTemperatureBricklet*)&device; temp1Bricklet = (TfTemperatureBricklet*)&device;
temp1Bricklet->connect(); temp1Bricklet->connect();
temp1Bricklet->addListener(*this);
temp1ConnectFlag =true;
temp1MissingFlag =false;
logger << log4cpp::Priority::INFO << "Added temp1 device" << device.getDeviceName(true) << "."; logger << log4cpp::Priority::INFO << "Added temp1 device" << device.getDeviceName(true) << ".";
} else if (prioNew < prioT2) { // new device has lower priority than current temp2 } else if (prioNew < prioT2) { // new device has lower priority than current temp2
temp2Bricklet = (TfTemperatureBricklet*)&device; temp2Bricklet = (TfTemperatureBricklet*)&device;
temp2Bricklet->connect(); temp2Bricklet->connect();
temp2Bricklet->addListener(*this);
temp2ConnectFlag =true;
temp2MissingFlag =false;
logger << log4cpp::Priority::INFO << "Added temp2 device " << device.getDeviceName(true) << "."; logger << log4cpp::Priority::INFO << "Added temp2 device " << device.getDeviceName(true) << ".";
} }
} }
@@ -140,23 +163,45 @@ void GrowControl::newDeviceCallback(TfConnection& conn, TfDevice& device) {
case TfDeviceIdentifier::HUMIDITY: case TfDeviceIdentifier::HUMIDITY:
if ( (hum1Bricklet == nullptr || hum1Bricklet->getDeviceState() != TfDeviceState::CONNECTED) if ( (hum1Bricklet == nullptr || hum1Bricklet->getDeviceState() != TfDeviceState::CONNECTED)
&& device.getDeviceState() == TfDeviceState::AVAILABLE ) { && device.getDeviceState() == TfDeviceState::AVAILABLE ) {
if (hum1Bricklet != nullptr) {
hum1Bricklet->removeListener(*this);
}
hum1Bricklet = (TfHumidityBricklet*)&device; hum1Bricklet = (TfHumidityBricklet*)&device;
hum1Bricklet->connect(); hum1Bricklet->connect();
hum1Bricklet->addListener(*this);
hum1ConnectFlag = true;
hum1MissingFlag = false;
logger << log4cpp::Priority::INFO << "Added hum1 device " << device.getDeviceName(true) << "."; logger << log4cpp::Priority::INFO << "Added hum1 device " << device.getDeviceName(true) << ".";
} }
break; break;
case TfDeviceIdentifier::IO16: case TfDeviceIdentifier::IO16:
if ( (io16Bricklet == nullptr || io16Bricklet->getDeviceState() != TfDeviceState::CONNECTED) if ( (io16Bricklet == nullptr || io16Bricklet->getDeviceState() != TfDeviceState::CONNECTED)
&& device.getDeviceState() == TfDeviceState::AVAILABLE ) { && device.getDeviceState() == TfDeviceState::AVAILABLE ) {
if (io16Bricklet != nullptr) {
io16Bricklet->removeListener(*this);
}
io16Bricklet = (TfIO16Bricklet*)&device; io16Bricklet = (TfIO16Bricklet*)&device;
io16Bricklet->connect(); io16Bricklet->connect();
io16Bricklet->setPortConfiguration('a', fan1PinMask, 'o', false); io16Bricklet->setPortConfiguration('a', fan1PinMask, 'o', false);
io16ConnectFlag = true;
io16MissingFlag = false;
io16Bricklet->addListener(*this);
setFan1Level(fan1Level); setFan1Level(fan1Level);
logger << log4cpp::Priority::INFO << "Added io16 device " << device.getDeviceName(true) << "."; logger << log4cpp::Priority::INFO << "Added io16 device " << device.getDeviceName(true) << ".";
} }
break; break;
case TfDeviceIdentifier::LCD20x4: case TfDeviceIdentifier::LCD20x4:
lcd.setTfObject((TfLCD20x4Bricklet&)device); if ( (lcdBricklet == nullptr || lcdBricklet->getDeviceState() != TfDeviceState::CONNECTED)
&& device.getDeviceState() == TfDeviceState::AVAILABLE ) {
if (lcdBricklet != nullptr) {
lcdBricklet->removeListener(*this);
}
lcdBricklet = (TfLCD20x4Bricklet*)&device;
lcdBricklet->addListener(*this);
lcd.setTfObject((TfLCD20x4Bricklet&)device);
lcdConnectFlag = true;
lcdMissingFlag = false;
}
break; break;
default: default:
break; break;
@@ -429,7 +474,7 @@ void GrowControl::shutdownController() {
} }
void GrowControl::mainLoop() { void GrowControl::mainLoop(std::string heartBeatFile) {
if (fan1ActiveProfile != nullptr) { if (fan1ActiveProfile != nullptr) {
fan1ActiveProfile->startCallback(); fan1ActiveProfile->startCallback();
@@ -437,6 +482,39 @@ void GrowControl::mainLoop() {
while (mainLoopFlag) { while (mainLoopFlag) {
// Check missing device countdown
if (missingRestartCountdown < 0) {
#define CHECK1_M(name) (!name ## ConnectFlag || name ## MissingFlag)
#define CHECK1_O(name) (name ## ConnectFlag && name ## MissingFlag)
if ( CHECK1_O(master)
|| CHECK1_O(temp1)
|| CHECK1_O(temp2)
|| CHECK1_O(hum1)
|| CHECK1_O(io16)
|| CHECK1_O(lcd) ) { // all missing devices are connected
missingRestartCountdown = missingRestartMaxCountdown;
logger << log4cpp::Priority::ERROR << "Starting missing device countdown." ;
}
} else if (missingRestartCountdown >= 0) {
#define CHECK2_M(name) (name ## ConnectFlag && !name ## MissingFlag)
#define CHECK2_O(name) (!name ## ConnectFlag || !name ## MissingFlag)
if ( CHECK2_O(master)
&& CHECK2_O(temp1)
&& CHECK2_O(temp2)
&& CHECK2_O(hum1)
&& CHECK2_O(io16)
&& CHECK2_O(lcd) ) { // all missing devices are connected
missingRestartCountdown = -1;
logger << log4cpp::Priority::ERROR << "Missing device countdown stopped, all missing devices are connected again." ;
} else if (missingRestartCountdown == 0) {
logger << log4cpp::Priority::ERROR << "Missing device timeout, restarting ..." ;
restartPC();
missingRestartCountdown = -1;
} else {
missingRestartCountdown--;
}
}
// Fetch sensor values // Fetch sensor values
GCSensorsInfo sensorValues; GCSensorsInfo sensorValues;
sensorValues.timestamp = std::chrono::system_clock::now(); sensorValues.timestamp = std::chrono::system_clock::now();
@@ -446,6 +524,9 @@ void GrowControl::mainLoop() {
} catch (GCException &e) { } catch (GCException &e) {
sensorValues.temp1.valid = false; sensorValues.temp1.valid = false;
sensorValues.temp1.error = e; sensorValues.temp1.error = e;
if (temp1ConnectFlag) {
temp1MissingFlag = true;
}
} }
try { try {
sensorValues.temp2.value = getTemp2(); sensorValues.temp2.value = getTemp2();
@@ -453,6 +534,9 @@ void GrowControl::mainLoop() {
} catch (GCException &e) { } catch (GCException &e) {
sensorValues.temp2.valid = false; sensorValues.temp2.valid = false;
sensorValues.temp2.error = e; sensorValues.temp2.error = e;
if (temp2ConnectFlag) {
temp2MissingFlag = true;
}
} }
try { try {
sensorValues.hum1.value = getHum1(); sensorValues.hum1.value = getHum1();
@@ -460,6 +544,9 @@ void GrowControl::mainLoop() {
} catch (GCException &e) { } catch (GCException &e) {
sensorValues.hum1.valid = false; sensorValues.hum1.valid = false;
sensorValues.hum1.error = e; sensorValues.hum1.error = e;
if (hum1ConnectFlag) {
hum1MissingFlag = true;
}
} }
try { try {
sensorValues.fan1UpperLimit = getFan1UpperLimit(); sensorValues.fan1UpperLimit = getFan1UpperLimit();
@@ -470,6 +557,9 @@ void GrowControl::mainLoop() {
} catch (GCException &e) { } catch (GCException &e) {
sensorValues.fan1Level.valid = false; sensorValues.fan1Level.valid = false;
sensorValues.fan1Level.error = e; sensorValues.fan1Level.error = e;
if (io16ConnectFlag) {
io16MissingFlag = true;
}
} }
lcd.controlMainLoopCallback(sensorValues); lcd.controlMainLoopCallback(sensorValues);
@@ -478,11 +568,32 @@ void GrowControl::mainLoop() {
fan1ActiveProfile->mainLoopCallback(sensorValues); fan1ActiveProfile->mainLoopCallback(sensorValues);
} }
// Write timestamp to heartbeatfile
if (!heartBeatFile.empty()) {
try {
std::ofstream hbfs(heartBeatFile, std::ios_base::out | std::ios_base::trunc);
if (hbfs) {
std::time_t timestamp = std::chrono::system_clock::to_time_t(sensorValues.timestamp);
hbfs << timestamp << " " << std::ctime(&timestamp);
hbfs.flush();
hbfs.close();
} else {
logger << log4cpp::Priority::ERROR << "Could not open heartBeatFile " << heartBeatFile
<< ": " << strerror(errno);
}
} catch (std::exception& e) {
logger << log4cpp::Priority::ERROR << "Exception while opening heartBeatFile " << heartBeatFile
<< ": " << e.what();
}
}
// Sleep
if (mainLoopFlag) { if (mainLoopFlag) {
std::this_thread::sleep_until(sensorValues.timestamp + std::chrono::seconds(1)); std::this_thread::sleep_until(sensorValues.timestamp + std::chrono::seconds(1));
} }
} } // end while(mainLoopFlag)
// Save state before exiting
try { try {
saveFileWrite<unsigned>(saveDirString, "fan1UpperLimit.save", fan1UpperLimit); saveFileWrite<unsigned>(saveDirString, "fan1UpperLimit.save", fan1UpperLimit);
} catch (GCException &e) { } catch (GCException &e) {
@@ -517,5 +628,86 @@ void GrowControl::mainLoop() {
} }
void GrowControl::stateChangeCallback(TfDevice& device, TfDeviceState oldstate, TfDeviceState newstate) {
if (&device == rootBrick) {
if (newstate == TfDeviceState::CONNECTION_LOST || newstate == TfDeviceState::DISCONNECTED) {
if (masterConnectFlag) {
masterMissingFlag = true;
}
} else if (newstate == TfDeviceState::CONNECTED) {
if (masterConnectFlag) {
masterMissingFlag = false;
}
}
} else if (&device == temp1Bricklet) {
if (newstate == TfDeviceState::CONNECTION_LOST || newstate == TfDeviceState::DISCONNECTED) {
if (temp1ConnectFlag) {
temp1MissingFlag = true;
}
} else if (newstate == TfDeviceState::CONNECTED) {
if (temp1ConnectFlag) {
temp1MissingFlag = false;
}
}
} else if (&device == temp2Bricklet) {
if (newstate == TfDeviceState::CONNECTION_LOST || newstate == TfDeviceState::DISCONNECTED) {
if (temp2ConnectFlag) {
temp2MissingFlag = true;
}
} else if (newstate == TfDeviceState::CONNECTED) {
if (temp2ConnectFlag) {
temp2MissingFlag = false;
}
}
} else if (&device == hum1Bricklet) {
if (newstate == TfDeviceState::CONNECTION_LOST || newstate == TfDeviceState::DISCONNECTED) {
if (hum1ConnectFlag) {
hum1MissingFlag = true;
}
} else if (newstate == TfDeviceState::CONNECTED) {
if (hum1ConnectFlag) {
hum1MissingFlag = false;
}
}
} else if (&device == io16Bricklet) {
if (newstate == TfDeviceState::CONNECTION_LOST || newstate == TfDeviceState::DISCONNECTED) {
if (io16ConnectFlag) {
io16MissingFlag = true;
}
} else if (newstate == TfDeviceState::CONNECTED) {
if (io16ConnectFlag) {
io16MissingFlag = false;
}
}
} else if (&device == lcdBricklet) {
if (newstate == TfDeviceState::CONNECTION_LOST || newstate == TfDeviceState::DISCONNECTED) {
if (lcdConnectFlag) {
lcdMissingFlag = true;
}
} else if (newstate == TfDeviceState::CONNECTED) {
if (lcdConnectFlag) {
lcdMissingFlag = false;
}
}
}
}
void GrowControl::shutdownCallback(TfDevice& device) {
if (masterConnectFlag) {
masterMissingFlag = true;
if (missingRestartCountdown < 0) {
missingRestartCountdown = missingRestartMaxCountdown;
logger << log4cpp::Priority::ERROR << "Starting missing device countdown." ;
}
}
}
void GrowControl::restartPC() {
std::ostringstream ss;
ss << scriptDirString << "/restartPC.sh";
std::string cmd = ss.str();
system(cmd.c_str());
}
} /* namespace growcontrol */ } /* namespace growcontrol */
+25 -2
View File
@@ -43,7 +43,7 @@ struct GCSensorsInfo {
}; };
class GrowControl : public TfConnectionListener { class GrowControl : public TfConnectionListener, public TfDeviceStateListener {
private: private:
static log4cpp::Category& logger; static log4cpp::Category& logger;
@@ -56,6 +56,7 @@ private:
TfTemperatureBricklet* temp2Bricklet = nullptr; TfTemperatureBricklet* temp2Bricklet = nullptr;
TfHumidityBricklet* hum1Bricklet = nullptr; TfHumidityBricklet* hum1Bricklet = nullptr;
TfIO16Bricklet* io16Bricklet = nullptr; TfIO16Bricklet* io16Bricklet = nullptr;
TfLCD20x4Bricklet* lcdBricklet = nullptr;
std::mutex controlMutex; std::mutex controlMutex;
unsigned int sleepDuration = 1; unsigned int sleepDuration = 1;
@@ -71,6 +72,22 @@ private:
std::string workDirString; std::string workDirString;
std::string saveDirString; std::string saveDirString;
std::string scriptDirString;
bool masterConnectFlag = false;
bool masterMissingFlag = false;
bool temp1ConnectFlag = false;
bool temp1MissingFlag = false;
bool temp2ConnectFlag = false;
bool temp2MissingFlag = false;
bool hum1ConnectFlag = false;
bool hum1MissingFlag = false;
bool io16ConnectFlag = false;
bool io16MissingFlag = false;
bool lcdConnectFlag = false;
bool lcdMissingFlag = false;
int missingRestartCountdown = -1;
int missingRestartMaxCountdown = 60;
public: public:
@@ -82,7 +99,7 @@ public:
void newDeviceCallback(TfConnection& conn, TfDevice& device); void newDeviceCallback(TfConnection& conn, TfDevice& device);
void shutdownCallback(); void shutdownCallback();
void mainLoop(); void mainLoop(std::string heartBeatFile);
double getTemp1(); double getTemp1();
int16_t getTemp1Raw(); int16_t getTemp1Raw();
@@ -110,6 +127,12 @@ public:
const std::string getSaveDir() { return saveDirString; } const std::string getSaveDir() { return saveDirString; }
const std::string getWorkDir() { return workDirString; } const std::string getWorkDir() { return workDirString; }
const std::string getScriptDir() { return scriptDirString; }
void stateChangeCallback(TfDevice& device, TfDeviceState oldstate, TfDeviceState newstate);
void shutdownCallback(TfDevice& device);
void restartPC();
}; };
} /* namespace growcontrol */ } /* namespace growcontrol */
+12 -1
View File
@@ -32,6 +32,7 @@ std::string socketPath = "/opt/growcontrol/growcontrold.socket";
std::string log4cppConfig = "log4cpp.config"; std::string log4cppConfig = "log4cpp.config";
std::string host = "localhost"; std::string host = "localhost";
std::string workDir = "/opt/growcontrol"; std::string workDir = "/opt/growcontrol";
std::string heartBeatFile = "/opt/growcontrol/growcontrold.heartbeat";
uint16_t port = 4223; uint16_t port = 4223;
bool daemonMode = false; bool daemonMode = false;
int pid_fd = 0; int pid_fd = 0;
@@ -68,6 +69,7 @@ void printUsage(std::ostream& stream, std::string name) {
<< "\t-l ... path to log4cpp config file" << std::endl << "\t-l ... path to log4cpp config file" << std::endl
<< "\t-h ... brickd address" << std::endl << "\t-h ... brickd address" << std::endl
<< "\t-p ... brickd port" << std::endl << "\t-p ... brickd port" << std::endl
<< "\t-hb ... heartbeat file" << std::endl
<< "\t-w ... working directory" << std::endl; << "\t-w ... working directory" << std::endl;
} }
@@ -126,6 +128,15 @@ int main(int argc, char **argv) {
printUsage(std::cerr, argv[0]); printUsage(std::cerr, argv[0]);
exit(1); exit(1);
} }
} else if (strcmp(argv[t], "-hb") == 0) {
if (t+1 < argc && argv[t+1][0] != '-') {
t++;
heartBeatFile = argv[t];
} else {
std::cerr << "Option -hb is missing an argument." << std::endl << std::endl;
printUsage(std::cerr, argv[0]);
exit(1);
}
} else if (strcmp(argv[t], "-p") == 0) { } else if (strcmp(argv[t], "-p") == 0) {
if (t+1 < argc && argv[t+1][0] != '-') { if (t+1 < argc && argv[t+1][0] != '-') {
t++; t++;
@@ -176,7 +187,7 @@ int main(int argc, char **argv) {
} catch (GCException &e) { } catch (GCException &e) {
} }
controller.mainLoop(); controller.mainLoop(heartBeatFile);
logger << log4cpp::Priority::WARN << "Shutting down ipc ..."; logger << log4cpp::Priority::WARN << "Shutting down ipc ...";