document proposed API for updating signals (#28)

This commit is contained in:
Scott Lamb 2019-06-07 10:19:38 -07:00
parent 6f2c63ffac
commit d232ca55fa

View File

@ -24,10 +24,10 @@ input such as a burglar alarm system's zone status.
All requests for JSON data should be sent with the header
`Accept: application/json` (exactly).
### `/api/login`
### `POST /api/login`
A `POST` request on this URL should have an `application/x-www-form-urlencoded`
body containing `username` and `password` parameters.
The request should have an `application/x-www-form-urlencoded` body containing
`username` and `password` parameters.
On successful authentication, the server will return an HTTP 204 (no content)
with a `Set-Cookie` header for the `s` cookie, which is an opaque, HttpOnly
@ -37,19 +37,19 @@ If authentication or authorization fails, the server will return a HTTP 403
(forbidden) response. Currently the body will be a `text/plain` error message;
future versions will likely be more sophisticated.
### `/api/logout`
### `POST /api/logout`
A `POST` request on this URL should have an `application/x-www-form-urlencoded`
body containing a `csrf` parameter copied from the `session.csrf` of the
The request should have an `application/x-www-form-urlencoded` body containing
a `csrf` parameter copied from the `session.csrf` of the
top-level API request.
On success, returns an HTTP 204 (no content) responses. On failure, returns a
4xx response with `text/plain` error message.
### `/api/`
### `GET /api/`
A `GET` request on this URL returns basic information about the server,
including all cameras. Valid request parameters:
Returns basic information about the server, including all cameras. Valid
request parameters:
* `days`: a boolean indicating if the days parameter described below
should be included.
@ -101,6 +101,7 @@ The `application/json` response will have a dict as follows:
`direct` or `indirect`. See `db/schema.sql` for more description.
* `type`: a UUID, expected to match one of `signalTypes`.
* `days`: as in `cameras.streams.days` above.
**status: unimplemented**
* `signalTypes`: a list of all known signal types.
* `uuid`: in text format.
* `states`: a map of all possible states of the enumeration to more
@ -190,9 +191,9 @@ Example response:
}
```
### `/api/cameras/<uuid>/`
### `GET /api/cameras/<uuid>/`
A GET returns information for the camera with the given URL. The information
Returns information for the camera with the given URL.
Example response:
@ -224,9 +225,9 @@ Example response:
}
```
### `/api/cameras/<uuid>/<stream>/recordings`
### `GET /api/cameras/<uuid>/<stream>/recordings`
A GET returns information about recordings, in descending order.
Returns information about recordings, in descending order.
Valid request parameters:
@ -308,11 +309,11 @@ Example response:
}
```
### `/api/cameras/<uuid>/<stream>/view.mp4`
### `GET /api/cameras/<uuid>/<stream>/view.mp4`
A GET returns a `.mp4` file, with an etag and support for range requests. The
MIME type will be `video/mp4`, with a `codecs` parameter as specified in [RFC
6381][rfc-6381].
Returns a `.mp4` file, with an etag and support for range requests. The MIME
type will be `video/mp4`, with a `codecs` parameter as specified in
[RFC 6381][rfc-6381].
Expected query parameters:
@ -356,14 +357,14 @@ Example request URI to retrieve recording id 1, skipping its first 26
TODO: error behavior on missing segment. It should be a 404, likely with an
`application/json` body describing what portion if any (still) exists.
### `/api/cameras/<uuid>/<stream>/view.mp4.txt`
### `GET /api/cameras/<uuid>/<stream>/view.mp4.txt`
A GET returns a `text/plain` debugging string for the `.mp4` generated by the
Returns a `text/plain` debugging string for the `.mp4` generated by the
same URL minus the `.txt` suffix.
### `/api/cameras/<uuid>/<stream>/view.m4s`
### `GET /api/cameras/<uuid>/<stream>/view.m4s`
A GET returns a `.mp4` suitable for use as a [HTML5 Media Source Extensions
Returns a `.mp4` suitable for use as a [HTML5 Media Source Extensions
media segment][media-segment]. The MIME type will be `video/mp4`, with a
`codecs` parameter as specified in [RFC 6381][rfc-6381].
@ -387,16 +388,16 @@ recording segment for several reasons:
than one video sample entry, so a `.m4s` that uses more than one video
sample entry can't be used.
### `/api/cameras/<uuid>/<stream>/view.m4s.txt`
### `GET /api/cameras/<uuid>/<stream>/view.m4s.txt`
A GET returns a `text/plain` debugging string for the `.mp4` generated by the
same URL minus the `.txt` suffix.
Returns a `text/plain` debugging string for the `.mp4` generated by the same
URL minus the `.txt` suffix.
### `/api/cameras/<uuid>/<stream>/live.m4s`
### `GET /api/cameras/<uuid>/<stream>/live.m4s`
A GET returns a `multipart/mixed` sequence of parts. An extra top-level
header, `X-Open-Id`, contains the `openId` which is assigned to all recordings
in this live stream.
Returns a `multipart/mixed` sequence of parts. An extra top-level header,
`X-Open-Id`, contains the `openId` which is assigned to all recordings in this
live stream.
Each part is a `.mp4` media segment that starts with a key frame and contains
all other frames which depend on that key frame. The following part headers
@ -463,21 +464,21 @@ following URLs, respectively:
* `/api/cameras/fd20f7a2-9d69-4cb3-94ed-d51a20c3edfe/main/view.m4s?s=5681@42.0-180002`
* `/api/cameras/fd20f7a2-9d69-4cb3-94ed-d51a20c3edfe/main/view.m4s?s=5681@42.180002-360004`
### `/api/init/<sha1>.mp4`
### `GET /api/init/<sha1>.mp4`
A GET returns a `.mp4` suitable for use as a [HTML5 Media Source Extensions
Returns a `.mp4` suitable for use as a [HTML5 Media Source Extensions
initialization segment][init-segment]. The MIME type will be `video/mp4`, with
a `codecs` parameter as specified in [RFC 6381][rfc-6381].
### `/api/init/<sha1>.mp4.txt`
### `GET /api/init/<sha1>.mp4.txt`
A GET returns a `text/plain` debugging string for the `.mp4` generated by the
Returns a `text/plain` debugging string for the `.mp4` generated by the
same URL minus the `.txt` suffix.
### `/api/signals`
### `GET /api/signals`
A GET returns an `application/json` response with state of every signal for
the requested timespan.
Returns an `application/json` response with state of every signal for the
requested timespan.
Valid request parameters:
@ -522,6 +523,130 @@ This represents the following observations:
2. signal 1 entered state 2 (`on`) at time 130985424000000.
3. signal 1 entered state 1 (`off`) at time 130985418600000.
### `POST /api/signals`
**status: unimplemented**
Alters the state of a signal.
Signal state can be broken into two parts: observed history and predicted
future. Observed history is written to the database on next flush.
Predicted future is only retained in RAM and returned on `GET` requests on the
near future. This avoids having to display the "unknown" state when it's very
likely that the state has not changed since the most recent update.
A typical request will add observed history from the time of a recent previous
prediction until now, and add another prediction. Following `GET /api/signals`
requests will return the new prediction until a pre-determined expiration
time. The client typically will send a following request before this
expiration time so that history is recorded and the UI never displays
`unknown` when the signal is being actively managed.
Some requests may instead backfill earlier history, such as when a video
analytics client starts up and analyzes all video segments recorded since it
last ran. These will specify beginning and end times for the observed history
and not make a prediction.
The request should have an `application/json` body describing the change to
make. It should be a dict with these attributes:
* `signalIds`: a list of signal ids to change.
* `observedStates`: (optional) a list (one entry per `signalIds` entry) of
observed states to set.
* `predictedStates`: (optional) a list (one entry per `signalIds` entry)
of predictions to make. If absent, assumed to match `observedStates`.
Only used if `predictedDur90k` is non-zero.
* `observedStartTime90k` (optional): if absent, assumed to be now. Otherwise
is typically a time from an earlier response.
* `observedEndTime90k` (optional): if absent, assumed to be now.
* `predictionDur90k` (optional): (only allowed when `endTime90k` is absent)
additional time in which the current state should seem to "linger" if no
further updates are received. a `GET /api/signals` request until this time
will reflect the curent
between the time this request
The response will be an `application/json` body dict with the following
attributes:
* `time90k`: the current time. When the request's `observedStartTime90k`
and/or `observedEndTime90k` were absent, this is needed to later upgrade
predictions to history seamlessly.
Example request sequence:
#### Request 1
The client responsible for reporting live driveway motion has just started. It
observes motion now. It records no history and predicts there will be motion
for the next minute.
Request:
```json
{
'signalIds': [1],
'predictedStates': [2],
'predictionDur90k': 5400000
}
```
Response:
```json
{
'time90k': 140067468000000
}
```
#### Request 2
30 seconds later (half the prediction interval), the client still observes
motion. It records the previous prediction and predicts the motion will continue.
Request:
```json
{
'signalIds': [1],
'observedStates': [2],
'observedStartTime90k': 140067468000000,
'predictionDur90k': 5400000
}
```
Response:
```json
{
'time90k': 140067470700000
}
```
### Request 3
5 seconds later, the client observes motion has ended. It records the history
and predicts no more motion.
Request:
```json
{
'signalIds': [1],
'observedStates': [2],
'predictedStates': [1],
'observedStartTime90k': 140067470700000,
'predictionDur90k': 5400000
}
```
Response:
```json
{
'time90k': 140067471150000
}
```
[media-segment]: https://w3c.github.io/media-source/isobmff-byte-stream-format.html#iso-media-segments
[init-segment]: https://w3c.github.io/media-source/isobmff-byte-stream-format.html#iso-init-segments
[rfc-6381]: https://tools.ietf.org/html/rfc6381