#include #include #include #include #include #include #include #include "ble/Bluetooth.h" #include "SoilMoisture.h" #include "json.hpp" // I'm lazy using namespace std; using namespace std::chrono; using namespace trygvis::bluetooth; using namespace trygvis::soil_moisture; using json = nlohmann::json; enum class Format { PLAIN, JSON }; void validate(boost::any &v, const std::vector &values, Format *, int) { using namespace boost::program_options; const std::string &s = validators::get_single_string(values); if (s == "json") { v = boost::any(Format::JSON); } else if (s == "plain") { v = boost::any(Format::PLAIN); } else { throw validation_error(validation_error::invalid_option_value); } } namespace boost { template<> string lexical_cast(const Format &arg) { if (arg == Format::PLAIN) return "plain"; else if (arg == Format::JSON) return "json"; else throw std::runtime_error("Unknown Format value: " + to_string(static_cast::type>(arg))); } } bool loop; Format format; time_point targetTime; unsigned int sleepTime; vector sensors; void withConnection(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 (int i = 0; i < sensorCount; i++) { sensors.push_back(i); } } auto device = gatt.getDevice().getMac(); targetTime = system_clock::now(); do { 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); if (format == Format::PLAIN) { cout << "device=" << device.str() << ", sensor=" << to_string(sensor) << ", timestamp=" << to_string(timestamp) << ", value=" << (int) value << endl; } else if (format == Format::JSON) { json j; j["device"] = device.str(); j["sensor"] = sensor; j["timestamp"] = timestamp; j["value"] = value; cout << j << endl; } } targetTime = targetTime + seconds(sleepTime); this_thread::sleep_until(targetTime); } while (loop); } int main(int argc, char *argv[]) { namespace po = boost::program_options; po::options_description desc("Options"); desc.add_options() ("help", "produce help message") ("device", po::value()->required(), "MAC of device to poll") ("sensor", po::value>(&sensors)->multitoken(), "Sensor to poll, defaults to all") ("sleep", po::value(&sleepTime)->default_value(0), "How long to sleep in seconds between each poll. If not give, it will exit after first poll") ("format", po::value(&format)->default_value(Format::PLAIN), "Output format"); po::variables_map vm; auto parsed = po::parse_command_line(argc, argv, desc); po::store(parsed, vm); po::notify(vm); auto unrecognized = po::collect_unrecognized(parsed.options, po::include_positional); if (vm.count("help")) { cerr << desc << "\n"; return EXIT_FAILURE; } if (unrecognized.size()) { cerr << "Unrecognized option: " << unrecognized.at(0) << "\n"; return EXIT_FAILURE; } __attribute__((unused)) BluetoothSystem bluetoothSystem; try { if (!vm.count("device")) { cerr << "Missing required option: device" << endl; cerr << desc << "\n"; return EXIT_FAILURE; } auto MAC = vm["device"].as(); cout << "MAC " << MAC << "wat" << endl; Mac mac = Mac::parseMac(MAC); auto &adapter = getAdapter(0); auto &device = adapter.getDevice(mac); loop = sleepTime > 0; do { cout << "Connecting to device: " << device.getMac().str() << endl; auto &gatt = device.connectGatt(); try { withConnection(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; } }