tons of updates

FIXED 100% CPU usage bug for MQTT and heimdall
master
Tibor 10 months ago
parent bf548fd790
commit bb97cf2cdc
  1. 18
      config.cpp
  2. 40
      heimdall.cpp
  3. 4
      heimdall.h
  4. 78
      heimdall.vcxproj
  5. 14
      heimdall.vcxproj.user
  6. 18
      main.cpp
  7. 28
      mqttClient.cpp
  8. 2
      mqttClient.h
  9. 10
      script/openDoor.py
  10. 17
      threadLauncher.cpp
  11. 2
      threadLauncher.h

@ -17,7 +17,7 @@ config::config(const std::vector<std::string>& options)
// parse our file
_config->parse(filename.c_str());
LOG_INF("Trying to parse " + std::to_string(options.size()) + " options...");
LOG_INF("[CONF] Trying to parse " + std::to_string(options.size()) + " options...");
// retain variable values
for (auto const& option : options) {
@ -32,22 +32,22 @@ config::config(const std::vector<std::string>& options)
}
}
LOG_INF("Parsed " + std::to_string(_options.size()) + " config options.");
LOG_INF("Configuration parsing complete.");
LOG_INF("[CONF] Parsed " + std::to_string(_options.size()) + " config options.");
LOG_INF("[CONF] Configuration parsing complete.");
if (_options.size() == options.size()) {
LOG_INF("All options were successfully parsed.");
LOG_INF("[CONF] All options were successfully parsed.");
}
else {
// We assume a total maximum of 256 entries in our config file.
// If you want to use more, use int or bigger instead.
uint8_t amount { static_cast<uint8_t>(options.size() - _options.size()) };
LOG_INF("Didn't parse " + std::to_string(amount) + " options.");
LOG_INF("[CONF] Didn't parse " + std::to_string(amount) + " options.");
}
}
catch (config4cpp::ConfigurationException& ce) {
LOG_FTL("Unable to read from config file or option: " + std::string(ce.c_str()));
LOG_FTL("Exiting.");
LOG_FTL("[CONF] Unable to read from config file or option: " + std::string(ce.c_str()));
LOG_FTL("[CONF] Exiting.");
// Just to make it easy for the dev to see what's wrong when debugging.
assert(false);
@ -72,8 +72,8 @@ auto config::optionsVec(const std::string& o) -> std::vector<std::string>
_config->lookupList("", o.c_str(), vec);
}
catch (config4cpp::ConfigurationException& ce) {
LOG_FTL("Unable to read from config option vector: " + std::string(ce.c_str()));
LOG_FTL("Exiting.");
LOG_FTL("[CONF] Unable to read from config option vector: " + std::string(ce.c_str()));
LOG_FTL("[CONF] Exiting.");
assert(false);

@ -20,15 +20,11 @@ heimdall::heimdall(uint8_t gpio_button, uint8_t gpio_opener, std::shared_ptr<tai
LOG_INF("Hello from heimdall.");
if (!_btn) {
LOG_FTL("Unable to create button object or invalid GPIO #. Exiting.");
LOG_FTL("[HD] Unable to create button object or invalid GPIO #. Exiting.");
exit(-1);
}
// MQTT listener should run asynchronously
threadLauncher& launcher { threadLauncher::inst() };
launcher.go(std::make_unique<std::thread>(&heimdall::registerMqttListener, this));
registerMqttListener();
// button push function hook
@ -43,11 +39,14 @@ heimdall::heimdall(uint8_t gpio_button, uint8_t gpio_opener, std::shared_ptr<tai
}
// we want to wait at least 100ms for the next trigger
LOG_DBG("sleeping 100ms.");
LOG_DBG("[HD] Button pushed; sleeping 100ms.");
std::this_thread::sleep_for(100ms);
};
// TODO take care of this
#if 0
_startAudioStreamingServer();
#endif
#endif // DEBUG_TAI
@ -59,9 +58,14 @@ heimdall::~heimdall()
// stop event handling
_btn->stop();
LOG_DBG("Releasing button.");
LOG_DBG("[HD] Releasing button pointer.");
_btn.release();
/*
LOG_DBG("[HD] Releasing all running threads.");
threadLauncher::inst().closeAllThreads();
*/
LOG_INF("Bye-bye from heimdall.");
}
@ -80,7 +84,10 @@ void heimdall::startMqttAndPlaySound()
};
// door opening. @TODO remove
_opener->on(std::chrono::milliseconds(1000));
if (_conf->options("openOnButtonPush") == "true") {
_opener->off(std::chrono::milliseconds(100));
}
// sound playback shell command
std::string cmdPlaySound { "aplay " + _conf->options("soundFilePath") };
@ -105,18 +112,18 @@ void heimdall::startMqttAndPlaySound()
#ifndef DEBUG_TAI
LOG_INF("Button was pushed!");
LOG_INF("[HD] Button was pushed!");
// execute mqtt publishing async
launcher.go(cmdMosquittoPub);
LOG_DBG("Creating thread for sound playback: " + cmdPlaySound);
LOG_DBG("[HD] Creating thread for sound playback: " + cmdPlaySound);
// execute sound playback async
launcher.go(cmdPlaySound);
#endif
// @TODO if (telegramNotificationEnabled in config)
LOG_DBG("Creating thread for Telegram notification: " + cmdNotifyOnTelegram);
LOG_DBG("[HD] Creating thread for Telegram notification: " + cmdNotifyOnTelegram);
launcher.go(cmdNotifyOnTelegram);
}
@ -156,12 +163,11 @@ void heimdall::takePictureAndSend(const std::vector<std::string>& recipients)
void heimdall::registerMqttListener()
{
LOG_INF("Registering MQTT listener for topic " + _conf->options("mqttTopic"));
LOG_INF("[HD] Registering MQTT listener for topic " + _conf->options("mqttTopic"));
// create our MQTT client and start subscription
mqttClient client(_conf);
client.subscribeToKnownTopic();
_mqttClient = std::make_shared<mqttClient>(_conf);
_mqttClient->subscribeToKnownTopic();
}
void heimdall::_startAudioStreamingServer()
@ -179,7 +185,7 @@ void heimdall::_startAudioStreamingServer()
// start streaming server
if (!_isAudioStreamingServerRunning) {
LOG_DBG("Creating thread for " + cmdStartAudioStream);
LOG_DBG("[HD] Creating thread for " + cmdStartAudioStream);
threadLauncher::inst().go(cmdStartAudioStream);
_isAudioStreamingServerRunning = true;

@ -28,14 +28,14 @@ public:
void startMqttAndPlaySound();
void takePictureAndSend(const std::vector<std::string>&);
void registerMqttListener();
std::shared_ptr<mqttClient> getMqttClient() { return _mqttClient; };
private:
// members
std::unique_ptr<GPIO::PushButton> _btn;
std::unique_ptr<GPIO::DigitalOut> _opener;
std::shared_ptr<tai::config> _conf;
mosquitto* mqttInst;
std::shared_ptr<mqttClient> _mqttClient;
// methods
bool _isAudioStreamingServerRunning { false };

@ -61,12 +61,19 @@
<LibraryPath>
</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<IncludePath>$(ProjectDir)3rdparty\cppgpio\include;$(ProjectDir)3rdparty\config4cpp\include</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<IncludePath>$(ProjectDir)3rdparty\cppgpio\include;$(ProjectDir)3rdparty\config4cpp\include</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<Link>
<LibraryDependencies>cppgpio;pthread;config4cpp;mosquittopp</LibraryDependencies>
</Link>
<RemotePostBuildEvent>
<Command>\cp heimdall.cfg $(RemoteOutDir)</Command>
<Command>
</Command>
<Message>
</Message>
</RemotePostBuildEvent>
@ -74,17 +81,25 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<Link>
<LibraryDependencies>cppgpio;pthread;config4cpp;mosquittopp</LibraryDependencies>
<AdditionalLibraryDirectories>%(Link.AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>/home/tai/CppGPIO;/home/tai/config4cpp/lib;%(Link.AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<RemotePostBuildEvent>
<Command>\cp heimdall.cfg $(RemoteOutDir)</Command>
<Command>
</Command>
<Message>
</Message>
<AdditionalSourcesToCopyMapping>%(AdditionalSourcesToCopyMapping)</AdditionalSourcesToCopyMapping>
</RemotePostBuildEvent>
<ClCompile>
<AdditionalIncludeDirectories>%(ClCompile.AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>/home/tai/config4cpp/include;%(ClCompile.AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CppLanguageStandard>c++14</CppLanguageStandard>
</ClCompile>
<PostBuildEvent>
<AdditionalSourcesToCopyMapping>heimdall.cfg:=projects/$(RemoteOutRelDir)/heimdall.cfg;sounds/ding.wav:=projects/$(RemoteOutRelDir)/sounds/ding.wav;sounds/notAtHome.wav:=projects/$(RemoteOutRelDir)/sounds/notAtHome.wav;sounds/onOurWay.wav:=projects/$(RemoteOutRelDir)/sounds/onOurWay.wav;script/openDoor.py:=projects/$(RemoteOutRelDir)/script/openDoor.py</AdditionalSourcesToCopyMapping>
</PostBuildEvent>
<RemotePreBuildEvent>
<Command>rm $(RemoteOutDir)heimdall.cfg; if [ ! -d $(RemoteOutDir)sounds ]; then mkdir $(RemoteOutDir)sounds; fi; if [ ! -d $(RemoteOutDir)script ]; then mkdir $(RemoteOutDir)script; fi; </Command>
</RemotePreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="config.cpp" />
@ -106,11 +121,62 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<CppLanguageStandard>c++14</CppLanguageStandard>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>/home/tai/config4cpp/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>/home/tai/CppGPIO;/home/tai/config4cpp/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<RemotePostBuildEvent>
<AdditionalSourcesToCopyMapping>%(AdditionalSourcesToCopyMapping)</AdditionalSourcesToCopyMapping>
</RemotePostBuildEvent>
<PostBuildEvent>
<AdditionalSourcesToCopyMapping>heimdall.cfg:=projects/$(RemoteOutRelDir)/heimdall.cfg;sounds/ding.wav:=projects/$(RemoteOutRelDir)/sounds/ding.wav;sounds/notAtHome.wav:=projects/$(RemoteOutRelDir)/sounds/notAtHome.wav;sounds/onOurWay.wav:=projects/$(RemoteOutRelDir)/sounds/onOurWay.wav;script/openDoor.py:=projects/$(RemoteOutRelDir)/script/openDoor.py</AdditionalSourcesToCopyMapping>
</PostBuildEvent>
<RemotePreBuildEvent>
<Command>rm $(RemoteOutDir)heimdall.cfg; if [ ! -d $(RemoteOutDir)sounds ]; then mkdir $(RemoteOutDir)sounds; fi; if [ ! -d $(RemoteOutDir)script ]; then mkdir $(RemoteOutDir)script; fi; </Command>
</RemotePreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<Link>
<AdditionalLibraryDirectories>/home/tai/CppGPIO;/home/tai/config4cpp/lib;%(Link.AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<LibraryDependencies>cppgpio;pthread;config4cpp;mosquittopp</LibraryDependencies>
</Link>
<ClCompile>
<AdditionalIncludeDirectories>/home/tai/config4cpp/include;%(ClCompile.AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CppLanguageStandard>c++14</CppLanguageStandard>
</ClCompile>
<RemotePostBuildEvent>
<Command>
</Command>
<AdditionalSourcesToCopyMapping>%(AdditionalSourcesToCopyMapping)</AdditionalSourcesToCopyMapping>
</RemotePostBuildEvent>
<PostBuildEvent>
<AdditionalSourcesToCopyMapping>heimdall.cfg:=projects/$(RemoteOutRelDir)/heimdall.cfg;sounds/ding.wav:=projects/$(RemoteOutRelDir)/sounds/ding.wav;sounds/notAtHome.wav:=projects/$(RemoteOutRelDir)/sounds/notAtHome.wav;sounds/onOurWay.wav:=projects/$(RemoteOutRelDir)/sounds/onOurWay.wav;script/openDoor.py:=projects/$(RemoteOutRelDir)/script/openDoor.py</AdditionalSourcesToCopyMapping>
</PostBuildEvent>
<RemotePreBuildEvent>
<Command>rm $(RemoteOutDir)heimdall.cfg; if [ ! -d $(RemoteOutDir)sounds ]; then mkdir $(RemoteOutDir)sounds; fi; if [ ! -d $(RemoteOutDir)script ]; then mkdir $(RemoteOutDir)script; fi; </Command>
</RemotePreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>/home/tai/CppGPIO;/home/tai/config4cpp/lib;%(Link.AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<LibraryDependencies>cppgpio;pthread;config4cpp;mosquittopp</LibraryDependencies>
</Link>
<ClCompile>
<AdditionalIncludeDirectories>/home/tai/config4cpp/include;%(ClCompile.AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<CppLanguageStandard>c++14</CppLanguageStandard>
</ClCompile>
<RemotePostBuildEvent>
<Command>
</Command>
<AdditionalSourcesToCopyMapping>%(AdditionalSourcesToCopyMapping)</AdditionalSourcesToCopyMapping>
</RemotePostBuildEvent>
<PostBuildEvent>
<AdditionalSourcesToCopyMapping>heimdall.cfg:=projects/$(RemoteOutRelDir)/heimdall.cfg;sounds/ding.wav:=projects/$(RemoteOutRelDir)/sounds/ding.wav;sounds/notAtHome.wav:=projects/$(RemoteOutRelDir)/sounds/notAtHome.wav;sounds/onOurWay.wav:=projects/$(RemoteOutRelDir)/sounds/onOurWay.wav;script/openDoor.py:=projects/$(RemoteOutRelDir)/script/openDoor.py</AdditionalSourcesToCopyMapping>
</PostBuildEvent>
<RemotePreBuildEvent>
<Command>rm $(RemoteOutDir)heimdall.cfg; if [ ! -d $(RemoteOutDir)sounds ]; then mkdir $(RemoteOutDir)sounds; fi; if [ ! -d $(RemoteOutDir)script ]; then mkdir $(RemoteOutDir)script; fi; </Command>
</RemotePreBuildEvent>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />

@ -4,10 +4,24 @@
<RemoteDebuggerCommandArguments>
</RemoteDebuggerCommandArguments>
<DebuggerFlavor>LinuxDebugger</DebuggerFlavor>
<RemoteGDBPath>/usr/bin/gdb</RemoteGDBPath>
<ASANRuntimeFlags>detect_leaks=1</ASANRuntimeFlags>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<RemoteDebuggerCommandArguments>
</RemoteDebuggerCommandArguments>
<DebuggerFlavor>LinuxDebugger</DebuggerFlavor>
<RemoteGDBPath>/usr/bin/gdb</RemoteGDBPath>
<ASANRuntimeFlags>detect_leaks=1</ASANRuntimeFlags>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<RemoteGDBPath>/usr/bin/gdb</RemoteGDBPath>
<ASANRuntimeFlags>detect_leaks=1</ASANRuntimeFlags>
<DebuggerFlavor>LinuxDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<RemoteGDBPath>/usr/bin/gdb</RemoteGDBPath>
<ASANRuntimeFlags>detect_leaks=1</ASANRuntimeFlags>
<DebuggerFlavor>LinuxDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

@ -1,6 +1,8 @@
#include "heimdall.h"
#include "config.h"
#include "mqttClient.h"
// see https://de.pinout.xyz/pinout/pin10_gpio15 for details
#define GPIO_DOORBELL 15
#define GPIO_OPENER 18
@ -26,7 +28,8 @@ int main(int argc, char* argv[]) {
"rtspServerHome",
"tg_notifMessage",
"tg_botId",
"tg_chatIds"
"tg_chatIds",
"openOnButtonPush"
};
std::shared_ptr<tai::config> conf { std::make_shared<tai::config>(configOptions) };
@ -36,21 +39,24 @@ int main(int argc, char* argv[]) {
if (!freopen(logfile.c_str(), "w", stderr)) {
// we can still write to stderr.
LOG_ERR("Unable to create log file! Continuing without log.");
LOG_ERR("[main] Unable to create log file! Continuing without log.");
}
LOG_INF("Starting heimdall program execution.");
LOG_DBG("Log file: " + logfile);
LOG_INF("[main] Starting heimdall program execution.");
LOG_DBG("[main] Log file: " + logfile);
// our doorbell class instance
tai::heimdall bell(GPIO_DOORBELL, GPIO_OPENER, conf);
std::shared_ptr<tai::mqttClient> mqttClient(bell.getMqttClient());
LOG_DBG("Entering main loop.");
LOG_DBG("[main] Entering main loop.");
// stay alive!
while (true) {
// yippieeeeeeeeeee
mqttClient->loop();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
LOG_INF("heimdall program execution stopped.");
LOG_INF("[main] heimdall program execution stopped.");
}

@ -18,13 +18,15 @@ mqttClient::mqttClient(std::shared_ptr<tai::config> config)
mosqpp::lib_init();
connect(_host.c_str(), _port, _keepalive);
loop_start();
}
mqttClient::~mqttClient()
{
disconnect();
loop_stop();
_mqttLoop.join();
mosqpp::lib_cleanup();
}
@ -109,26 +111,34 @@ void mqttClient::on_message(const struct mosquitto_message* message)
LOG_INF(msg);
if (msg.find(_token) == std::string::npos) {
LOG_ERR("Unable to find token in message: " + msg);
LOG_ERR("Nothing happened.");
LOG_ERR("[MQTT] Unable to find token in message: " + msg);
LOG_ERR("[MQTT] Nothing happened.");
return;
}
// @TODO rework this
if (msg.find("onOpenDoor") != std::string::npos) {
std::string openDoorCmd { "python ./script/openDoor.py" };
LOG_INF("[MQTT] Triggering \"Open door\" procedure: " + openDoorCmd);
threadLauncher::inst().go(openDoorCmd);
}
if (msg.find("onPlayNotAtHome") != std::string::npos) {
std::string notAtHomeCmd { "aplay /home/tai/sounds/notAtHome.wav" };
std::string notAtHomeCmd { "aplay ./sounds/notAtHome.wav" };
LOG_INF("Triggering \"Not at home\" procedure: " + notAtHomeCmd);
LOG_INF("[MQTT] Triggering \"Not at home\" procedure: " + notAtHomeCmd);
threadLauncher::inst().go(notAtHomeCmd);
}
if (msg.find("onPlayOnOurWay") != std::string::npos) {
std::string onOurWayCmd { "aplay /home/tai/sounds/onOurWay.wav" };
std::string onOurWayCmd { "aplay ./sounds/onOurWay.wav" };
LOG_INF("Triggering \"On our way\" procedure: " + onOurWayCmd);
LOG_INF("[MQTT] Triggering \"On our way\" procedure: " + onOurWayCmd);
threadLauncher::inst().go(onOurWayCmd);
}
@ -156,7 +166,7 @@ void mqttClient::on_message(const struct mosquitto_message* message)
cmd.append(" && ");
cmd.append("curl -s --location --request GET 'https://api.telegram.org/" + _conf->options("tg_botId") + "/sendPhoto?chat_id=" + chat_id + "' --form 'photo=@\"./" + pictureName + "\"' > /dev/null");
LOG_INF("Triggering picture record: " + cmd);
LOG_INF("[MQTT] Triggering picture record: " + cmd);
threadLauncher::inst().go(cmd);
}

@ -32,6 +32,8 @@ private:
int _port;
int _keepalive;
std::thread _mqttLoop;
void on_connect(int rc) override;
void on_disconnect(int rc) override;
void on_publish(int mid) override;

@ -0,0 +1,10 @@
import RPi.GPIO as GPIO
import time
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
GPIO.output(12, False)
time.sleep(0.1)
GPIO.output(12, True)

@ -21,7 +21,7 @@ void threadLauncher::go(std::unique_ptr<std::thread> thread)
*/
auto threadLauncher::execShellCmd(std::string const& cmd) -> std::string
{
LOG_DBG("Executing shell command: " + cmd);
LOG_DBG("[TL] Executing shell command: " + cmd);
std::array<char, 128> buffer;
std::string result;
@ -29,7 +29,7 @@ auto threadLauncher::execShellCmd(std::string const& cmd) -> std::string
std::unique_ptr<FILE, decltype(&pclose)> pipe { popen(cmd.c_str(), "r"), pclose };
if (!pipe) {
LOG_ERR("Unable to execute the above command.");
LOG_ERR("[TL] Unable to execute the above command.");
throw std::runtime_error("popen() failed!");
}
@ -37,23 +37,28 @@ auto threadLauncher::execShellCmd(std::string const& cmd) -> std::string
result += buffer.data();
}
LOG_DBG("Thread [" + cmd + "] stopped.");
LOG_DBG("[TL] Thread [" + cmd + "] stopped.");
return result;
}
threadLauncher::~threadLauncher()
void threadLauncher::closeAllThreads()
{
for (auto& at : _asyncThreads) {
if (at) {
std::string const& threadIdStr = Log::threadIdToStr(at->get_id());
if (at->joinable()) {
LOG_DBG("Joining thread " + threadIdStr);
LOG_DBG("[TL] Joining thread " + threadIdStr);
at->join();
}
LOG_DBG("Releasing pointer for thread " + threadIdStr);
LOG_DBG("[TL] Releasing pointer for thread " + threadIdStr);
at.release();
}
}
}
threadLauncher::~threadLauncher()
{
closeAllThreads();
}
}

@ -15,6 +15,8 @@ public:
auto execShellCmd(std::string const& cmd) -> std::string;
void closeAllThreads();
static threadLauncher& inst()
{
static threadLauncher inst;

Loading…
Cancel
Save