mirror of
https://github.com/owntracks/recorder.git
synced 2026-02-13 20:49:51 +00:00
Support for Greenwich batt,ext,status arrays in LAST
This commit is contained in:
4
Makefile
4
Makefile
@@ -48,6 +48,10 @@ ifeq ($(WITH_HTTP),yes)
|
||||
OTR_OBJS += mongoose.o http.o
|
||||
endif
|
||||
|
||||
ifeq ($(WITH_GREENWICH),yes)
|
||||
CFLAGS += -DWITH_GREENWICH=1
|
||||
endif
|
||||
|
||||
ifeq ($(JSON_INDENT),yes)
|
||||
CFLAGS += -DJSON_INDENT="\" \""
|
||||
else
|
||||
|
||||
@@ -375,7 +375,7 @@ As mentioned earlier, data is stored in files, and these files are relative to `
|
||||
* `cards/`, optional, contains user cards which are published when either you or one of your trackers on Hosted adds a new device. This card is then stored here and used with, e.g., `ocat --last` to show a user's name and optional avatar.
|
||||
* `config/`, optional, contains the JSON of a [device configuration](http://owntracks.org/booklet/features/remoteconfig/) (`.otrc`) which was requested remotely via a [dump command](http://owntracks.org/booklet/tech/json/#_typecmd). Note that this will contain sensitive data. You can use this `.otrc` file to restore the OwnTracks configuration on your device by copying to the device and opening it in OwnTracks.
|
||||
* `ghash/`, unless disabled, reverse Geo data is collected into an LMDB database located in this directory. This LMDB database also contains named databases which are used by your optional Lua hooks, as well as a `topic2tid` database which can be used for TID re-mapping.
|
||||
* `last/` contains the last location published by devices. E.g. Jane's last publish from her iPhone would be in `last/jjolie/iphone/jjolie-iphone.json`. The JSON payload contained therein is enhanced with the fields `user`, `device`, `topic`, and `ghash`. If a device's `last/` directory contains a file called `extra.json` (i.e. matching the example, this would be `last/jjolie/iphone/extra.json`), the content of this file is merged into the existing JSON for this user and returned by the API. Note, that you cannot overwrite existing values. So, an `extra.json` containing `{ "tst" : 11 }` will do nothing because the `tst` element we obtain from location data overrules, but adding `{ "beverage" : "water" }` will do what you want.
|
||||
* `last/` contains the last location published by devices. E.g. Jane's last publish from her iPhone would be in `last/jjolie/iphone/jjolie-iphone.json`. The JSON payload contained therein is enhanced with the fields `user`, `device`, `topic`, and `ghash`. If a device's `last/` directory contains a file called `extra.json` (i.e. matching the example, this would be `last/jjolie/iphone/extra.json`), the content of this file is merged into the existing JSON for this user and returned by the API. Note, that you cannot overwrite existing values. So, an `extra.json` containing `{ "tst" : 11 }` will do nothing because the `tst` element we obtain from location data overrules, but adding `{ "beverage" : "water" }` will do what you want. If _recorder_ is built with support for our Greenwich firmware, this directory might contain `batt.json`, `ext.json`, and/or `status.json` each of which hold an array of the last 100 reports for internal battery voltage, external voltage, and status respectively. These values are returned via the API in the LAST object.
|
||||
* `monitor` a file which contains a timestamp and the last received topic (see Monitoring below).
|
||||
* `msg/` contains messages received by the Messaging system.
|
||||
* `photos/` optional; contains the binary photos from a _card_.
|
||||
|
||||
@@ -21,6 +21,9 @@ WITH_KILL ?= no
|
||||
# If you set this to `yes', WITH_LMDB will be set to yes
|
||||
WITH_RONLY ?= no
|
||||
|
||||
# Do you require support for OwnTracks Greenwich firmware?
|
||||
WITH_GREENWICH ?= no
|
||||
|
||||
# Where should the recorder store its data? This directory must
|
||||
# exist and be writeable by recorder (and readable by ocat)
|
||||
STORAGEDEFAULT = /var/spool/owntracks/recorder/store
|
||||
|
||||
88
recorder.c
88
recorder.c
@@ -58,6 +58,7 @@
|
||||
#define TOPIC_PARTS (4) /* owntracks/user/device/info */
|
||||
#define DEFAULT_QOS (2)
|
||||
#define CLEAN_SESSION false
|
||||
#define GWNUMBERSMAX 50 /* number of batt,ext,status in array */
|
||||
|
||||
static int run = 1;
|
||||
|
||||
@@ -469,6 +470,71 @@ static void ronly_set(struct udata *ud, UT_string *basetopic, int active)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_GREENWICH
|
||||
|
||||
/*
|
||||
* key is "batt", "ext", or "status"
|
||||
* value is a string which contains a number
|
||||
*
|
||||
* Open/create a file at gw/user/device/user-device.json. Append to the existing array,
|
||||
* limiting the number of array entries.
|
||||
*/
|
||||
|
||||
void store_gwvalue(char *username, char *device, time_t tst, char *key, char *value)
|
||||
{
|
||||
static UT_string *ts = NULL;
|
||||
JsonNode *array, *o, *j;
|
||||
int count = 0;
|
||||
char *js;
|
||||
|
||||
utstring_renew(ts);
|
||||
utstring_printf(ts, "%s/last/%s/%s",
|
||||
STORAGEDIR,
|
||||
username,
|
||||
device);
|
||||
if (mkpath(UB(ts)) < 0) {
|
||||
olog(LOG_ERR, "Cannot mkdir %s: %m", UB(ts));
|
||||
return;
|
||||
}
|
||||
|
||||
utstring_printf(ts, "/%s.json", key);
|
||||
|
||||
/* Read file into array or create array on error */
|
||||
if ((js = slurp_file(UB(ts), TRUE)) != NULL) {
|
||||
if ((array = json_decode(js)) == NULL) {
|
||||
array = json_mkarray();
|
||||
}
|
||||
free(js);
|
||||
} else {
|
||||
array = json_mkarray();
|
||||
}
|
||||
|
||||
|
||||
/* Count elements in array and pop first if too long */
|
||||
json_foreach(j, array) {
|
||||
++count;
|
||||
}
|
||||
if (count >= GWNUMBERSMAX) {
|
||||
j = json_first_child(array);
|
||||
json_delete(j);
|
||||
}
|
||||
|
||||
o = json_mkobject();
|
||||
|
||||
json_append_member(o, "tst", json_mknumber(tst));
|
||||
json_append_member(o, key, json_mknumber(atof(value)));
|
||||
|
||||
json_append_element(array, o);
|
||||
|
||||
if ((js = json_stringify(array, NULL)) != NULL) {
|
||||
safewrite(UB(ts), js);
|
||||
free(js);
|
||||
}
|
||||
|
||||
json_delete(array);
|
||||
}
|
||||
#endif /* GREENWICH */
|
||||
|
||||
void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *m)
|
||||
{
|
||||
JsonNode *json, *j, *geo = NULL;
|
||||
@@ -558,7 +624,6 @@ void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_m
|
||||
utstring_printf(username, "%s", topics[1 + skipslash]);
|
||||
utstring_printf(device, "%s", topics[2 + skipslash]);
|
||||
|
||||
mosquitto_sub_topic_tokens_free(&topics, count);
|
||||
|
||||
#ifdef WITH_PING
|
||||
if (!strcmp(UB(username), "ping") && !strcmp(UB(device), "ping")) {
|
||||
@@ -566,8 +631,27 @@ void on_message(struct mosquitto *mosq, void *userdata, const struct mosquitto_m
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_GREENWICH
|
||||
/*
|
||||
* First things first: let's see if this contains some sort of valid JSON
|
||||
* For Greenwich: handle owntracks/user/device/voltage/batt, voltage/ext, and
|
||||
* status all of which have a numeric payload.
|
||||
*/
|
||||
|
||||
if ((count == 5+skipslash && !strcmp(topics[3+skipslash], "voltage")) &&
|
||||
(!strcmp(topics[4+skipslash], "batt") || !strcmp(topics[4+skipslash], "ext"))) {
|
||||
store_gwvalue(UB(username), UB(device), now, topics[4+skipslash], m->payload);
|
||||
}
|
||||
|
||||
if (count == 4+skipslash && !strcmp(topics[3+skipslash], "status")) {
|
||||
store_gwvalue(UB(username), UB(device), now, "status", m->payload);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
mosquitto_sub_topic_tokens_free(&topics, count);
|
||||
|
||||
/*
|
||||
* Now let's see if this contains some sort of valid JSON
|
||||
* or an OwnTracks CSV. If it doesn't, just store this payload because
|
||||
* there's nothing left for us to do with it.
|
||||
*/
|
||||
|
||||
36
storage.c
36
storage.c
@@ -142,6 +142,39 @@ static int user_device_list(char *name, int level, JsonNode *obj)
|
||||
return (rc);
|
||||
}
|
||||
|
||||
#if WITH_GREENWICH
|
||||
/*
|
||||
* See if we have batt,ext,status data for this device, and if so, add
|
||||
* their arrays into the JSON object at `last'.
|
||||
*/
|
||||
|
||||
static void get_gw_data(char *username, char *device, JsonNode *last)
|
||||
{
|
||||
JsonNode *array;
|
||||
static char *types[] = { "batt", "ext", "status", NULL };
|
||||
char **t, *js;
|
||||
static UT_string *ts = NULL;
|
||||
|
||||
for (t = types; t && *t; t++) {
|
||||
utstring_renew(ts);
|
||||
utstring_printf(ts, "%s/last/%s/%s/%s.json",
|
||||
STORAGEDIR,
|
||||
username,
|
||||
device,
|
||||
*t);
|
||||
|
||||
/* Read file into JSON array and append to `last' object */
|
||||
if ((js = slurp_file(UB(ts), TRUE)) != NULL) {
|
||||
if ((array = json_decode(js)) != NULL) {
|
||||
json_append_member(last, *t, array);
|
||||
}
|
||||
free(js);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* GREENWICH */
|
||||
|
||||
void append_device_details(JsonNode *userlist, char *user, char *device)
|
||||
{
|
||||
char path[BUFSIZ];
|
||||
@@ -183,6 +216,9 @@ void append_device_details(JsonNode *userlist, char *user, char *device)
|
||||
snprintf(path, BUFSIZ, "%s/last/%s/%s/extra.json",
|
||||
STORAGEDIR, user, device);
|
||||
json_copy_from_file(last, path);
|
||||
#if WITH_GREENWICH
|
||||
get_gw_data(user, device, last);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user