Skip to content

Commit

Permalink
Added upate_period and scan_duration args
Browse files Browse the repository at this point in the history
  • Loading branch information
anders617 committed Oct 11, 2020
1 parent d2ea40a commit 1d8f76d
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 105 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ Run `make` from the govee directory and the executable should end up at `build/a

Run:
```bash
./build/apps/govee --streamname=govee-data
./build/apps/govee --stream_name=govee-data
```

## Installing as a system service
(These instructions are also in `install.sh`)

Change the ExecStart line in `govee.service` to match your AWS kinesis stream name:
```
ExecStart=/bin/govee --streamname=YOUR_STREAM_NAME
ExecStart=/bin/govee --stream_name=YOUR_STREAM_NAME
```

Copy `govee.service` to `/etc/systemd/system/govee.service`:
Expand Down
2 changes: 1 addition & 1 deletion govee.service
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Requires=bluetooth.target
[Service]
Type=simple
User=root
ExecStart=/bin/govee --streamname=govee-data
ExecStart=/bin/govee --stream_name=govee-data
Restart=always
RestartSec=5
StartLimitBurst=5
Expand Down
6 changes: 6 additions & 0 deletions src/BTScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

#include <iostream>

namespace govee {

const int ON = 1;
const int OFF = 0;

using util::CHECK;

BTScanner::BTScanner(const std::string &bd_addr) {
bdaddr_t ba;
CHECK(str2ba(bd_addr.c_str(), &ba), "Invalid string address: " + bd_addr);
Expand Down Expand Up @@ -102,3 +106,5 @@ bool BTScanner::scan(std::function<bool(evt_le_meta_event *)> handle_message,
"Failed to disable scan");
return false;
}

} // namespace govee
12 changes: 8 additions & 4 deletions src/BTScanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

#include "Util.h"

namespace govee {

// Class for scanning for evt_le_meta_event bluetooth events.
//
// Can be used with a function handler:
Expand Down Expand Up @@ -72,8 +74,8 @@ bool BTScanner::scan(T &event_handler,
scanning = true;
auto scanStartTime = std::chrono::steady_clock::now();
// Enable scanning
CHECK(hci_le_set_scan_enable(device_handle, 0x01, 1, 1000),
"Failed to enable scan");
util::CHECK(hci_le_set_scan_enable(device_handle, 0x01, 1, 1000),
"Failed to enable scan");
while (scanning && !error) {
if (std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::steady_clock::now() - scanStartTime)
Expand All @@ -89,9 +91,11 @@ bool BTScanner::scan(T &event_handler,
}
}
// Disable scanning
CHECK(hci_le_set_scan_enable(device_handle, 0x00, 1, 1000),
"Failed to disable scan");
util::CHECK(hci_le_set_scan_enable(device_handle, 0x00, 1, 1000),
"Failed to disable scan");
return false;
}

} // namespace govee

#endif
4 changes: 4 additions & 0 deletions src/GoveeData.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include <string>

namespace govee {

struct GoveeData {
long long int timestamp;
std::string name;
Expand All @@ -19,4 +21,6 @@ std::string to_json(const GoveeData &data) {
return s.str();
}

} // namespace govee

#endif
26 changes: 16 additions & 10 deletions src/GoveeEventHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

#include "Util.h"

namespace govee {

using util::Log;

int GoveeEventParser::add_name_handler(NameEventHandler name_handler) {
int id = next_handler_id++;
name_handlers[id] = name_handler;
Expand All @@ -14,16 +18,14 @@ int GoveeEventParser::add_data_handler(DataEventHandler data_handler) {
return next_handler_id;
}

void GoveeEventParser::remove_name_handler(int id) {
name_handlers.erase(id);
}
void GoveeEventParser::remove_name_handler(int id) { name_handlers.erase(id); }

void GoveeEventParser::remove_data_handler(int id) {
data_handlers.erase(id);
}
void GoveeEventParser::remove_data_handler(int id) { data_handlers.erase(id); }

std::optional<std::tuple<float, float, int>> GoveeEventParser::read_data(const uint8_t *data, const size_t data_len) {
if (data_len != 9 && data_len != 10) return std::nullopt;
std::optional<std::tuple<float, float, int>>
GoveeEventParser::read_data(const uint8_t *data, const size_t data_len) {
if (data_len != 9 && data_len != 10)
return std::nullopt;
if ((data[1] == 0x88) && (data[2] == 0xEC)) {
float temp = -1, humidity = -1;
int battery = -1;
Expand Down Expand Up @@ -77,11 +79,13 @@ void GoveeEventParser::parse(evt_le_meta_event *meta) {
std::string_view strAddr(addr);
if ((info->data + current_offset + 1)[0] == EIR_NAME_SHORT ||
(info->data + current_offset + 1)[0] == EIR_NAME_COMPLETE) {
std::string name((char *)&((info->data + current_offset + 1)[1]), data_len-1);
std::string name((char *)&((info->data + current_offset + 1)[1]),
data_len - 1);
for (const auto &[id, name_handler] : name_handlers) {
name_handler(strAddr, name);
}
} else if ((info->data + current_offset + 1)[0] == EIR_MANUFACTURE_SPECIFIC) {
} else if ((info->data + current_offset + 1)[0] ==
EIR_MANUFACTURE_SPECIFIC) {
if (auto new_data =
read_data((info->data + current_offset + 1), data_len)) {
const auto [temp, humidity, battery] = *new_data;
Expand All @@ -94,3 +98,5 @@ void GoveeEventParser::parse(evt_le_meta_event *meta) {
}
}
}

} // namespace govee
71 changes: 42 additions & 29 deletions src/GoveeEventHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,50 @@
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>

namespace govee {

/**
* Class for parsing bluetooth evt_le_meta_event messages that contain Govee data.
*
* Name handlers are called when a message advertising the name for a device is parsed.
*
* Data handlers are called when a message containing temp/humidity/battery for a device is parsed.
*/
* Class for parsing bluetooth evt_le_meta_event messages that contain Govee
* data.
*
* Name handlers are called when a message advertising the name for a device is
* parsed.
*
* Data handlers are called when a message containing temp/humidity/battery for
* a device is parsed.
*/
class GoveeEventParser {
public:
// Associate `name` with the bluetooth `addr`
using NameEventHandler = std::function<void(std::string_view addr, std::string_view name)>;
// New data from the given `addr`
using DataEventHandler = std::function<void(std::string_view addr, float temp, float humidity, int battery)>;

GoveeEventParser() : next_handler_id(1) {}

// Returns the id of the handler which can be used when calling remove_name_handler
int add_name_handler(NameEventHandler name_handler);
// Returns the id of the handler which can be used when calling remove_name_handler
int add_data_handler(DataEventHandler data_handler);

void remove_name_handler(int id);
void remove_data_handler(int id);

void parse(evt_le_meta_event *meta);
private:
std::optional<std::tuple<float, float, int>> read_data(const uint8_t *data, const size_t data_len);

int next_handler_id;
std::unordered_map<int, NameEventHandler> name_handlers;
std::unordered_map<int, DataEventHandler> data_handlers;
public:
// Associate `name` with the bluetooth `addr`
using NameEventHandler =
std::function<void(std::string_view addr, std::string_view name)>;
// New data from the given `addr`
using DataEventHandler = std::function<void(std::string_view addr, float temp,
float humidity, int battery)>;

GoveeEventParser() : next_handler_id(1) {}

// Returns the id of the handler which can be used when calling
// remove_name_handler
int add_name_handler(NameEventHandler name_handler);
// Returns the id of the handler which can be used when calling
// remove_name_handler
int add_data_handler(DataEventHandler data_handler);

void remove_name_handler(int id);
void remove_data_handler(int id);

void parse(evt_le_meta_event *meta);

private:
std::optional<std::tuple<float, float, int>> read_data(const uint8_t *data,
const size_t data_len);

int next_handler_id;
std::unordered_map<int, NameEventHandler> name_handlers;
std::unordered_map<int, DataEventHandler> data_handlers;
};

} // namespace govee

#endif
58 changes: 57 additions & 1 deletion src/Util.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#include "Util.h"

#include <chrono>
#include <getopt.h>
#include <iostream>

namespace govee::util {

void Log(const char *format, ...) {
printf("[%lld] ",
std::chrono::system_clock::now().time_since_epoch().count());
Expand All @@ -13,3 +15,57 @@ void Log(const char *format, ...) {
printf("\n");
fflush(stdout);
}

void print_help() {
Log("Usage: govee");
Log("\t--stream_name\tname\t[required]\tName of the AWS Kinesis stream to "
"push to");
Log("\t--update_period\t60\t[default=60]\tNumber of seconds between pushes "
"to the Kinesis stream.");
Log("\t--scan_duration\t10\t[default=10]\tNumber of seconds to wait for data "
"from devices before uploading");
}

Args parse_args(int argc, char *argv[]) {
const struct option longopts[] = {
{"help", no_argument, 0, 'h'},
{"stream_name", required_argument, 0, 's'},
{"update_period", required_argument, 0, 'u'},
{"scan_duration", required_argument, 0, 'd'},
{0, 0, 0, 0},
};
Args args;
int index;
int iarg = 0;
while (iarg != -1) {
switch (iarg = getopt_long(argc, argv, "hs:", longopts, &index)) {
case 'h':
print_help();
break;
case 's':
args.stream_name = std::string(optarg);
break;
case 'u':
try {
args.update_period = std::stoll(std::string(optarg));
} catch (const std::invalid_argument &e) {
Log("Invalid integer: %s", std::string(optarg));
print_help();
exit(0);
}
break;
case 'd':
try {
args.scan_duration = std::stoll(std::string(optarg));
} catch (const std::invalid_argument &e) {
Log("Invalid integer: %s", std::string(optarg));
print_help();
exit(0);
}
break;
}
}
return args;
}

} // namespace govee::util
17 changes: 16 additions & 1 deletion src/Util.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
#ifndef UTIL_H
#define UTIL_H

#include <chrono>
#include <cstdarg>
#include <functional>
#include <cstring>
#include <functional>

constexpr uint8_t EIR_FLAGS = 0X01;
constexpr uint8_t EIR_NAME_SHORT = 0x08;
constexpr uint8_t EIR_NAME_COMPLETE = 0x09;
constexpr uint8_t EIR_MANUFACTURE_SPECIFIC = 0xFF;

namespace govee::util {

void Log(const char *format, ...);

struct Defer {
Expand All @@ -27,4 +30,16 @@ template <typename T> T CHECK(T t, const std::string &msg) {
return t;
}

struct Args {
std::optional<std::string> stream_name;
std::optional<std::chrono::seconds::rep> update_period;
std::optional<std::chrono::seconds::rep> scan_duration;
};

void print_help();

Args parse_args(int argc, char *argv[]);

} // namespace govee::util

#endif
Loading

0 comments on commit 1d8f76d

Please sign in to comment.