mirror of
https://github.com/owntracks/recorder.git
synced 2026-05-07 02:46:36 +00:00
Split Lua hooks docs into their own file
This commit is contained in:
93
HOOKS.md
Normal file
93
HOOKS.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Lua hooks
|
||||
|
||||
If Recorder is compiled with Lua support, a Lua script you provide is launched at startup. Lua is _a powerful, fast, lightweight, embeddable scripting language_. You can use this to process location publishes in any way you desire: your imagination (and Lua-scripting knowhow) set the limits. Some examples:
|
||||
|
||||
* insert publishes into a database of your choice
|
||||
* switch on the coffee machine when your OwnTracks device reports you're entering home (but see also [mqttwarn](http://jpmens.net/2014/02/17/introducing-mqttwarn-a-pluggable-mqtt-notifier/))
|
||||
* write a file with data in a format of your choice (see `etc/example.lua`)
|
||||
|
||||
Run the Recorder with the path to your Lua script specified in its `--lua-script` option (there is no default). If the script cannot be loaded (e.g. because it cannot be read or contains syntax errors), the Recorder unloads Lua and continues *without* your script.
|
||||
|
||||
If the Lua script can be loaded, it is automatically provided with a table variable called `otr` which contains the following members:
|
||||
|
||||
* `otr.version` is a read-only string with the Recorder version (example: `"0.3.2"`)
|
||||
* `otr.log(s)` is a function which takes a string `s` which is logged to syslog at the Recorder's facility and log level INFO.
|
||||
* `otr.strftime(fmt, t)` is a function which takes a format string `fmt` (see `strftime(3)`) and an integer number of seconds `t` and returns a string with the formatted UTC time. If `t` is 0 or negative, the current system time is used.
|
||||
* `otr.putdb(key, value)` is a function which takes two strings `k` and `v` and stores them in the named LMDB database called `luadb`. This can be viewed with
|
||||
* `otr.getdb(key)` is a function which takes a single string `key` and returns the database value associated with that key or `nil` if the key isn't stored.
|
||||
|
||||
```
|
||||
ocat --dump=luadb
|
||||
```
|
||||
|
||||
Your Lua script *must* provide the following functions:
|
||||
|
||||
## `otr_init`
|
||||
|
||||
This is invoked at start of Recorder. If the function returns a non-zero value, Recorder unloads Lua and disables its processing; i.e. the `hook()` will *not* be invoked on location publishes.
|
||||
|
||||
## `otr_exit`
|
||||
|
||||
This is invoked when the Recorder stops, which it doesn't really do unless you CTRL-C it or send it a SIGTERM signal.
|
||||
|
||||
|
||||
## `otr_hook`
|
||||
|
||||
This function is invoked at every location publish processed by the Recorder. Your function is passed three arguments:
|
||||
|
||||
1. _topic_ is the topic published to (e.g. `owntracks/jane/phone`)
|
||||
2. _type_ is the type of MQTT message. This is the `_type` in our JSON messages (e.g. `location`, `cmd`, `transition`, ...) or `"unknown"`.
|
||||
3. _location_ is a [Lua table](http://www.lua.org/pil/2.5.html) (associative array) with all the elements obtained in the JSON message. In the case of _type_ being `location`, we also add country code (`cc`) and the location's address (`addr`) unless reverse-geo lookups have been disabled in Recorder.
|
||||
|
||||
Assume the following small example Lua script in `example.lua`:
|
||||
|
||||
```lua
|
||||
local file
|
||||
|
||||
function otr_init()
|
||||
otr.log("example.lua starting; writing to /tmp/lua.out")
|
||||
file = io.open("/tmp/lua.out", "a")
|
||||
file:write("written by OwnTracks Recorder version " .. otr.version .. "\n")
|
||||
end
|
||||
|
||||
function otr_hook(topic, _type, data)
|
||||
local timestr = otr.strftime("It is %T in the year %Y", 0)
|
||||
print("L: " .. topic .. " -> " .. _type)
|
||||
file:write(timestr .. " " .. topic .. " lat=" .. data['lat'] .. data['addr'] .. "\n")
|
||||
end
|
||||
|
||||
function otr_exit()
|
||||
end
|
||||
```
|
||||
|
||||
When Recorder is launched with `--lua-script example.lua` it invokes `otr_init()` which opens a file. Then, for each location received, it calls `otr_hook()` which updates the file.
|
||||
|
||||
Assuming an OwnTracks device publishes this payload
|
||||
|
||||
```json
|
||||
{"cog":-1,"batt":-1,"lon":2.29513,"acc":5,"vel":-1,"vac":-1,"lat":48.85833,"t":"u","tst":1441984413,"alt":0,"_type":"location","tid":"JJ"}
|
||||
```
|
||||
|
||||
the file `/tmp/lua.out` would contain
|
||||
|
||||
```txt
|
||||
written by OwnTracks Recorder version 0.3.0
|
||||
It is 14:10:01 in the year 2015 owntracks/jane/phone lat=48.858339 Avenue Anatole France, 75007 Paris, France
|
||||
```
|
||||
|
||||
## `otr_putrec`
|
||||
|
||||
An optional function you provide is called `otr_putrec(u, d, s)`. If it exists,
|
||||
it is called with the current user in `u`, the device in `d` and the payload
|
||||
(which for OwnTracks apps is JSON but for, eg Greenwich devices might not be) in the string `s`. If your function returns a
|
||||
non-zero value, the Recorder will *not* write the REC file for this publish.
|
||||
|
||||
## `otr_httpobject`
|
||||
|
||||
An optional function you provide is called `otr_httpobject(u, d, t, data)` where `u` is the username used by the client (`?u=`), `d` is the device name (`&d=` in the URI), `t` is the OwnTracks JSON `_type` and `data` a Lua table built from the OwnTracks JSON payload of `_type`. If it exists, this function is called whenever a POST is received in httpmode and the Recorder is gathering data to return to the client app. The function *must* return a Lua table containing any number of string, number, or boolean values which are converted to a JSON object and appended to the JSON array returned to the client. An [example](etc/example.lua) shows how, say, a transition event can be used to open the Featured content tab in the app.
|
||||
|
||||
## Hooklets
|
||||
|
||||
After running `otr_hook()`, the Recorder attempts to invoke a Lua function for each of the elements in the extended JSON. If, say, your Lua script contains a function called `hooklet_lat`, it will be invoked every time a `lat` is received as part of the JSON payload. Similarly with `hooklet_addr`, `hooklet_cc`, `hooklet_tst`, etc. These _hooklets_ are invoked with the same parameters as `otr_hook()`.
|
||||
|
||||
You define a hooklet function only if you're interested in expressly triggering on a particular JSON element.
|
||||
104
README.md
104
README.md
@@ -48,12 +48,6 @@ We developed the Recorder as a one-stop solution to storing location data publis
|
||||
* [The geo cache](#the-geo-cache)
|
||||
* [Monitoring](#monitoring)
|
||||
* [Lua hooks](#lua-hooks)
|
||||
* [`otr_init`](#otr_init)
|
||||
* [`otr_exit`](#otr_exit)
|
||||
* [`otr_hook`](#otr_hook)
|
||||
* [`otr_putrec`](#otr_putrec)
|
||||
* [`otr_httpobject`](#otr_httpobject)
|
||||
* [Hooklets](#hooklets)
|
||||
* [Views](#views)
|
||||
* [view JSON](#view-json)
|
||||
* [Authentication](#authentication)
|
||||
@@ -655,6 +649,10 @@ u09ey1r {"cc":"FR","addr":"D83, 91590 La Ferté-Alais, France","tst":1445435679,
|
||||
|
||||
The key to this data is the geohash string (here with an example of precision 2).
|
||||
|
||||
## Lua hooks
|
||||
|
||||
You can customize Recorder's behavior with Lua hooks. See [HOOKS.md](https://github.com/owntracks/recorder/blob/master/HOOKS.md).
|
||||
|
||||
## Monitoring
|
||||
|
||||
In order to monitor the Recorder, whenever an MQTT message is received, a `monitor` file located relative to STORAGEDEFAULT is maintained. It contains a single line of text: the epoch timestamp and the last received topic separated from each other by a space.
|
||||
@@ -672,100 +670,6 @@ After sending a _pingping_, you can query the REST interface to determine the di
|
||||
OK ot-recorder pingping at http://127.0.0.1:8085: 0 seconds difference
|
||||
```
|
||||
|
||||
## Lua hooks
|
||||
|
||||
If Recorder is compiled with Lua support, a Lua script you provide is launched at startup. Lua is _a powerful, fast, lightweight, embeddable scripting language_. You can use this to process location publishes in any way you desire: your imagination (and Lua-scripting knowhow) set the limits. Some examples:
|
||||
|
||||
* insert publishes into a database of your choice
|
||||
* switch on the coffee machine when your OwnTracks device reports you're entering home (but see also [mqttwarn](http://jpmens.net/2014/02/17/introducing-mqttwarn-a-pluggable-mqtt-notifier/))
|
||||
* write a file with data in a format of your choice (see `etc/example.lua`)
|
||||
|
||||
Run the Recorder with the path to your Lua script specified in its `--lua-script` option (there is no default). If the script cannot be loaded (e.g. because it cannot be read or contains syntax errors), the Recorder unloads Lua and continues *without* your script.
|
||||
|
||||
If the Lua script can be loaded, it is automatically provided with a table variable called `otr` which contains the following members:
|
||||
|
||||
* `otr.version` is a read-only string with the Recorder version (example: `"0.3.2"`)
|
||||
* `otr.log(s)` is a function which takes a string `s` which is logged to syslog at the Recorder's facility and log level INFO.
|
||||
* `otr.strftime(fmt, t)` is a function which takes a format string `fmt` (see `strftime(3)`) and an integer number of seconds `t` and returns a string with the formatted UTC time. If `t` is 0 or negative, the current system time is used.
|
||||
* `otr.putdb(key, value)` is a function which takes two strings `k` and `v` and stores them in the named LMDB database called `luadb`. This can be viewed with
|
||||
* `otr.getdb(key)` is a function which takes a single string `key` and returns the database value associated with that key or `nil` if the key isn't stored.
|
||||
|
||||
```
|
||||
ocat --dump=luadb
|
||||
```
|
||||
|
||||
Your Lua script *must* provide the following functions:
|
||||
|
||||
### `otr_init`
|
||||
|
||||
This is invoked at start of Recorder. If the function returns a non-zero value, Recorder unloads Lua and disables its processing; i.e. the `hook()` will *not* be invoked on location publishes.
|
||||
|
||||
### `otr_exit`
|
||||
|
||||
This is invoked when the Recorder stops, which it doesn't really do unless you CTRL-C it or send it a SIGTERM signal.
|
||||
|
||||
|
||||
### `otr_hook`
|
||||
|
||||
This function is invoked at every location publish processed by the Recorder. Your function is passed three arguments:
|
||||
|
||||
1. _topic_ is the topic published to (e.g. `owntracks/jane/phone`)
|
||||
2. _type_ is the type of MQTT message. This is the `_type` in our JSON messages (e.g. `location`, `cmd`, `transition`, ...) or `"unknown"`.
|
||||
3. _location_ is a [Lua table](http://www.lua.org/pil/2.5.html) (associative array) with all the elements obtained in the JSON message. In the case of _type_ being `location`, we also add country code (`cc`) and the location's address (`addr`) unless reverse-geo lookups have been disabled in Recorder.
|
||||
|
||||
Assume the following small example Lua script in `example.lua`:
|
||||
|
||||
```lua
|
||||
local file
|
||||
|
||||
function otr_init()
|
||||
otr.log("example.lua starting; writing to /tmp/lua.out")
|
||||
file = io.open("/tmp/lua.out", "a")
|
||||
file:write("written by OwnTracks Recorder version " .. otr.version .. "\n")
|
||||
end
|
||||
|
||||
function otr_hook(topic, _type, data)
|
||||
local timestr = otr.strftime("It is %T in the year %Y", 0)
|
||||
print("L: " .. topic .. " -> " .. _type)
|
||||
file:write(timestr .. " " .. topic .. " lat=" .. data['lat'] .. data['addr'] .. "\n")
|
||||
end
|
||||
|
||||
function otr_exit()
|
||||
end
|
||||
```
|
||||
|
||||
When Recorder is launched with `--lua-script example.lua` it invokes `otr_init()` which opens a file. Then, for each location received, it calls `otr_hook()` which updates the file.
|
||||
|
||||
Assuming an OwnTracks device publishes this payload
|
||||
|
||||
```json
|
||||
{"cog":-1,"batt":-1,"lon":2.29513,"acc":5,"vel":-1,"vac":-1,"lat":48.85833,"t":"u","tst":1441984413,"alt":0,"_type":"location","tid":"JJ"}
|
||||
```
|
||||
|
||||
the file `/tmp/lua.out` would contain
|
||||
|
||||
```txt
|
||||
written by OwnTracks Recorder version 0.3.0
|
||||
It is 14:10:01 in the year 2015 owntracks/jane/phone lat=48.858339 Avenue Anatole France, 75007 Paris, France
|
||||
```
|
||||
|
||||
### `otr_putrec`
|
||||
|
||||
An optional function you provide is called `otr_putrec(u, d, s)`. If it exists,
|
||||
it is called with the current user in `u`, the device in `d` and the payload
|
||||
(which for OwnTracks apps is JSON but for, eg Greenwich devices might not be) in the string `s`. If your function returns a
|
||||
non-zero value, the Recorder will *not* write the REC file for this publish.
|
||||
|
||||
### `otr_httpobject`
|
||||
|
||||
An optional function you provide is called `otr_httpobject(u, d, t, data)` where `u` is the username used by the client (`?u=`), `d` is the device name (`&d=` in the URI), `t` is the OwnTracks JSON `_type` and `data` a Lua table built from the OwnTracks JSON payload of `_type`. If it exists, this function is called whenever a POST is received in httpmode and the Recorder is gathering data to return to the client app. The function *must* return a Lua table containing any number of string, number, or boolean values which are converted to a JSON object and appended to the JSON array returned to the client. An [example](etc/example.lua) shows how, say, a transition event can be used to open the Featured content tab in the app.
|
||||
|
||||
### Hooklets
|
||||
|
||||
After running `otr_hook()`, the Recorder attempts to invoke a Lua function for each of the elements in the extended JSON. If, say, your Lua script contains a function called `hooklet_lat`, it will be invoked every time a `lat` is received as part of the JSON payload. Similarly with `hooklet_addr`, `hooklet_cc`, `hooklet_tst`, etc. These _hooklets_ are invoked with the same parameters as `otr_hook()`.
|
||||
|
||||
You define a hooklet function only if you're interested in expressly triggering on a particular JSON element.
|
||||
|
||||
## Views
|
||||
|
||||
A view is a sort of sandboxed look at data provided by the Recorder. Assume you host several devices, be they your own or those of some of your friends, and assume you want to allow somebody else to see where you are or have been during a specific time frame: with the Recorder's default Web server you cannot limit a visitor to see specific data only; once they reach the Recorder's Web interface, they have access to all your data. (We warned you about that earlier.) Using a HTTP proxy, you can provide an insight into certain portions of your data only.
|
||||
|
||||
Reference in New Issue
Block a user