============ API v2.0 ============ .. based on https://github.com/Geonovum/smartemission/blob/master/docs/specs/rawsensor-api/rawsensor-api.txt .. warning:: Not all sensors/project may provide all measurands that are documented here. That depends on hardware capabilities and project configuration. The base url is: https://josene.intemo.com/ API methods =========== List devices ------------ .. http:get:: /sensors/v2.0/devices Get a list of devices that are available **Example request**: .. sourcecode:: http GET /sensors/v2.0/devices HTTP/1.1 Host: josene.intemo.com Authorization: Bearer yEUqAXfH06WPr81IKU1X **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 { "devices": [ "/sensors/v2.0/devices/14561", "/sensors/v2.0/devices/14564", "/sensors/v2.0/devices/15300" ] } **Example request**: .. sourcecode:: http GET /sensors/v2.0/devices?user_field__contains=Amsterdam&type=main HTTP/1.1 Host: josene.intemo.com Authorization: Bearer yEUqAXfH06WPr81IKU1X **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 { "devices": [ "/sensors/v2.0/devices/14561" ] } :status 200: OK :query user_field: Show only sensors that have this user_field (case insensitive) :query user_field__contains: Show only sensors which user_field contain this value (case insensitive) :query hardware_id: Show only sensors that have this hardware_id (case insensitive) :query type: [main, sub, all] Show only sensors which are a main or sub board. defaults to all :status 403: Authorization error .. _meta: Get metadata ------------ .. http:get:: /sensors/v2.0/devices/(uint32:sensor_id) Get meta data list for a specific sensor `sensor_id` **Example request**: .. sourcecode:: http GET /sensors/v2.0/devices/14561 HTTP/1.1 Host: josene.intemo.com Authorization: Bearer yEUqAXfH06WPr81IKU1X **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 { "id": "14561", "hardware": { "id": "0004A30B00012AD0", "sensors" : [{"measurand": "NH3 Concentration", "type": "Gas, Calyx, N100 Ammonia , NH3" }], }, "last": "/sensors/v2.0/devices/14561/last", "subs": [14562, 14563], "main": 14660, "location": "gps", "outputs": [ { "name": "battery_current.mA" }, { "name": "battery_gauge.mCoulomb" }, { " snipped..."}, ], "user_field": "My fancy name", "serial_number": "22090019", "timeseries": "/sensors/v2.0/devices/14561/timeseries" } :param sensor_id: id of device :status 200: OK :status 404: `sensor_id` not found :status 403: Authorization error :resjson id: `sensor_id` of the sensor :resjson object hardware: Hardware details of the sensor :resjson hardware_id: Hardware id (hex format) :resjson hardware_sensors: List of sensor info (Informative only, format may change) :resjson main: `sensor_id` of the corresponding main sensor (if any) :resjson subs: sensor_ids of the corresponding sub sensors (if any) :resjson location: "gps" location is read from gps in sensor, "fixed" location is fixed. (only available on the main sensor) :resjson user_field: Custom field writable by api user. Useful for naming, cross-referencing or grouping (string, max length = 50) :resjson serial_number: Intemo serial number .. TODO:: more documentation Multiple sensor devices can be placed in the same physical sensor. In that case you have one main sensor, and one or more sub-sensors. Every sensor is visible in the api with its own `sensor_id` and the topology can be derived from the `main` and `subs` fields in the response. Update metadata --------------- .. http:post:: /sensors/v2.0/devices/(uint32:sensor_id) Update meta data fields list for a specific sensor `sensor_id` **Example request**: .. sourcecode:: http POST /sensors/v2.0/devices/14561 HTTP/1.1 Host: josene.intemo.com Authorization: Bearer yEUqAXfH06WPr81IKU1X { "user_field": "My fancy name" } **Example response**: .. sourcecode:: http HTTP/1.1 201 CREATED Content-Type: application/json; charset=utf-8 :param sensor_id: id of device :status 201: OK :status 404: `sensor_id` not found :status 400: Invalid parameter or invalid value :status 403: Authorization error :jsonparam string user_field: Update user_field :jsonparam string serial_number: Update serial_number :jsonparam int hardware_type: Hardware type (EG: 22000) :jsonparam string hardware_revision: Hardware rev (Eg: "A03") :jsonparam string firmware_version: Firmware version (Eg: "1.0.4") Pass an empty value ("") to erase a field. .. note:: You can only update the fields documented here. the other fields are not writable via the API. .. note:: Not all api keys have write access enabled. If you POST metadata with an apikey that has write access not enabled you get a 403 with an informative body eg: "token has no write access" .. note:: serial_number, hardware_type, hardware_revision, firmware_version are Intemo internal apis. These require special permission. If you try to update these fields with an ApiKey without those permissions you get a 403. Create Sensor ------------- .. http:post:: /sensors/v2.0/devices Create a new sensor in the database. **Example request**: .. sourcecode:: http POST /sensors/v2.0/devices/ HTTP/1.1 Host: josene.intemo.com Authorization: Bearer yEUqAXfH06WPr81IKU1X { "hardware": {"id": "0004A30B00012AD0"}, "user_field": "My fancy name" "project_id": 2, "serial_number": "22090019", } **Example response**: .. sourcecode:: http HTTP/1.1 201 CREATED Content-Type: application/json; charset=utf-8 { "id": "14561" } :param sensor_id: id of device :status 201: OK :status 400: Invalid parameter or invalid value :status 403: Authorization error :status 409: Object already existed (hardware id is already known) :jsonparam string hardware.id: unique hardware identifier :jsonparam string user_field: user_field :jsonparam string serial_number: serial_number :jsonparam int hardware_type: Hardware type (EG: 22000) :jsonparam string hardware_revision: Hardware rev (Eg: "A03") :jsonparam string firmware_version: Firmware version (Eg: "1.0.4") :jsonparam string project_id: Project id (sensor gets initially assigned to this project) :>json string id: Resulting `sensor_id` of created object .. note:: This is an Intemo internal API. Not all api keys have access to this method. If your api key does not have the correct permissions, you get a 403 with an informative body. Days ---- .. http:get:: /sensors/v2.0/devices/(uint32:sensor_id)/timeseries Get the available days of timeseries for a specific sensor `sensor_id`. **Example request**: .. sourcecode:: http GET /sensors/v2.0/devices/14561/timeseries HTTP/1.1 Host: josene.intemo.com Authorization: Bearer yEUqAXfH06WPr81IKU1X **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 { "days": [ "/sensors/v2.0/devices/14561/timeseries/20171207", "/sensors/v2.0/devices/14561/timeseries/20171208", "/sensors/v2.0/devices/14561/timeseries/20171215", "/sensors/v2.0/devices/14561/timeseries/20171216", "/sensors/v2.0/devices/14561/timeseries/20171217" ], "id": "14561" } :param sensor_id: id of device :status 200: OK :status 404: `sensor_id` not found :status 403: Authorization error Hours ----- .. http:get:: /sensors/v2.0/devices/(uint32:sensor_id)/timeseries/(int:date) Get the available days of timeseries for a specific sensor `sensor_id`. **Example request**: .. sourcecode:: http GET /sensors/v2.0/devices/14561/timeseries/20171208 HTTP/1.1 Host: josene.intemo.com Authorization: Bearer yEUqAXfH06WPr81IKU1X **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 { "date": "2017/12/08", "hours": [ 9, 10, 11, 12, 13, 14 ], "id": "14561" } :param sensor_id: id of device :param date: YYYYMMDD encoded date :status 200: OK :status 404: `sensor_id` not found :status 403: Authorization error .. note:: * Date/Time is in UTC * The hour number ranges from 1 to 24; 1 means from 0:00:00 until 0:59:59 * The date should include zero padding, so 1 january 2018 should be encoded as 2018010 Get data -------- .. http:get:: /sensors/v2.0/devices/(uint32:sensor_id)/timeseries/(int:date)/(int:hour) Get all sensor data in time window `date` and `hour` for sensor `sensor_id`. **Example request**: .. sourcecode:: http GET /sensors/v2.0/devices/14561/timeseries/20171208/9 HTTP/1.1 Host: josene.intemo.com Authorization: Bearer yEUqAXfH06WPr81IKU1X **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 { "date": "2017/12/08", "hour": 9, "id": "14561", "timeseries": [ { "accelero_z.g": 1.07421875, "max_audio_125Hz.dbA": 30, "max_audio_630Hz.dbA": 26, "mom_audio_2_5kHz.dbA": 25, "max_audio_total.dbA": 48, "time": "2017-12-08T08:22:53.972Z" }, { " snipped ..." }, { " snipped ..." } ] } :param sensor_id: id of device :query measurands: (Optional) comma separated list of measurands you want to see. (defaults to show all) :param date: YYYYMMDD encoded date :param hour: hour :status 200: OK :status 404: `sensor_id` not found :status 403: Authorization error In `timeseries` a number of measurands is given. In `timeseries` you find a list of measurements. Each measurements contains a set of measurands on a single `time`. The unit of the measurand is encoded in the measurand name. See :ref:`data-format` for details on the unit abbreviations .. NOTE:: * Date/Time is in UTC * The hour number ranges from 1 to 24; 1 means from 0:00:00 until 0:59:59 * The date should include zero padding, so 1 Januari 2018 should be encoded as 2018010 .. _last_data: Get last data ------------- .. http:get:: /sensors/v2.0/devices/(uint32:sensor_id)/last Get the last sensor data of sensor `sensor_id` **Example request**: .. sourcecode:: http GET /sensors/v2.0/devices/14561/last HTTP/1.1 Host: josene.intemo.com Authorization: Bearer yEUqAXfH06WPr81IKU1X **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 { "id": "14561", "accelero_z.g": 1.07421875, "max_audio_125Hz.dbA": 30, "max_audio_630Hz.dbA": 26, "mom_audio_2_5kHz.dbA": 25, "max_audio_total.dbA": 48, " snipped ...", " snipped ..." "time": "2018-01-11T08:40:51.521Z" } :param sensor_id: id of device :query measurands: (Optional) comma separated list of measurands you want to see. (leaving out defaults to show all) :status 200: OK :status 404: `sensor_id` not found :status 403: Authorization error The reply contains a number of measurands. See :ref:`data-format` for details how to interpret that unit. Get last data (multiple) ------------------------ .. http:get:: /sensors/v2.0/devices/last/(comma_separated:sensor_ids) Get the last sensor data of a series of sensors. This api is similar to :ref:`last_data` but queries multiple sensors in a single request. This api should be used when querying every sensor individually takes much overhead/latency. **Example request**: .. sourcecode:: http GET /sensors/v2.0/devices/last/14561,14562 HTTP/1.1 Host: josene.intemo.com Authorization: Bearer yEUqAXfH06WPr81IKU1X **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 [ { "id": "14561", "max_audio_100Hz.dbA": 30, " snipped ...", " snipped ..." "time": "2018-01-11T08:40:51.521Z" }, { "id": "14562", "max_audio_100Hz.dbA": 32, " snipped ...", " snipped ..." "time": "2018-01-11T08:41:50.123Z" } ] :param sensor_ids: comma separated list of sensor ids :query measurands: (Optional) comma separated list of measurands you want to see. (leaving out defaults to show all) :status 200: OK. If not all sensors in `sensor_ids` could be found, we return a 200 with the sensors that do exist. :status 404: None of the sensors in `sensor_ids` could be found. :status 403: Authorization error The reply contains a number of measurands. See :ref:`meta` what the unit is, and see :ref:`data-format` for details how to interpret that unit. .. _data-format: Data format =========== This chapter describes how to interpret the units of the measurands. .. warning:: This chapter is not complete. Some of the units are self explanatory: eg "milliKelvin", "milliAmpere", "milliCoulomb". The ones that are not self explanatory are described in in the table below. .. TODO:: check these .. csv-table:: measurand unit conversion :header: unit, description,conversion,example ``degrees``, degrees latitude, longitude ``mdegrees``, milli degrees (angle) ``mV``, milli Volt ``mA``, milli Ampere ``nV``, nano Volt ``mCoulomb``, milli Coulomb ``mK``, milli Kelvin ``dbA``, dB(A) sound pressure ``ppb``, parts per billion,, 498000 is 498 ppm ``s``, seconds ``lx``, lux ``Pa``, Pascal ``g``, g-force 9.81 m/s^2 ``m``, meter ``ugm3``, micro gram per cubic meter ``ngm3``, nano gram per cubic meter ``html``, # html color code eg: 0x808000 = #808000 = olive ``Ohm``, Ohm ``ms``, m/s meter per second (speed) ``mms``, mm/s milli-meter per second (speed) ``uls``, micro liter per second ``milli``, milli ``percent``, relative humidity in % ``K``, Kelvin ``binary``, , for internal use only, wind direction -------------- `Wind direction `_ is reported by the direction from which is originates where 0 degrees is north, 180 is south. .. csv-table:: wind direction :header: degrees,origin, meaning 0, north, wind blowing from north to south 90, east, wind blowing from east to west 180, south, wind blowing from south to north 270, west, wind blowing from west to east. .. _audio-format: audio format ------------ Audio measurements return four types measurements: 1. average in sample interval 2. minimum values in sample interval 3. maximum values in sample interval 4. momentary level (single measurement) A sample interval is typically 10s. Audio levels are send in dB(A), where 0 dB(A) is the lowest, and 127 dB(A) is the highest possible value. The four types of measurements are distinguished by the prefix in the measurands in the api. .. csv-table:: audio types :header: type,prefix,example average data, `avg_audio_` , `avg_audio_25Hz.dbA` minumum data, `min_audio_`, `min_audio_31_5Hz.dbA` maximum data, `max_audio_`, `max_audio_31_5Hz.dbA` momentary data, `mom_audio_` , `mom_audio_125Hz.dbA` The following table lists all the frequency sub-bands the sensors measure. Each of the audio types above, have the bands below. .. csv-table:: audio bands :header: measurand, Freq ``avg_audio_25Hz``, 25 Hz ``avg_audio_31_5Hz``, 31.5 Hz ``avg_audio_40Hz``, 40 Hz ``avg_audio_50Hz``, 50 Hz ``avg_audio_63Hz``, 63 Hz ``avg_audio_80Hz``, 80 Hz ``avg_audio_100Hz``, 100 Hz ``avg_audio_125Hz``, 125 Hz ``avg_audio_160Hz``, 160 Hz ``avg_audio_200Hz``, 200 Hz ``avg_audio_250Hz``, 250 Hz ``avg_audio_315Hz``, 315 Hz ``avg_audio_400Hz``, 400 Hz ``avg_audio_500Hz``, 500 Hz ``avg_audio_630Hz``, 630 Hz ``avg_audio_800Hz``, 800 Hz ``avg_audio_1kHz``, 1 kHz ``avg_audio_1_25kHz``, 1.25 kHz ``avg_audio_1_6kHz``, 1.6 kHz ``avg_audio_2kHz``, 2 kHz ``avg_audio_2_5kHz``, 2.5 kHz ``avg_audio_3_15kHz``, 3.15 kHz ``avg_audio_3_15kHz``, 4 kHz ``avg_audio_5kHz``, 5 kHz ``avg_audio_6_3kHz``, 6.3 kHz ``avg_audio_8kHz``, 8 kHz ``avg_audio_10kHz``, 10 kHz ``avg_audio_12_5kHz``, 12.5 kHz ``avg_audio_16kHz``, 16 kHz ``avg_audio_20kHz``, 20 kHz ``avg_audio_total``, sum of bands Total audio ~~~~~~~~~~~ The sensors measure the audio in 1/3 octave bands. Besides these sub-bands measurands the api exports the 'total' audio pressure. This `total` value is not directly measued but calculated by adding the sub-band data. .. csv-table:: total audio types :header: type,measurand average data, `total_avg_audio.dbA` minumum data, `total_min_audio.dbA` maximum data, `total_max_audio.dbA` momentary data, `total_mom_audio.dbA` NB: The total audio values are not plain additions, but rather additions taking into account the logarithmic scales of the dB(A) values. The following code example shows how the total audio fields are calculated. .. code-block:: python import numpy as np def db_sum(levels): """Add audio levels This is what smartemission does too: https://github.com/smartemission/ further references: http://www.sengpielaudio.com/calculator-spl.htm :param levels: list of levels (dB). :type levels: list :return: sum of audio levels :rtype: float >>> '%.1f' % db_sum([80]) '80.0' >>> '%.2f' % db_sum([80, 80, 80]) '84.77' >>> '%.2f' % db_sum([80] * 30) '94.77' >>> '%.2f' % db_sum([0] * 30) '0.00' """ levels = np.asanyarray(levels) total = 10.0 * np.log10((10.0 ** (levels / 10.0)).sum()) # Adding 30 zeroes, end up with a dB(A) of 15 # if that is the case just round down to zero again, that is much clearer if total <= 15: total = 0 return total Color temperature ----------------- The api may provide a measurand ``color_temperature.K``. This is not a directly measured value but rather a calculated value based on a measured RGB value (``rgb_color.html``). We use the algorithm as proposed by `Javier Hernandez-Andre`__ to calculate the temperature, using the library colour_. .. _Hernandez: https://www.usna.edu/Users/oceano/raylee/papers/RLee_AO_CCTpaper.pdf __ Hernandez_ .. _colour: https://colour.readthedocs.io/en/develop/generated/colour.xy_to_CCT.html .. warning:: This algorithm may have unexpected results for some RGB values. Even negative values for `color_temperature.K` may be reported. .. TODO:: Add chapter that describes the measurands