aboutsummaryrefslogtreecommitdiff
path: root/apps/sm-get-value.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'apps/sm-get-value.cpp')
-rw-r--r--apps/sm-get-value.cpp185
1 files changed, 185 insertions, 0 deletions
diff --git a/apps/sm-get-value.cpp b/apps/sm-get-value.cpp
new file mode 100644
index 0000000..19b0066
--- /dev/null
+++ b/apps/sm-get-value.cpp
@@ -0,0 +1,185 @@
+#include <iostream>
+#include <iomanip>
+#include <chrono>
+#include <boost/uuid/uuid_io.hpp>
+#include <thread>
+#include "ble/Bluetooth.h"
+#include "SoilMoisture.h"
+#include "trygvis/sensor.h"
+#include "trygvis/sensor/io.h"
+#include "apps.h"
+
+namespace trygvis {
+namespace apps {
+
+// I'm lazy
+using namespace std;
+using namespace std::chrono;
+using namespace trygvis::apps;
+using namespace trygvis::bluetooth;
+using namespace trygvis::sensor;
+using namespace trygvis::sensor::io;
+
+class sm_get_value : public app {
+public:
+ sm_get_value() : app("sm-get-value") {}
+
+ ~sm_get_value() = default;
+
+ bool loop;
+ sample_format_type format;
+ unsigned int sleepTime;
+ vector<unsigned int> sensorIndexes;
+ vector<pair<unsigned int, string>> sensors;
+
+ KeyDictionary dict;
+ SampleKey *hostname_key = dict.indexOf("hostname");
+ SampleKey *device_key = dict.indexOf("device");
+ SampleKey *timestamp_key = dict.indexOf("timestamp_ms");
+
+ void add_options(po::options_description_easy_init &options) override {
+ auto default_sleep = po::value<>(&sleepTime)->default_value(0);
+ auto default_format = po::value<sample_format_type>(&format)->default_value(sample_format_type::KEY_VALUE);
+
+ options("device", po::value<string>()->required(), "MAC of device to poll");
+ options("sensor", po::value<vector<unsigned int>>(&sensorIndexes)->multitoken(),
+ "Sensor to poll, defaults to all");
+ options("sleep", default_sleep,
+ "How long to sleep in seconds between each poll. If not given, it will exit after first poll");
+ options("format", default_format, "Output format");
+ }
+
+ int main(app_execution &execution) override {
+ __attribute__((unused)) BluetoothSystem bluetoothSystem;
+
+ auto desc = execution.desc;
+ auto vm = execution.vm;
+
+ try {
+ if (!vm.count("device")) {
+ cerr << "Missing required option: device" << endl;
+ cerr << desc << "\n";
+ return EXIT_FAILURE;
+ }
+
+ auto mac_string = vm["device"].as<string>();
+
+ Mac mac = Mac::parseMac(mac_string);
+
+ auto adapter = getAdapter(0);
+
+ auto &device = adapter->getDevice(mac);
+
+ loop = sleepTime > 0;
+
+ do {
+ try {
+ LOG4CPLUS_INFO(execution.logger, "Connecting to device: " + device.getMac().str());
+ auto gatt = device.connectGatt();
+
+ withConnection(format, gatt);
+ } catch (runtime_error &e) {
+ LOG4CPLUS_ERROR(execution.logger, "Exception: " << e.what());
+ }
+
+ if (loop) {
+ LOG4CPLUS_DEBUG(execution.logger,
+ "Sleeping for " + std::to_string(sleepTime) + " seconds after failure.");
+
+ auto targetTime = system_clock::now() + seconds(sleepTime);
+ this_thread::sleep_until(targetTime);
+ }
+ } while (loop);
+
+ return EXIT_SUCCESS;
+ } catch (std::runtime_error ex) {
+ cout << "std::runtime_error: " << ex.what() << endl;
+ return EXIT_FAILURE;
+ } catch (std::exception ex) {
+ cout << "std::exception: " << ex.what() << endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ void read_sensors(SoilMoisture &soilMoisture, string mac) {
+ auto epoch = system_clock::now().time_since_epoch();
+ auto timestamp = duration_cast<seconds>(epoch).count();
+ auto unique_output_stream = open_sample_output_stream(shared_ptr<ostream>(&cout, noop_deleter), dict, format);
+ shared_ptr<SampleOutputStream> output_stream{std::move(unique_output_stream)};
+
+ int i = 0;
+ for (auto s : sensors) {
+ auto sensor = s.first;
+ auto name = s.second;
+
+ uint16_t value = soilMoisture.getValue((uint8_t) sensor);
+
+ auto sensor_key = dict.indexOf("sensor" + std::to_string(i));
+ auto sensor_name_key = dict.indexOf("sensor_name" + std::to_string(i));
+
+ auto sample = SampleRecord(dict)
+ .set(hostname_key, get_hostname())
+ .set(device_key, mac)
+ .set(timestamp_key, std::to_string(timestamp))
+ .set(sensor_key, std::to_string(value))
+ .set(sensor_name_key, name);
+
+ output_stream->write(sample);
+
+ i++;
+ }
+ }
+
+ void withConnection(sample_format_type format, shared_ptr<BluetoothGatt> gatt) {
+ SoilMoisture soilMoisture = SoilMoisture::create(gatt);
+
+ const int sensorCount = soilMoisture.getSensorCount();
+
+ if (sensorCount == 0) {
+ throw runtime_error("Sensor count is 0");
+ }
+
+ // If the user didn't specify any sensors, add all.
+ if (sensors.size() == 0) {
+ for (unsigned int i = 0; i < sensorCount; i++) {
+ sensorIndexes.push_back(i);
+ }
+ }
+
+ for_each(begin(sensorIndexes), end(sensorIndexes), [&](auto i) {
+ if (i >= sensorCount) {
+ // Ignore invalid sensors
+ return;
+ }
+
+ sensors.push_back(make_pair(i, soilMoisture.getName(i)));
+ });
+
+ auto mac = gatt->getDevice().getMac().str();
+
+ if (!loop) {
+ read_sensors(soilMoisture, mac);
+ } else {
+ time_point<system_clock> targetTime;
+ targetTime = system_clock::now();
+
+ do {
+ read_sensors(soilMoisture, mac);
+
+ do {
+ targetTime = targetTime + seconds(sleepTime);
+ } while (targetTime < system_clock::now());
+
+ this_thread::sleep_until(targetTime);
+ } while (loop);
+ }
+ }
+};
+}
+}
+
+int main(int argc, const char *argv[]) {
+ using namespace trygvis::apps;
+
+ return real_main(new sm_get_value(), argc, argv);
+}