This is a short guide to the current experimental Version of the Velobox' Websocket-API for the saddle pressure analysis.
The new Velobox WS/HTTP-server supports "applications" that work largely independent from each other on top of a "kernel". We could also talk about "application servers" but "application" is shorter. You start an application with
Although more than one client can connect to the same application, they won't work independently from each other.
The number 0 stands for the live image, 1 for the left and 2 for the right integrated image. Number 3 stands for a retrieved image. [something] denotes an optional input for "something", a|b an alternative. m...[n] is a range.
| channel{1|2}: | recording status of that channel |
| finished true|false | |
| recording_id (0 if not stored) | |
| imagespeed: | number of pressure images received during 1s1) |
| temp: | CPU temperature in degrees centigrade |
1) Questions are subdivided in an array of sections. Each section object has a code, a text for display and an array of questions (named fragen). Each question has a code (equal to the code in Velometrik®s product selection webservice), a response type (antworttyp), a text for display and, depending on the response type, an array of defaults. The respond types are:
2) Versioning follows the rule: <main>.<minor>.<revision>. A new revision contains corrections only. A new minor version is compatible with the previous minor version. A new main version may not be compatible with the previous one. The version string may have one of the following appendices (seperated by underscore '_'):
| Appendix | Meaning | Remark |
|---|---|---|
| A | Alpha | Developers current personal version |
| X<date> | eXperimental | <date>: YYYYMMDD |
| B<nr> | Beta <nr> | |
| P<nr> | Prerelease <nr> |
Recording ends with wsevent result1 or result2 rsp.
It may end with wsevent error (msg "Insufficient data")
if no pressure images have arrived during recording.
Remember that non of these values has overall meaning.
That means you can compare only values captured during the same bike fitting session
to find an improvement or a change for the worse.
The result values are:
| Key | Value |
|---|---|
| pelvisrotation | area in which the center of pressure moved during recording (details below) |
| veloscore | Velometrik®s measure of pressure distribution (explanation below) |
| front_rear (front:rear) | pressure ratio between front and rear half in % relative to whole pressure |
| left_right (left:right) | pressure ratio between left and right rear quarter in % relative to whole pressure in the rear half |
| center_left (x,y) | center of pressure inside left half |
| center_right (x,y) | center of pressure inside right half |
| center (x,y) | overall center of pressure (situated on the tie line between center_left and center_right) |
v-Secondary axis
| c1 | front | c2
-+------------------+------------------------+- Front tangent
| | |
| | |
| | |
| left | center | right
-+------------------+------------------------+- <-Principal axis
| | |
| | |
| c4 | rear | c3
-+------------------+------------------------+- Rear tangent
| | |
Left tangent Right tangent
The "veloscore" is a measure of pressure distribution. Values are from 0 to 100 where 0 means "All pressure is on a single point." and 100 means "All points have the same pressure.".
Every JSON response has the key "wsevent" which classifies the JSON message. Depending on the message class there may be more keys specific for that message class. Until now there are the following definitions:
| WSEvent | Detail keys | Notes |
|---|---|---|
| error | class | internal|client|user 2) |
| nr | error number (user errors only) | |
| source | error source | |
| msg | text message | |
| max_value | value | New pressure maximum |
| sda_live | A new live image is available.1) | |
| sda_int1 | An integrated image for the left side is available.1) | |
| sda_int2 | An integrated image for the right side is available.1) | |
| sda_int3 | A retrieved image in "session compare mode". | |
| result1 | Result for the left side. | |
| pelvisrotation | see schema above | |
| Values in cm scale=1 | ||
| veloscore | Velometriks measure of the pressure distribution | |
| Values 0...100 scale=1 | ||
| front_rear | pressure distribution between front and rear in percent | |
| Format <left>:<right> | ||
| Values 0...100 scale=0 | ||
| left_right | pressure distribution between left and right in percent | |
| Format <left>:<right> | ||
| Values 0...100 scale=0 | ||
| center | center of pressure | |
| Object with keys x, y | ||
| Values in cm scale=1 | ||
| center_left | center of pressure on left half | |
| Object with keys x, y | ||
| Values in cm scale=1 | ||
| center_right | center of pressure on right half | |
| Object with keys x, y | ||
| Values in cm scale=1 | ||
| result2 | Result for the right side. | |
| result3 | Result from a retrieved recording. | |
| pelvisrotation | (like record1) | |
| veloscore | ... | |
| ... | ||
| ttychange | change | plugged|unplugged |
| start | started reading (ok|error if plugged) | |
| type | mat type (MT_SAT*|MT_STD) | |
| driver | (used as identifier) | |
| ttystate | state | active|inactive |
| driver | (used as identifier) | |
| overload | source | where overload comes from |
| total | total number of requests | |
| rejected | number of requests rejected | |
| temp | CPU temperature | |
| freq_max | maximum CPU frequency | |
| freq_cur | current CPU frequency | |
| btevent | btevent | Bluetooth event (Detail keys see next table) |
| class | number | notes |
|---|---|---|
| internel | Error in the application server This should never happen and therefore must be reported to Velometrik | |
| client | Error in the client application This must be fixed by the client (GUI) developer. | |
| user | Handling error by client application user These errors should be reported to the application user. | |
| 1 | Insufficient data for analysis | |
| 2 | A recording started before is still running. | |
| 3 | There are unstored recording(s) that must be stored or cancelled before. | |
| 4 | There is no session. (It must be create before.) | |
| 5 | There is no recording (to store) or the recording is not finished yet. |
| BTEvent | Detail key | Class | Number | Meaning |
|---|---|---|---|---|
| disconnected | Regular disconnect | |||
| ambiguity | devices | Array with all device names | ||
| data | Data are available | |||
| error | class | disconnected | Unexpected disconnect | |
| fail | Connection fails | |||
| Pair failed | ||||
| Start notify failed | ||||
| Device not found | ||||
| No device found | ||||
| Expected device not found | ||||
| Connection timeout | ||||
| comm | Stop notify failed | |||
| client | Command/syntax errors | |||
| 1 | ||||
| 2 | disconnect while trying connect (ignored) | |||
| internal | Unexpected error, btagent restarted | |||
| msg | The error message | |||
| debug | Debug message |
The Velobox has a database for storing the results of the saddle fittings. It can be accessed by SQL. Extra commands ease the handling of images by creating JPEG images with the current JPEG setting from the stored pressure values and the mask. Together they support a reasonable workflow.
| clients | ||
|---|---|---|
| client_id | INT NOT NULL | PK |
| VARCHAR(129) | ||
| forename | VARCHAR(40) | |
| surname | VARCHAR(40) | |
| first_contact | CHAR(19) NOT NULL | YYYY-MM-DD hh:mm:ss |
| sessions | ||
|---|---|---|
| session_id | INT NOT NULL | PK |
| client_id | INT NOT NULL | FK to clients |
| date | CHAR(10) NOT NULL | |
| restart | CHAR(10) | YYYY-MM-DD |
| notes | TEXT | YYYY-MM-DD |
| recordings | ||
|---|---|---|
| recording_id | INT NOT NULL | PK |
| session_id | INT NOT NULL | FK to sessions |
| analysis | INT NOT NULL | 1 sitbones 1) 2 saddlepressure 3 anamnesis 1) |
| finished | CHAR(19) NOT NULL | YYYY-MM-DD hh:mm:ss |
| product | VARCHAR(40) | |
| product_label | VARCHAR(40) | |
| n_pressure_rows | INT | |
| n_pressure_cols | INT | |
| pressure_values | TEXT | space char separated integers |
| max_pressure | INT | |
| mask | TEXT | space char separated 0 and 1 |
| results | TEXT | JSON object |
| notes | TEXT | |
| masks | ||
|---|---|---|
| mask_id | INT NOT NULL | PK |
| name | CHAR(20) NOT NULL | alphanumerical chars only |
| standard | INT NOT NULL | 0 or 1 |
| n_rows | INT NOT NULL | |
| n_cols | INT NOT NULL | |
| mask | TEXT NOT NULL | space char separated 0 and 1 |
| nextids | ||
|---|---|---|
| table_name | VARCHAR NOT NULL | PK |
| id_name | VARCHAR NOT NULL | |
| next_id | INT NOT NULL | 1) |
| block | contains |
|---|---|
| sitbones | Result of sitbone analysis |
| (currently of visual analysis of sitbones pressure image) | |
| anamnesis | Result of anamnesis |
| (see get appquestions) | |
| x1 | 1st result set defined by client application |
| x2 | 2nd result set ... |
| ... | (numbering 1 ...) |
analysis {<blocks> [<session_id>] | <analyses>}
<blocks>: JSON-array containing the block codes for retrieve
<session_id>: ... the results belong to
(Default is the active session.)
<analyses>: JSON-object containing all the results to be stored
A series of the commands documented above apply to settings
that define the appearance of pressure images.
These settings will be stored in the Velobox when disconnecting from the application
and they will be retrieved at the next application start.
The client application developer may want to offer menu like graphical elements to the user to let him set everything according to his own flavor.
To initialize them the current settings
can be obtained using the command get appsettings.
The application responds with a wsevent "appsettings" with a settings object
as value of the key appsettings.
This object has the keys listed as "Settings" in the following table.
If a setting applies to different displays (0 live image; 1, 2 integrated images; 3 other images) there are subkeys 0...3.
| Setting | Command |
|---|---|
| maskname | set mask ... |
| compare | set compare ... |
| contrast | set jpegcontrast ... |
| bgcolor | set jpeg {0|1|2|3} bgcolor ... |
| grid | set jpeg {0|1|2|3} grid ... |
| resolution | set jpeg {0|1|2|3} resolution ... |
| frame | set jpeg {0|1|2|3} frame ... |
| jpegquality | set jpeg {0|1|2|3} quality ... |
| showmask | set jpeg {0|1|2|3} mask ... |
| imageupdates | config n_update_... |
Creating JPEG images is the most CPU power consuming part of the whole application.
Therefore you should choose your JPEG settings in a way that minimizes power consumption.
It is very easy to create an overload situation by setting 'set jpeg 0 resolution 50' for example.
You will see a delayed live image and after a few seconds an overload wsevent will arrive.
Among the additional information is the temperature. This is because the cpu slows down at high temperatures1).
If at overload the current frequency is lower than the maximum frequency a high temperature might be the reason.
It could a good idea to send a warning to your user in this case.
1)It also slows down at low load which would contradict the overload condition.
The pelvis rotation area in real life is very small. (The fitting goal is a minimized area.) Showing the shape with four splines usually only makes sense in a magnified representation.
Bluetooth connection handling is managed by only two commands, btconnect and btdisconnect. In case of an error it's sufficient to rety btconnect after giving an appropriate to the user. In case of ambiguity a menu with all choices should be offered.
An image announced by a wsevent must be either fetched by a HTTP-request or it can be ignored. The URL for fetching is
The following limitations must be eliminated until Eurobike:
The application server listens on Port 8080. In the final Version there will be an apache2-proxy listening on port 80.
There is a very simple HTML test page at http://<velobox-name>.local:8080/test/satteldruckanalyse.html.
The listing below the screenshot indicates the way how commands from the Tk-Application can be implemented with the Velobox API. The table following shows where to place the individual results.
| Label | Value in result object |
|---|---|
| Veloscore | result.veloscore |
| Rotation | result.pelvisrotation.width : result.pelvisrotation.height |
| Front:Rear | result.front_rear |
| Left:Right | result.left_right |