Skip to content

openradiation/openradiation-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OpenRadiation

Abstract

This project aims to develop a database to store environmental radioactivity measurements. It's shared in 2 parts :

  • backend : the postgresql backend database
  • api : a JSON Rest-like API developed in node.js to request the database

Source code is under licence Apache 2.0 (cf https://www.openradiation.org/fr/conditions-dutilisation#licence_apache2)

First at all, to use the API you need a key. Please ask by sending an email to [email protected] For only a few tests, you're allowed to use the following key : bde8ebc61cb089b8cc997dd7a0d0a434

By using this API, you accept the terms of use : https://www.openradiation.org/conditions-dutilisation

This project is self sufficient, but it is designed to work with the openradiation.org website. There is restricted access for this website to give informations about users and qualifications. The API is designed to be installed in two parts : the submit api and the request api.

Structure of the data

API NameTypeAvailable for request APIAvailable for submit APIDescription
apparatusIdStringUnique sensor identifier
apparatusVersionString Sensor firmware version
apparatusSensorTypeString Sensor type : geiger, photodiode
apparatusTubeTypeString Tube identification (only if apparatusSensorType = geiger)
temperatureIntegerTemperature (°C)
valueReal*MandatoryDose rate (µSv/h)
hitsNumberIntegerCounts measured during the whole measurement period. cps (counts per second) used to evaluate dose rate with the calibration function will be : cps = hitsNumber / (endTime - startTime)
calibrationFunctionStringCalibration function used to calculate µSv/h from cps (counts per second). Format should be inline with these symbols : cps 0-9. -+/*^() max,. Example : 7.543*(cps-0.02)^2+0.001*(cps-0.02)
startTimeTimestamp*MandatoryDate of the beginning of the measurement (ISO GMT)
endTimeTimestamp Date of the end of the measurement (ISO GMT)
latitudeReal*Mandatorylatitude
longitudeReal*Mandatorylongitude
accuracyReal Position accuracy in meters
altitudeInteger Altitude above sea in meters
altitudeAccuracyReal Altitude accuracy in meters
endLatitudeReallatitude at the end of the measurement
endLongitudeReallongitude at the end of the measurement
endAccuracyRealPosition accuracy in meters at the end of the measurement
endAltitudeIntegerAltitude above sea in meters at the end of the measurement
endAltitudeAccuracyRealAltitude accuracy in meters at the end of the measurement
deviceUuidString Smartphone device UUID (see http://plugins.cordova.io/#/package/org.apache.cordova.device)
devicePlatformString Smartphone device platform
deviceVersionString Smartphone device OS version
deviceModelString Smartphone device model
reportUuidString*MandatoryUnique measurement UUID (UUIDv4 format) client-side generated
manualReportingBooleanManual Reporting : true, false (default:true). False if the data is not entered by a human being
organisationReportingStringSoftware version (sample:openradiation_v1)
reportContextStringNeverReport context : emergency, routine, exercise, test (default:test). test:data are not registrated but you can test api use, emergency and exercise:not used,routine:you should use this one !
descriptionStringFree description (only if userId is specified)
measurementHeightIntegerMeasurement height above the ground (in meters). It is measurement height from the ground (and not altitude above sea level).
tagsJson array of stringFree tags list [tag1 ; tag2] (only if userId is specified)
enclosedObjectStringBase64 encoded Image. The size shoudn't exceeded 1mb and format should be closed from 600*800 pixels (width * height). The value should be a data URI scheme 'data:image/;base64,'. (only if userId is specified)
userIdStringOpenradiation.org user id
userPwdStringNeverOpenradiation.org plain text password (mandatory if userId is specified)
measurementEnvironmentStringMeasurement environment : countryside, city, ontheroad, inside, plane (if plane, qualification is set to plane)
rainBooleanRain : true if it rains during the measurement
flightNumberStringif measurementEnvironment is plane, flightNumber of the commercial flight in capital letters (AITA code followed by number, example: AF179)
seatNumberStringif measurementEnvironment is plane, seatNumber in capital letters with row number first (example: 14C)
windowSeatBooleanif measurementEnvironment is plane, windowSeat : true if the seat where is the sensor is next to the window
stormBooleanStorm : true if storm crossing during the measurement
flightIdIntegerNo, determinated by the APIif measurementEnvironment is plane and flightNumber setted, measurement is associated to a flightId (flightId permits to retrieve all measurements in a same flight)
refinedLatitudeRealNo, determinated by the APIif measurementEnvironment is plane and flightNumber recognize, latitude is refined with the track of the plane
refinedLongitudeRealNo, determinated by the APIif measurementEnvironment is plane and flightNumber recognize, longitude is refined with the track of the plane
refinedAltitudeIntegerNo, determinated by the APIif measurementEnvironment is plane and flightNumber recognize, altitude is refined with the track of the plane
refinedEndLatitudeRealNo, determinated by the APIif measurementEnvironment is plane and flightNumber recognize, endLatitude is refined with the track of the plane
refinedEndLongitudeRealNo, determinated by the APIif measurementEnvironment is plane and flightNumber recognize, endLongitude is refined with the track of the plane
refinedEndAltitudeIntegerNo, determinated by the APIif measurementEnvironment is plane and flightNumber recognize, endAltitude is refined with the track of the plane
departureTimeTimestampNo, determinated by the APIif measurementEnvironment is plane and flightNumber recognize, actual departure time of the plane
arrivalTimeTimestampNo, determinated by the APIif measurementEnvironment is plane and flightNumber recognize, actual arrival time of the plane
airportOriginStringNo, determinated by the APIif measurementEnvironment is plane and flightNumber recognize, airport origin (AITA) of the plane
airportDestinationStringNo, determinated by the APIif measurementEnvironment is plane and flightNumber recognize, airport destination (AITA) of the plane
aircraftTypeStringNo, determinated by the APIif measurementEnvironment is plane and flightNumber recognize, aircraft type of the plane
firstLatitudeRealNo, determinated by the APIif measurementEnvironment is plane and flightNumber setted, latitude of the first measurement or latitude of the origin airport
firstLongitudeRealNo, determinated by the APIif measurementEnvironment is plane and flightNumber setted, longitude of the first measurement or longitude of the origin airport
midLatitudeRealNo, determinated by the APIif measurementEnvironment is plane and flightNumber setted, latitude picked up from a measurement or in the middle of the plane track
midLongitudeRealNo, determinated by the APIif measurementEnvironment is plane and flightNumber setted, longitude picked up from a measurement or in the middle of the plane track
lastLatitudeRealNo, determinated by the APIif measurementEnvironment is plane and flightNumber setted, latitude of the last measurement or latitude of the destination airport
lastLongitudeRealNo, determinated by the APIif measurementEnvironment is plane and flightNumber setted, longitude of the last measurement or longitude of the destination airport
dateAndTimeOfCreationTimestampNo, but always determinated by the APIDate of registration in the database
qualificationString*No, determinated by the API or the websiteplane, wrongmeasurement, temporarysource, groundlevel
qualificationVotesNumberIntegerNo, determinated by the API or the websitequalification Votes Number
reliabilityIntegerNo, but always determinated by the API and never modifiedEstimated reliability that the measurement is correct. Calculated when submitted to the API as following : +1 for each filled field, + min(30,HitsNumber) if HitsNumber not null, +10 if userId not null, +20 if ManualReporting=false, +20 if MeasurementEnvironment=countryside / +10 if MeasurementEnvironment=city or ontheroad, +10 if MeasurementHeight=1. Expecting > 78 (if not qualification is set to mustbeverified and qualificationVotesNumber is set to 0)
atypicalBoolean*No, but always determinated by the API and never modifiedatypical if value is not representative of an environnemental measure. No if value < 0.2 (but we should compare value to an estimated local reference ...), yes otherwise

Anatomy of the OpenRadiation API

Error codes & responses

The OpenRadiation API attempts to return appropriate HTTP status codes for ever request

HTTP status codeTextDescription
200OKAPI requested with success, the API will return a JSON object described as below
201CreatedAPI submitted with success and ressource created
400Bad RequestThe request is invalid. An error message is returned (described as below)
401UnauthorizedapiKey is incorrect. An error message is returned (described as below)
403ForbiddenThe request is understood, but it has been refused. An error message is returned (described as below)
404Not FoundThe URI requested is invalid
413Request Entity Too LargeThe request entity is too large
500Internal Server ErrorSomething is broken. You can send an mail to [email protected] so that we can investigate

Error message response will look like :

{
    "error": {
        "code": "`An application-specific error code, expressed as a string value`",
        "message": "`A short, human-readable summary of the problem`"
    }
}

Requesting the API

The endpoint for request API is https://request.openradiation.net/

By default, all requests will be limited to the 400 last measurements within the criterias (considering startTime). This max number is in the response group and defined in the properties file.

General fields in the query strings :

  • response=complete : render all fields and not only stared fields (see "Available for request API" column above), available for all requests.
  • withEnclosedObject=no : the enclosedObject will not be in the response group (due to length spare considerations), available for all requests.
  • maxNumber=maxNumber : limit the number of measurements in the response to maxNumber instead of default, only available for bulk requests. This number cannot be upper than the default maxNumber limit.

Simple request

To get a unique measurement having the reportUuid (reportUuid should already exist in the database):

GET /measurements/`reportUuid`?apiKey=`apiKey`   
GET /measurements/`reportUuid`?apiKey=`apiKey`&response=complete
GET /measurements/`reportUuid`?apiKey=`apiKey`&response=complete&withEnclosedObject=no

Response will look like :

{
    "data": {
        "reportUuid": "`reportUuid`",
        "latitude": `latitude`,
        "longitude": `longitude`,
        "value": `value`,
        "startTime": "`startTime`",
        "qualification": "`qualification`",
        "atypical": `atypical`  
    }
}

Bulk requests

To get a multiple measurements with combined complex criterias :

  • with min/max bounds : value, startTime, latitude, longitude (sample : minValue/maxValue)
  • with an unique criteria : userId, qualification, tag, atypical, flightId, dateOfCreation

for flightId and dateOfCreation criterias there is no default maxNumber limit

All these criterias can be combined :

GET /measurements?apiKey=`apiKey`
GET /measurements?apiKey=`apiKey`&minValue=`value`&userId=`userId`&minstartTime=`startTime`&tag=`tag`&response=complete&maxNumber=`maxNumber`&withEnclosedObject=no
GET /measurements?apiKey=`apiKey`&minStartTime=`startTime`&maxStartTime=`startTime`&qualification=`qualification`
GET /measurements?apiKey=`apiKey`&dateOfCreation=`date`
GET /measurements?apiKey=`apiKey`&dateOfCreation=`date`&withEnclosedObject=no&maxNumber=`maxNumber`

Sample : to get the last measurements all over the world

https://request.openradiation.net/measurements?apiKey=bde8ebc61cb089b8cc997dd7a0d0a434

Response will look like :

{
    "maxNumber":`maxNumber`,
    "data": [
        {
            "reportUuid": "`reportUuid`",
            "latitude": `latitude`,
            "longitude": `longitude`,
            "value": `value`,
            "startTime": "`startTime`",
            "qualification": "`qualification`",
            "atypical": `atypical`
        }, 
        {
            "reportUuid": "`reportUuid`",
            "latitude": `latitude`,
            "longitude": `longitude`,
            "value": `value`,
            "startTime": "`startTime`",
            "qualification": "`qualification`",
            "atypical": `atypical`
        },
        ...
    ]
}

To get all flights :

GET /flights?apiKey=`apiKey`

Response will look like :

{
    "data": [
        {
            "flightId": "`flightId`", 
            "flightNumber": `flightNumber`, 
            "departureTime": "`departureTime`", 
            "arrivalTime": "`arrivalTime`", 
            "airportOrigin": "`airportOrigin`", 
            "airportDestination": "`airportDestination`", 
            "aircraftType": "`aircraftType`", 
            "firstLatitude": `firstLatitude`, 
            "firstLongitude": `firstLongitude`, 
            "midLatitude": `midLatitude`, 
            "midLongitude": `midLongitude`, 
            "lastLatitude": `lastLatitude`, 
            "lastLongitude": `lastLongitude`
        }, 
        {
            "flightId": "`flightId`", 
            "flightNumber": `flightNumber`, 
            "departureTime": "`departureTime`", 
            "arrivalTime": "`arrivalTime`", 
            "airportOrigin": "`airportOrigin`", 
            "airportDestination": "`airportDestination`", 
            "aircraftType": "`aircraftType`", 
            "firstLatitude": `firstLatitude`, 
            "firstLongitude": `firstLongitude`, 
            "midLatitude": `midLatitude`, 
            "midLongitude": `midLongitude`, 
            "lastLatitude": `lastLatitude`, 
            "lastLongitude": `lastLongitude`
        },
        ...
    ]
}

To get statistics measurement by interval :

GET /measurmentsStatisticsTotal?apiKey=`apiKey`
GET /measurmentsStatisticsTotal?apiKey=`apiKey`&userId=`<userId>`

Response will look like :

{
  450
}

To get statistics measurement by interval :

GET /measurmentsStatisticsByInterval?apiKey=`apiKey`

Curl Command :

curl --location --request GET 'https://request.openradiation.staging.ul2i.fr/measurementsHistoryValue?apiKey=<apikey>' \
--header 'Content-Type: application/json' \
--data-raw '{
    "interval": [0.020,0.040,0.060,0.080,0.120,0.130,0.140,0.160,0.180,0.200]
    "qualification" : ['groundlevel']
}'

Response will look like :

{
"elements": {
    "val_0": "416",
    "val_1": "3755",
    "val_2": "14931",
    "val_3": "44695",
    "val_4": "189031",
    "val_5": "29714",
    "val_6": "18005",
    "val_7": "24348",
    "val_8": "18285",
    "val_9": "11946",
    "val_10": "18294"
},
"labels": {
    "val_0": "0-0.020",
    "val_1": "0.020-0.040",
    "val_2": "0.040-0.060",
    "val_3": "0.060-0.080",
    "val_4": "0.080-0.120",
    "val_5": "0.120-0.130",
    "val_6": "0.130-0.140",
    "val_7": "0.140-0.160",
    "val_8": "0.160-0.180",
    "val_9": "0.180-0.200",
    "val_10": "0.200 et +"
},
"qualification": [
    "groundlevel"
]

}

Submitting data to the API

The endpoint for submit API is https://submit.openradiation.net/.

To submit a measurement

POST /measurements 
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json
{
    "apiKey": "`apiKey`",
    "data": {
        "reportUuid": "`reportUuid`",
        "latitude": `latitude`,
        "longitude": `longitude`,
        "value": `value`,
        "startTime": "`startTime`"
        ....
    }
}

Restricted access to the API

This restricted access is only available for openradiation.org website with a special secret key

To communicate the list of users :

PUT /users
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json
{
    "apiKey": "`apiKey`",
    "data": [{
        "userId": "`userId`",
        "userPwd": "`userPwd`"
        },{ 
            ....
        }
    ]
}

To Create/Update user :

PUT /users
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json
{
    "apiKey": "`apiKey`",
    "userId": "`userId`",
    "userPwd": "`userPwd`"
}

To Delete user :

PUT /users
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json
{
    "apiKey": "`apiKey`",
    "userId": "`userId`"
}

To update the qualification criteria for a unique measurement :

POST /measurements/`reportUuid`
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json
{
    "apiKey": "`apiKey`",
    "data": {
        "qualification": "`qualification`",
        "qualificationVotesNumber": `qualificationVotesNumber`
    }
}

Install with Docker

This project can be start with docker

    docker-compose up -d postgres
  • copy of your dump into the postgres container :
   docker cp openradiation.dmp openradiation-api_postgres_1:/openradiation.dmp
  • create database openradiation :
    docker ps --all //to see <postresID>
    docker exec -it <postresID> bash
    psql -U postgres
    create database openradiation;
  • dump of database :
    \q
    pg_restore -Fc -i -U postgres -d openradiation -c /openradiation.dmp
  • create your container nodeJS 6.9.3 :
    exit
    docker-compose up -d app