diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/SoilMoistureIo.cpp | 81 | ||||
-rw-r--r-- | apps/SoilMoistureIo.h | 15 | ||||
-rw-r--r-- | apps/sample-convert.cpp | 27 | ||||
-rw-r--r-- | apps/sm-get-value.cpp | 49 | ||||
-rw-r--r-- | apps/sm-serial-read.cpp | 55 |
5 files changed, 106 insertions, 121 deletions
diff --git a/apps/SoilMoistureIo.cpp b/apps/SoilMoistureIo.cpp index 40f2f7a..c7f3504 100644 --- a/apps/SoilMoistureIo.cpp +++ b/apps/SoilMoistureIo.cpp @@ -121,6 +121,54 @@ void JsonSampleOutputStream::write(SampleRecord sample) { *stream.get() << doc << endl; } +KeyValueSampleOutputStream::KeyValueSampleOutputStream(shared_ptr<ostream> stream, KeyDictionary &dict) : + dict(dict), stream(move(stream)) { +} + +void KeyValueSampleOutputStream::write(SampleRecord sample) { + // Skip empty records + if (sample.empty()) { + return; + } + + auto &s = *stream.get(); + + bool first = true; + if (!dict.empty()) { + for (auto &key: dict) { + auto sampleKey = sample.dict.indexOf(key->name); + + auto value = sample.at(sampleKey); + + if (value) { + if (first) { + first = false; + } else { + s << ", "; + } + s << key->name << "=" << value; + } + } + } else { + for (auto &sampleKey: sample.dict) { + auto o = sample.at(sampleKey); + + if (o) { + if (first) { + first = false; + } else { + s << ", "; + } + // Make sure that the key is registered in the dictionary + dict.indexOf(sampleKey->name); + s << sampleKey->name << "=" << o.get(); + } + } + } + + *stream.get() << endl; +} + SqlSampleOutputStream::SqlSampleOutputStream(shared_ptr<ostream> stream, KeyDictionary &dict, string table_name) : dict(dict), stream(move(stream)), table_name(table_name) { } @@ -257,6 +305,29 @@ string to_string(const sample_format_type &arg) { throw std::runtime_error("Unknown format value: " + to_string(arg)); } +std::ostream& operator<<(std::ostream& os, sample_format_type const& type){ + return os << to_string(type); +} + +std::istream& operator>>(std::istream& is, sample_format_type& type){ + string s; + is >> s; + + if (s == "auto") { + type = sample_format_type::AUTO; + } else if (s == "csv") { + type = sample_format_type::CSV; + } else if (s == "key-value") { + type = sample_format_type::KEY_VALUE; + } else if (s == "json") { + type = sample_format_type::JSON; + } else if (s == "sql") { + type = sample_format_type::SQL; + } + + return is; +} + unique_ptr<SampleStreamParser> open_sample_input_stream( shared_ptr<SampleOutputStream> output, KeyDictionary &dict, @@ -266,7 +337,7 @@ unique_ptr<SampleStreamParser> open_sample_input_stream( } else if (type == sample_format_type::AUTO) { return make_unique<AutoSampleParser>(output, dict); } else { - throw sample_exception("Unsupported format type: " + to_string(type)); + throw sample_exception("No parser for format type: " + to_string(type)); } } @@ -276,13 +347,15 @@ unique_ptr<SampleOutputStream> open_sample_output_stream( sample_format_type type) { if (type == sample_format_type::CSV) { - return make_unique<CsvSampleOutputStream>(move(output), dict); + return make_unique<CsvSampleOutputStream>(output, dict); + } else if (type == sample_format_type::KEY_VALUE) { + return make_unique<KeyValueSampleOutputStream>(output, dict); } else if (type == sample_format_type::JSON) { - return make_unique<JsonSampleOutputStream>(move(output), dict); + return make_unique<JsonSampleOutputStream>(output, dict); // } else if (type == sample_format_type::SQL) { // return make_unique<SqlSampleOutputStream>(dict, move(output), table_name); } else { - throw sample_exception("Unsupported format type: " + to_string(type)); + throw sample_exception("No writer for format type: " + to_string(type)); } } diff --git a/apps/SoilMoistureIo.h b/apps/SoilMoistureIo.h index 5324114..3e78f46 100644 --- a/apps/SoilMoistureIo.h +++ b/apps/SoilMoistureIo.h @@ -31,6 +31,10 @@ enum class sample_format_type { string to_string(const sample_format_type &arg); +std::ostream& operator<<(std::ostream& os, sample_format_type const& type); + +std::istream& operator>>(std::istream& is, sample_format_type& type); + class SampleStreamParser; class SampleOutputStream; @@ -270,6 +274,17 @@ private: shared_ptr<ostream> stream; }; +class KeyValueSampleOutputStream : public SampleOutputStream { +public: + KeyValueSampleOutputStream(shared_ptr<ostream> stream, KeyDictionary &dict); + + void write(SampleRecord sample) override; + +private: + KeyDictionary &dict; + shared_ptr<ostream> stream; +}; + class SqlSampleOutputStream : public SampleOutputStream { public: SqlSampleOutputStream(shared_ptr<ostream> stream, KeyDictionary &dict, string table_name); diff --git a/apps/sample-convert.cpp b/apps/sample-convert.cpp index 79d6f1c..c6f5d01 100644 --- a/apps/sample-convert.cpp +++ b/apps/sample-convert.cpp @@ -18,9 +18,9 @@ public: options ("help", "produce this help message") ("input", po::value<string>(&input_file)->default_value("-")) - ("input-format", po::value<string>(&input_format)->default_value("csv")) +// ("input-format", po::value<string>(&input_format)->default_value("csv")) ("output", po::value<string>(&output_file)->default_value("-")) - ("output-format", po::value<string>(&output_format)->default_value("plain")); + ("output-format", po::value<sample_format_type>(&output_format)->default_value(sample_format_type::KEY_VALUE)); } void add_extra_options(po::options_description &all_options) override { @@ -36,7 +36,6 @@ public: auto vm = execution.vm; KeyDictionary dict; - shared_ptr<SampleOutputStream> output; istream *inputStream; if (input_file == "-") { @@ -60,23 +59,7 @@ public: } } - if (output_format == "plain") { - output = make_shared<CsvSampleOutputStream>(outputStream, dict); - } else if (output_format == "json") { - output = make_shared<JsonSampleOutputStream>(outputStream, dict); - } else if (output_format == "sql") { - if (table_name.size() == 0) { - cerr << "Missing option: table-name" << endl; - return EXIT_FAILURE; - } - - output = make_shared<SqlSampleOutputStream>(outputStream, dict, table_name); - } else if (output_format == "csv") { - output = make_shared<CsvSampleOutputStream>(outputStream, dict); - } else { - cerr << "Unsupported output format: " << output_format << endl; - return EXIT_FAILURE; - } + shared_ptr<SampleOutputStream> output = open_sample_output_stream(outputStream, dict, output_format); auto input = make_shared<KeyValueSampleParser>(output, dict); @@ -90,8 +73,8 @@ public: } private: - string input_file, input_format; - string output_file, output_format; + string input_file, output_file; + sample_format_type output_format; string table_name; }; diff --git a/apps/sm-get-value.cpp b/apps/sm-get-value.cpp index a61132f..9f9308a 100644 --- a/apps/sm-get-value.cpp +++ b/apps/sm-get-value.cpp @@ -5,6 +5,7 @@ #include <thread> #include "ble/Bluetooth.h" #include "SoilMoisture.h" +#include "SoilMoistureIo.h" #include "json.hpp" #include "apps.h" @@ -17,46 +18,8 @@ using namespace trygvis::soil_moisture; namespace po = boost::program_options; using json = nlohmann::json; -enum class Format { - PLAIN, - JSON, - SQL -}; - -void validate(boost::any &v, const std::vector<std::string> &values, Format *, int) { - using namespace boost::program_options; - - const std::string &s = validators::get_single_string(values); - - if (s == "plain") { - v = boost::any(Format::PLAIN); - } else if (s == "json") { - v = boost::any(Format::JSON); - } else if (s == "sql") { - v = boost::any(Format::SQL); - } 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 if (arg == Format::SQL) - return "sql"; - else - throw std::runtime_error("Unknown format value: " + lexical_cast<string>(arg)); -} - -} - bool loop; -Format format; +sample_format_type format; time_point<system_clock> targetTime; unsigned int sleepTime; vector<unsigned int> sensors; @@ -92,19 +55,19 @@ void withConnection(BluetoothGatt &gatt) { auto timestamp = duration_cast<seconds>(epoch).count(); uint16_t value = soilMoisture.getValue((uint8_t) sensor); - if (format == Format::PLAIN) { + 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 == Format::JSON) { + } 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 == Format::SQL) { + } else if (format == sample_format_type::SQL) { cout << "INSERT INTO soil_moisture_sample(device, sensor, timestamp, value) VALUES(" << "'" << device.str() << "', " << sensor << ", " @@ -131,7 +94,7 @@ public: ("sensor", po::value<vector<unsigned int>>(&sensors)->multitoken(), "Sensor to poll, defaults to all") ("sleep", po::value<unsigned int>(&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>(&format)->default_value(Format::PLAIN), "Output format"); + ("format", po::value<sample_format_type>(&format)->default_value(sample_format_type::KEY_VALUE), "Output format"); } diff --git a/apps/sm-serial-read.cpp b/apps/sm-serial-read.cpp index 10981e0..aa997e5 100644 --- a/apps/sm-serial-read.cpp +++ b/apps/sm-serial-read.cpp @@ -5,44 +5,6 @@ #include <thread> #include <boost/asio/serial_port.hpp> -enum class Format { - PLAIN, - JSON, - SQL -}; - -void validate(boost::any &v, const std::vector<std::string> &values, Format *, int) { - using namespace boost::program_options; - - const std::string &s = validators::get_single_string(values); - - if (s == "plain") { - v = boost::any(Format::PLAIN); - } else if (s == "json") { - v = boost::any(Format::JSON); - } else if (s == "sql") { - v = boost::any(Format::SQL); - } else { - throw validation_error(validation_error::invalid_option_value); - } -} - -namespace boost { - -template<> -std::string lexical_cast(const Format &arg) { - if (arg == Format::PLAIN) - return "plain"; - else if (arg == Format::JSON) - return "json"; - else if (arg == Format::SQL) - return "sql"; - else - throw std::runtime_error("Unknown format value: " + lexical_cast<std::string>(arg)); -} - -} - namespace trygvis { namespace apps { @@ -54,7 +16,7 @@ using namespace trygvis::soil_moisture; namespace po = boost::program_options; using json = nlohmann::json; -Format format; +sample_format_type format; string hostname = get_hostname(); class port_handler { @@ -94,7 +56,7 @@ public: options ("help", "produce help message") ("port", po::value<string>()->required(), "The serial port to read") - ("format", po::value<Format>(&format)->default_value(Format::PLAIN), "Output format"); + ("format", po::value<sample_format_type>(&format)->default_value(sample_format_type::KEY_VALUE), "Output format"); } int main(app_execution &execution) override { @@ -122,19 +84,8 @@ public: cerr << "port is not open" << endl; } - shared_ptr<SampleOutputStream> output; shared_ptr<ostream> outputStream = shared_ptr<ostream>(&cout, noop_deleter); - - if (format == Format::JSON) { - output = make_shared<JsonSampleOutputStream>(outputStream, dict); - } else if (format == Format::SQL) { - output = make_shared<SqlSampleOutputStream>(outputStream, dict, "raw"); - } else if (format == Format::PLAIN) { - output = make_shared<CsvSampleOutputStream>(outputStream, dict); - } else { - cerr << "Unsupported format: " << boost::lexical_cast<string>(format) << endl; - return EXIT_FAILURE; - } + shared_ptr<SampleOutputStream> output = open_sample_output_stream(outputStream, dict, format); shared_ptr<KeyValueSampleParser> input = make_shared<KeyValueSampleParser>(output, dict); |