#include #include #include #include #include #include "ble/Bluetooth.h" #include "SoilMoisture.h" #include "trygvis/sensor.h" #include "json.hpp" #include "apps.h" // 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; using json = nlohmann::json; bool loop; sample_format_type format; time_point targetTime; unsigned int sleepTime; vector sensors; void withConnection(sample_format_type format, 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++) { sensors.push_back(i); } } auto mac = gatt.getDevice().getMac(); targetTime = system_clock::now(); do { KeyDictionary dict; auto hostname_key = dict.indexOf("hostname"); auto device_key = dict.indexOf("device"); auto sensor_key = dict.indexOf("sensor"); auto timestamp_key = dict.indexOf("timestamp"); auto value_key = dict.indexOf("value"); auto unique_output_stream = open_sample_output_stream(shared_ptr(&cout, noop_deleter), dict, format); shared_ptr output_stream{std::move(unique_output_stream)}; for (auto sensor : sensors) { if (sensor >= sensorCount) { // Ignore invalid sensors continue; } auto epoch = system_clock::now().time_since_epoch(); auto timestamp = duration_cast(epoch).count(); uint16_t value = soilMoisture.getValue((uint8_t) sensor); SampleRecord sample(dict); sample.set(hostname_key, get_hostname()); sample.set(device_key, mac.str()); sample.set(sensor_key, std::to_string(sensor)); sample.set(timestamp_key, std::to_string(timestamp)); sample.set(value_key, std::to_string(value)); output_stream->write(sample); // if (format == sample_format_type::KEY_VALUE) { // cout << "device=" << device.str() // << ", sensor=" << to_string(sensor) // << ", timestamp=" << to_string(timestamp) // << ", value=" << (int) value << endl; // } else if (format == sample_format_type::JSON) { // json j; // j["device"] = device.str(); // j["sensor"] = sensor; // j["timestamp"] = timestamp; // j["value"] = value; // cout << j << endl; // } else if (format == sample_format_type::SQL) { // cout << "INSERT INTO soil_moisture_sample(device, sensor, timestamp, value) VALUES(" // << "'" << device.str() << "', " // << sensor << ", " // << timestamp << ", " // << value << ";" << endl; // } } targetTime = targetTime + seconds(sleepTime); this_thread::sleep_until(targetTime); } while (loop); } namespace trygvis { namespace apps { class sm_get_value : public app { public: sm_get_value() : app("sm-get-value") { } ~sm_get_value() = default; void add_options(po::options_description_easy_init &options) override { auto default_sleep = po::value<>(&sleepTime)->default_value(0); options ("device", po::value()->required(), "MAC of device to poll") ("sensor", po::value>(&sensors)->multitoken(), "Sensor to poll, defaults to all") ("sleep", default_sleep, "How long to sleep in seconds between each poll. If not given, it will exit after first poll") ("format", po::value(&format)->default_value(sample_format_type::KEY_VALUE), "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 = vm["device"].as(); Mac mac = Mac::parseMac(MAC); auto &adapter = getAdapter(0); auto &device = adapter.getDevice(mac); loop = sleepTime > 0; do { LOG4CPLUS_INFO(execution.logger, "Connecting to device: " + device.getMac().str()); auto &gatt = device.connectGatt(); try { withConnection(format, gatt); } catch (runtime_error &e) { cout << "exception: " << e.what() << endl; } gatt.disconnect(); } 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; } } }; } }