Implementation

The monitoring service will be implemented as a basic systemd service, meaning that it will be started by the operating system when the system starts, and the service can be monitored and restarted using all the regular systemd tools.

We will have the following dependencies:

  • POCO
  • WiringPi
  • libmosquittopp (and libmosquitto)

The libmosquitto dependency (https://mosquitto.org/man/libmosquitto-3.html) is used to add MQTT support. The libmosquittopp dependency is a wrapper around the C-based API to provide a class-based interface, which makes integration into C++ projects easier.

The POCO framework (https://pocoproject.org/) is a highly portable set of C++ APIs, which provides everything from network-related functions (including HTTP) to all common low-level functions. In this project, its HTTP server will be used, along with its support for handling configuration files.

Finally, WiringPi (http://wiringpi.com/) is the de facto standard header for accessing and using the GPIO header features on the Raspberry Pi and compatible systems. It implements APIs to communicate with I2C devices and UARTs, and uses PWM and digital pins. In this project, it allows us to communicate with the relay board and the debounce board.

The current version of this code can also be found at the author's GitHub account: https://github.com/MayaPosch/ClubStatusService.

We will start with the main file:

#include "listener.h"

#include <iostream>
#include <string>

using namespace std;

#include <Poco/Util/IniFileConfiguration.h>
#include <Poco/AutoPtr.h>
#include <Poco/Net/HTTPServer.h>

using namespace Poco::Util;
using namespace Poco;
using namespace Poco::Net;

#include "httprequestfactory.h"
#include "club.h"

Here, we include some basic STL functionality, along with the HTTP server and ini file support from POCO. The listener header is for our MQTT class, with the httprequestfactory and club headers being for the HTTP server and the main monitoring logic, respectively:

int main(int argc, char* argv[]) {
Club::log(LOG_INFO, "Starting ClubStatus server...");
int rc;
mosqpp::lib_init();

Club::log(LOG_INFO, "Initialised C++ Mosquitto library.");

string configFile;
if (argc > 1) { configFile = argv[1]; }
else { configFile = "config.ini"; }

AutoPtr<IniFileConfiguration> config;
try {
config = new IniFileConfiguration(configFile);
}
catch (Poco::IOException &e) {
Club::log(LOG_FATAL, "Main: I/O exception when opening configuration file: " + configFile + ". Aborting...");
return 1;
}

string mqtt_host = config->getString("MQTT.host", "localhost");
int mqtt_port = config->getInt("MQTT.port", 1883);
string mqtt_user = config->getString("MQTT.user", "");
string mqtt_pass = config->getString("MQTT.pass", "");
string mqtt_topic = config->getString("MQTT.clubStatusTopic", "/public/clubstatus");
bool relayactive = config->getBool("Relay.active", true);
uint8_t relayaddress = config->getInt("Relay.address", 0x20);

In this section, we initialize the MQTT library (libmosquittopp) and try to open the configuration file, using the default path and name if nothing is specified in the command-line parameters.

POCO's IniFileConfiguration class is used to open and read in the configuration file, throwing an exception if it cannot be found or opened. POCO's AutoPtr is equivalent to C++11's unique_ptr, allowing us to create a new heap-based instance without having to worry about disposing of it later.

Next, we read out the values that we are interested in for the MQTT and relay board functionality, specifying defaults where it makes sense to do so:

Listener listener("ClubStatus", mqtt_host, mqtt_port, mqtt_user, mqtt_pass);

Club::log(LOG_INFO, "Created listener, entering loop...");

UInt16 port = config->getInt("HTTP.port", 80);
HTTPServerParams* params = new HTTPServerParams;
params->setMaxQueued(100);
params->setMaxThreads(10);
HTTPServer httpd(new RequestHandlerFactory, port, params);
try {
httpd.start();
}
catch (Poco::IOException &e) {
Club::log(LOG_FATAL, "I/O Exception on HTTP server: port already in use?");
return 1;
}
catch (...) {
Club::log(LOG_FATAL, "Exception thrown for HTTP server start. Aborting.");
return 1;
}

In this section, we start the MQTT class, providing it with the parameters it needs to connect to the MQTT broker. Next, the HTTP server's configuration details are read out and a new HTTPServer instance is created.

The server instance is configured with the provided port and some limits for the maximum number of threads the HTTP server is allowed to use, as well as for the maximum queued connections it can keep. These parameters are useful to optimize system performance and fit code like this into systems with fewer resources to spare.

New client connections are handled by the custom RequestHandlerFactory class, which we will look at later:


Club::mqtt = &listener;
Club::start(relayactive, relayaddress, mqtt_topic);

while(1) {
rc = listener.loop();
if (rc){
Club::log(LOG_ERROR, "Disconnected. Trying to
reconnect...");
listener.reconnect();
}
}

mosqpp::lib_cleanup();
httpd.stop();
Club::stop();

return 0;
}

Finally, we assign a reference to the Listener instance we created to the static Club class's mqtt member. This will allow the Listener object to be used more easily later on, as we will see.

With calling start() on Club, the monitoring and configuring of the connected hardware will be handled and we are done with that aspect in the main function.

Finally, we enter a loop for the MQTT class, ensuring that it remains connected to the MQTT broker. Upon leaving the loop, we will clean up resources and stop the HTTP server and others. However, since we are in an infinite loop here, this code will not be reached with this implementation.

Since this implementation would be run as a service that runs 24/7, a way to terminate the service cleanly is not an absolute requirement. A relatively easy way to do this would be to add a signal handler that would interrupt the loop once triggered. For simplicity's sake, this has been left out of this project.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.78.237