diff options
Diffstat (limited to 'apps/sm-get-value.cpp')
-rw-r--r-- | apps/sm-get-value.cpp | 185 |
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); +} |