aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/SoilMoistureIo.cpp140
-rw-r--r--apps/SoilMoistureIo.h26
-rw-r--r--apps/sample-convert.cpp105
3 files changed, 145 insertions, 126 deletions
diff --git a/apps/SoilMoistureIo.cpp b/apps/SoilMoistureIo.cpp
index 98a256b..24618ff 100644
--- a/apps/SoilMoistureIo.cpp
+++ b/apps/SoilMoistureIo.cpp
@@ -11,94 +11,140 @@ namespace soil_moisture {
using namespace std;
using json = nlohmann::json;
+CsvSampleOutputStream::CsvSampleOutputStream(ostream &stream) :
+ stream(stream), filterFields(false), headerWritten(false) {
+}
+
CsvSampleOutputStream::CsvSampleOutputStream(ostream &stream, vector<string> fields) :
- stream(stream), fields(fields) {
+ stream(stream), fields(fields), filterFields(true), headerWritten(false) {
+}
- auto i = fields.begin();
- while (true) {
- stream << *i;
+void CsvSampleOutputStream::write(Sample values) {
+ if (!headerWritten) {
+ writeHeader();
+ headerWritten = true;
+ }
- i++;
+ if (filterFields) {
+ auto i = fields.begin();
+ while (i != fields.end()) {
+ if (i != fields.begin()) {
+ stream << ",";
+ }
- if (i != fields.end()) {
- stream << ",";
- } else {
- break;
+ auto field = *i++;
+ auto value = values.find(field);
+
+ if (value != values.end()) {
+ stream << value->second;
+ }
+ }
+ } else {
+ for (auto i = values.begin(); i != values.end();) {
+ stream << "\"" << (*i).second << "\"";
+
+ if (++i != values.end()) {
+ stream << ",";
+ }
}
}
stream << endl;
}
-void CsvSampleOutputStream::write(Sample values) {
- auto i = fields.begin();
- while (true) {
- auto field = *i;
- auto value = values.find(field);
+void CsvSampleOutputStream::writeHeader() {
+ if (fields.size() == 0) {
+ return;
+ }
- if (value != values.end()) {
- stream << value->second;
- }
+ auto i = fields.begin();
+ while (i != fields.end()) {
+ stream << *i;
i++;
if (i != fields.end()) {
stream << ",";
- } else {
- break;
}
}
stream << endl;
}
+JsonSampleOutputStream::JsonSampleOutputStream(ostream &stream) :
+ stream(stream), fields(), filterFields(false) {
+}
+
JsonSampleOutputStream::JsonSampleOutputStream(ostream &stream, vector<string> fields) :
- stream(stream), fields(fields) {
+ stream(stream), fields(fields), filterFields(true) {
}
void JsonSampleOutputStream::write(Sample values) {
json doc({});
- for (auto &f: fields) {
- auto value = values.find(f);
+ if (filterFields) {
+ for (auto &f: fields) {
+ auto value = values.find(f);
- if (value != values.end()) {
- doc[f] = value->second;
+ if (value != values.end()) {
+ doc[f] = value->second;
+ }
+ }
+ } else {
+ for (auto &v: values) {
+ doc[v.first] = v.second;
}
}
stream << doc << endl;
}
+SqlSampleOutputStream::SqlSampleOutputStream(ostream &stream) :
+ stream(stream), filterFields(false) {
+}
+
SqlSampleOutputStream::SqlSampleOutputStream(ostream &stream, vector<string> fields) :
- stream(stream), fields(fields) {
+ stream(stream), fields(fields), filterFields(true) {
}
void SqlSampleOutputStream::write(Sample values) {
- auto i = fields.begin();
-
stringstream fs, vs;
- while (true) {
- auto field = *i;
+ if (filterFields) {
+ auto i = fields.begin();
- fs << field;
+ while (i != fields.end()) {
+ auto field = *i;
- auto value = values.find(field);
+ fs << field;
- if (value != values.end()) {
- vs << "'" << value->second << "'";
- } else {
- vs << "NULL";
- }
+ auto value = values.find(field);
- i++;
+ if (value != values.end()) {
+ vs << "'" << value->second << "'";
+ } else {
+ vs << "NULL";
+ }
- if (i != fields.end()) {
- fs << ",";
- vs << ",";
- } else {
- break;
+ i++;
+
+ if (i != fields.end()) {
+ fs << ",";
+ vs << ",";
+ }
+ }
+ } else {
+ auto i = values.begin();
+ while (i != values.end()) {
+ auto v = *i++;
+
+ fs << v.first;
+ vs << "'" << v.second << "'";
+
+ if (i != values.end()) {
+ fs << ",";
+ vs << ",";
+ }
}
}
@@ -126,7 +172,6 @@ void CsvParser::process(mutable_buffers_1 buffer) {
void CsvParser::process_line(shared_ptr<vector<uint8_t>> packet) {
auto timestamp = std::chrono::system_clock::now().time_since_epoch().count();
auto s = std::string((char *) packet->data(), packet->size());
-// cerr << "packet: " << s << ", size=" << packet->size() << endl;
static const boost::regex e("([_a-zA-Z0-9]+)=([0-9]+)");
@@ -142,17 +187,8 @@ void CsvParser::process_line(shared_ptr<vector<uint8_t>> packet) {
auto value = static_cast<string>(what[2]);
start = what[0].second;
-// static const string device_type = "serial";
map<string, string> values;
values[key] = value;
-// values["hostname"] = hostname;
-// values["device"] = device;
-// values["device_type"] = device_type;
-// values["timestamp"] = to_string(timestamp);
-// values["sensor"] = sensor;
-// values["value"] = value;
-
-// cerr << key << " => " << value << endl;
sample[key] = value;
diff --git a/apps/SoilMoistureIo.h b/apps/SoilMoistureIo.h
index aff7c85..4edf4f4 100644
--- a/apps/SoilMoistureIo.h
+++ b/apps/SoilMoistureIo.h
@@ -34,7 +34,7 @@ public:
return entries.end();
}
- string& operator[](string key) {
+ string &operator[](string key) {
return entries[key];
}
@@ -49,34 +49,46 @@ public:
class CsvSampleOutputStream : public SampleOutputStream {
public:
- CsvSampleOutputStream(ostream& stream, vector<string> fields);
+ CsvSampleOutputStream(ostream &stream);
+
+ CsvSampleOutputStream(ostream &stream, vector<string> fields);
void write(Sample values);
private:
- ostream& stream;
+ void writeHeader();
+
+ ostream &stream;
+ bool headerWritten;
+ bool filterFields;
vector<string> fields;
};
class JsonSampleOutputStream : public SampleOutputStream {
public:
- JsonSampleOutputStream(ostream& stream, vector<string> fields);
+ JsonSampleOutputStream(ostream &stream);
+
+ JsonSampleOutputStream(ostream &stream, vector<string> fields);
void write(Sample values);
private:
- ostream& stream;
+ ostream &stream;
+ bool filterFields;
vector<string> fields;
};
class SqlSampleOutputStream : public SampleOutputStream {
public:
- SqlSampleOutputStream(ostream& stream, vector<string> fields);
+ SqlSampleOutputStream(ostream &stream);
+
+ SqlSampleOutputStream(ostream &stream, vector<string> fields);
void write(Sample values);
private:
- ostream& stream;
+ ostream &stream;
+ bool filterFields;
vector<string> fields;
};
diff --git a/apps/sample-convert.cpp b/apps/sample-convert.cpp
index 9a0627d..370059c 100644
--- a/apps/sample-convert.cpp
+++ b/apps/sample-convert.cpp
@@ -1,45 +1,7 @@
#include "SoilMoistureIo.h"
#include "json.hpp"
#include "apps.h"
-#include <istream>
-
-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));
-}
-
-}
+#include <fstream>
namespace trygvis {
namespace apps {
@@ -49,17 +11,20 @@ using namespace trygvis::apps;
using namespace trygvis::soil_moisture;
namespace po = boost::program_options;
-Format inputFormat, outputFormat;
+string inputFile, inputFormat;
+string outputFile, outputFormat;
class sample_convert : public app {
public:
-// void add_options(po::options_description_easy_init &options) override {
-// options
-// ("help", "produce help message")
-// ("input-format", po::value<Format>(&inputFormat)->default_value(Format::PLAIN))
-// ("output-format", po::value<Format>(&outputFormat)->default_value(Format::PLAIN))
-// }
+ void add_options(po::options_description_easy_init &options) override {
+ options
+ ("help", "produce this help message")
+ ("input", po::value<string>(&inputFile)->default_value("-"))
+ ("input-format", po::value<string>(&inputFormat)->default_value("csv"))
+ ("output", po::value<string>(&outputFile)->default_value("-"))
+ ("output-format", po::value<string>(&outputFormat)->default_value("plain"));
+ }
int main(app_execution &execution) override {
auto desc = execution.desc;
@@ -67,31 +32,36 @@ public:
shared_ptr<SampleOutputStream> output;
- auto field_names = vector<string>({
- "hostname",
- "device_type",
- "device",
- "timestamp",
- "sensor",
- "value"
- });
-
- field_names = vector<string>({
- "analog",
- "dry",
- "water",
- "last_watering_started",
- "last_watering_stopped",
- "now"
- });
-
- output = make_shared<JsonSampleOutputStream>(cout, field_names);
+ istream *inputStream;
+ if (inputFile == "-") {
+ inputStream = &cin;
+ } else {
+ inputStream = new ifstream(inputFile);
+ }
+
+ ostream *outputStream;
+ if (outputFile == "-") {
+ outputStream = &cout;
+ } else {
+ outputStream = new ofstream(outputFile);
+ }
+
+ if (outputFormat == "plain") {
+ output = make_shared<CsvSampleOutputStream>(*outputStream);
+ } else if (outputFormat == "json") {
+ output = make_shared<JsonSampleOutputStream>(*outputStream);
+ } else if (outputFormat == "sql") {
+ output = make_shared<SqlSampleOutputStream>(*outputStream);
+ } else {
+ cerr << "Unsupported output format: " << outputFormat << endl;
+ return EXIT_FAILURE;
+ }
auto input = make_shared<CsvParser>(output);
char data[100];
- while (!cin.eof()) {
- cin.get(data[0]);
+ while (!inputStream->eof()) {
+ inputStream->get(data[0]);
input->process(boost::asio::buffer(data, 1));
}
@@ -104,6 +74,7 @@ public:
}
using namespace trygvis::apps;
+
int main(int argc, char *argv[]) {
sample_convert app;
return launch_app(argc, argv, app);