API основного бэкенд приложения и другая полезная информация о нём - Glost/iot-olap-clickhouse GitHub Wiki
Общая информация
Исходный код приложения находится в директории server. Технологический стек: Java 8, Spring Boot, PostgreSQL (реляционная СУБД для кратковременного хранения текущих данных), ClickHouse (OLAP column-oriented СУБД для выгрузки аналитических данных за промежуток времени для хранения на постоянной основе и использования в аналитических целях).
Данные в ClickHouse выгружаются в начале каждого астрономического часа. Данные, выгружаемые в ClickHouse, удаляются из PostgreSQL.
Используются POST-запросы, тело POST-запросов передаётся в JSON-формате, ответы запросов, если они есть, передаются также в JSON-формате.
Для обоих указанных в списке запросов необходимо передавать токен в заголовке с ключом token, сами значения токена можно найти в файлах с пропертями.
Статус запроса будет 200, если запрос отработал корректно.
Хост приложения
To be defined.
Подключение к виртуальной машине (по SSH) и к БД
Виртуальная машина с развёрнутым и запущенным бэкенд-приложением и кластеры обеих БД (PostgreSQL и ClickHouse) расположены в To be defined. Все данные (кроме паролей, но они есть в файлах с пропертями) и инструкции для подключения к БД можно найти по ссылкам ниже, а для подключения к виртуальной машине - надо добавить свой SSH-ключ в доверенные.
- Виртуальная машина: To be defined.
- Кластер PostgreSQL: To be defined.
- Кластер ClickHouse: To be defined.
Пользовательские типы данных
Coordinates- координаты датчика, поля:latitude- широта (в градусах), на которой расположен датчик - типdouble- обязательноеlongitude- долгота (в градусах), на которой расположен датчик - типdouble- обязательноеaltitude- высота над уровнем моря (в метрах), на которой расположен датчик - типdouble- обязательное
Values- показания датчика, поля:air_temperature- температура воздуха (в градусах Цельсия) - типdouble- обязательноеair_humidity- влажность воздуха (в процентах) - типdouble- обязательноеwind_speed- скорость ветра (в метрах в секунду) - типdouble- обязательноеis_raining- флаг, идёт ли дождь (true, если идёт, иначеfalse) - типboolean- обязательноеilluminance- освещённость (в люксах) - типdouble- обязательное
CoordinateInterval- отрезок для значения координаты датчика, поля:from- начальное значение отрезка (включительно) - типdouble- обязательноеto- конечное значение отрезка (включительно) - должно быть не меньше, чемfrom- типdouble- обязательное
TimestampInterval- отрезок для значения времени произведения замера показаний на датчике, поля:from- начальное значение отрезка (включительно) - строка (типString) в форматеyyyy-MM-dd['T'][ ]HH:mm:ss.SSSXXXX(например:2019-12-01 17:18:48.126+0300,2019-12-01T17:18:48.126+0300,2019-12-01 17:18:48.126Z,2019-12-01T17:18:48.126Z, и т. д.) - обязательноеto- конечное значение отрезка (включительно) - должно быть не меньше, чемfrom- строка (типString) в форматеyyyy-MM-dd['T'][ ]HH:mm:ss.SSSXXXX(например:2019-12-01 17:18:48.126+0300,2019-12-01T17:18:48.126+0300,2019-12-01 17:18:48.126Z,2019-12-01T17:18:48.126Z, и т. д.) - обязательное
AggregatedPeriod- период времени, по которому производится агрегация данных - перечисление (enum), возможные значения:MINUTE- одна минутаHOUR- один часDAY- один день
AggregatedValue- агрегированные значения того или иного показания датчика(-ов) за то или иное время, поля:timestamp- время, начиная с которого агрегированы показания на датчике, с указанием часового пояса - строка (типString) в форматеyyyy-MM-dd HH:mm:ss.SSSXXXX(например:2019-12-01 17:18:48.126+0300) - обязательноеmin- наименьшее значение показания - типdouble- обязательноеmax- наибольшее значение показания - типdouble- обязательноеavg- среднее значение показания - типdouble- обязательноеmedian- медианное значение показания - типdouble- обязательноеvariance- несмещённая оценка дисперсии значений показания - типdouble- обязательное
AggregatedRainValue- агрегированные значения показания наличия дождя датчика(-ов) за то или иное время, поля:timestamp- время, начиная с которого агрегированы показания на датчике, с указанием часового пояса - строка (типString) в форматеyyyy-MM-dd HH:mm:ss.SSSXXXX(например:2019-12-01 17:18:48.126+0300) - обязательноеavg_rains- среднее количество показаний по учитываемым датчикам за данный промежуток времени, в которых шёл дождь, то естьis_rainingв показаниях датчика (Values) было равноtrue(если показания агрегируются для одного датчика, то количество показаний по данному датчику за данный промежуток времени, в которых шёл дождь) - типdouble- обязательное
AggregatedValues- агрегированные значения показаний датчика(-ов), поля:air_temperature- массив объектовAggregatedValueагрегированных за разное время значений для температуры воздуха (в градусах Цельсия) - типAggregatedValue[]- обязательноеair_humidity- массив объектовAggregatedValueагрегированных за разное время значений для влажности воздуха (в процентах) - типAggregatedValue[]- обязательноеwind_speed- массив объектовAggregatedValueагрегированных за разное время значений для скорости ветра (в метрах в секунду) - типAggregatedValue[]- обязательноеilluminance- массив объектовAggregatedValueагрегированных за разное время значений для освещённости (в люксах) - типAggregatedValue[]- обязательноеavg_rains_values- массив объектовAggregatedRainValueсо средними количествами показаний по учитываемым датчикам за данные промежутки времени, в которых шёл дождь, то естьis_rainingв показаниях датчика (Values) было равноtrue(если показания агрегируются для одного датчика, то количество показаний по данному датчику за данный промежуток времени, в которых шёл дождь) - типAggregatedRainValue[]- обязательное
SensorAggregatedValues- агрегированные значения показаний датчика(-ов) с информацией о самом(-их) датчике(-ах), поля:coordinates- координаты датчика - типCoordinates- необязательное (еслиnullили не задано, то агрегированные показания представляют собой агрегированные данные по всем удовлетворяющим запросу датчикам, а не по одному конкретному)aggregated_values- агрегированные значения показаний датчика(-ов) за разные промежутки времени - типAggregatedValues- обязательное
Описание методов API
POST /pushData
Передача данных от датчика серверу.
Поля тела запроса:
coordinates- координаты датчика - типCoordinates- обязательноеvalues- значения датчика - типValues- обязательноеtimestamp- время произведения замера показаний на датчике, с указанием часового пояса - строка (типString) в форматеyyyy-MM-dd['T'][ ]HH:mm:ss.SSSXXXX(например:2019-12-01 17:18:48.126+0300,2019-12-01T17:18:48.126+0300,2019-12-01 17:18:48.126Z,2019-12-01T17:18:48.126Z, и т. д.) - обязательное
Пример тела запроса в формате JSON:
{
"coordinates": {
"latitude": 55.755831,
"longitude": 37.617673,
"altitude": 156.5
},
"values": {
"air_temperature": 15.7,
"air_humidity": 72.1,
"wind_speed": 5.62,
"is_raining": false,
"illuminance": 5072.134
},
"timestamp": "2019-12-01 17:18:48.126+0300"
}
Тело ответа пустое, но необходимо смотреть на статус выполнения запроса (200 или не 200), возвращённый сервером.
POST /getAggregatedData
Получение агрегированных в ClickHouse данных от сервера.
Поля тела запроса:
latitude_intervals- массив объектов типаCoordinateIntervalдля широты (в градусах), на которой расположен датчик - типCoordinateInterval[]- необязательное (еслиnullили не задано, то широта, на которой расположен датчик, не ограничивается)longitude_intervals- массив объектов типаCoordinateIntervalдля долготы (в градусах), на которой расположен датчик - типCoordinateInterval[]- необязательное (еслиnullили не задано, то долгота, на которой расположен датчик, не ограничивается)altitude_intervals- массив объектов типаCoordinateIntervalдля высоты над уровнем моря (в метрах), на которой расположен датчик - типCoordinateInterval[]- необязательное (еслиnullили не задано, то высота над уровнем моря, на которой расположен датчик, не ограничивается)timestamp_interval- объект типаTimestampIntervalдля времени произведения замера показаний на датчике - типTimestampInterval- обязательноеaggregated_period- период времени, по которому производится агрегация данных - типAggregatedPeriod(в JSON представлен как строка -String) - обязательноеneed_split_by_coordinates- показывает, нужно ли возвращать агрегированные данные по каждому отдельному датчику (true) или только агрегированные данные по всем удовлетворяющим запросу датчикам (false) - необязательное (по умолчаниюfalse)
Пример тела запроса в формате JSON:
{
"latitude_intervals": [
{
"from": 55.755831,
"to": 57.854573
},
{
"from": 65.459327,
"to": 69.423342
}
],
"longitude_intervals": [
{
"from": 37.617673,
"to": 41.965782
}
],
"altitude_intervals": [
{
"from": 150.0,
"to": 450.0
}
],
"timestamp_interval": {
"from": "2019-12-01 17:18:48.126+0300",
"to": "2019-12-05 15:00:00.000+0300"
},
"aggregated_period": "HOUR",
"need_split_by_coordinates": true
}
Другой пример тела запроса в формате JSON, здесь не ограничены широта и долгота, на которых расположен датчик, а также не требуется возвращать агрегированные данные по каждому отдельному датчику, будут возвращены только агрегированные данные по всем удовлетворяющим запросу датчикам:
{
"altitude_intervals": [
{
"from": 150.0,
"to": 450.0
}
],
"timestamp_interval": {
"from": "2019-12-01 17:18:48.126+0300",
"to": "2019-12-05 15:00:00.000+0300"
},
"aggregated_period": "HOUR",
"need_split_by_coordinates": false
}
Поля тела ответа:
is_success- выполнен ли запрос успешно (true) или нет (false) - типboolean- обязательноеerror_message- текст ошибки (в тех случаях, когдаis_successравенfalse) - строка (типString) - необязательное (отсутствует либо равноnull, еслиis_successравенtrue, но обязательное, еслиis_successравенfalse)click_house_query_execution_time- суммарное время выполнения всех запросов в ClickHouse, выполненных при исполнении данного запроса к бэкенд-приложению (в миллисекундах) - типint- необязательное (отсутствует либо равноnull, еслиis_successравенfalse, но обязательное, еслиis_successравенtrue)sensor_aggregated_values- массив объектов типаSensorAggregatedValuesс агрегированными значениями показаний датчика(-ов) с информацией о самом(-их) датчике(-ах) - типSensorAggregatedValues[]- необязательное (может отсутствовать либо быть равноnullили пустому массиву, еслиis_successравенfalseлибо не найдено ни одного датчика или показаний датчика для указанных в запросе ограничений по координатам и времени)
Пример тела ответа в формате JSON, если флаг need_split_by_coordinates в теле запроса был равен true:
{
"is_success": true,
"click_house_query_execution_time": 2791,
"sensor_aggregated_values": [
{
"coordinates": {
"latitude": 55.755831,
"longitude": 37.617673,
"altitude": 156.5
},
"aggregated_values": {
"air_temperature": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 15.5,
"max": 16.1,
"avg": 15.82,
"median": 15.7,
"variance": 0.357
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 15.3,
"max": 15.9,
"avg": 15.62,
"median": 15.5,
"variance": 0.357
}
],
"air_humidity": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 70.5,
"max": 82.36,
"avg": 77.89,
"median": 72.34,
"variance": 3.359
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 70.7,
"max": 82.56,
"avg": 78.09,
"median": 72.54,
"variance": 3.359
}
],
"wind_speed": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 5.21,
"max": 5.87,
"avg": 5.72,
"median": 5.34,
"variance": 0.12376
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 5.41,
"max": 6.07,
"avg": 5.92,
"median": 5.54,
"variance": 0.12376
}
],
"illuminance":[
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 4045.45,
"max": 5201.01,
"avg": 5145.54,
"median": 5054.45,
"variance": 45.5
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 3045.45,
"max": 4201.01,
"avg": 4145.54,
"median": 4054.45,
"variance": 45.5
}
],
"avg_rains": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"avg_rains": 7.0
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"avg_rains": 3.0
}
]
}
},
{
"coordinates": {
"latitude": 56.124057,
"longitude": 40.750421,
"altitude": 300.0
},
"aggregated_values": {
"air_temperature": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 13.5,
"max": 14.1,
"avg": 13.82,
"median": 13.7,
"variance": 0.357
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 13.3,
"max": 13.9,
"avg": 13.62,
"median": 13.5,
"variance": 0.357
}
],
"air_humidity": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 72.5,
"max": 84.36,
"avg": 79.89,
"median": 74.34,
"variance": 3.359
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 72.7,
"max": 84.56,
"avg": 80.09,
"median": 74.54,
"variance": 3.359
}
],
"wind_speed": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 7.21,
"max": 7.87,
"avg": 7.72,
"median": 7.34,
"variance": 0.12376
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 7.41,
"max": 8.07,
"avg": 7.92,
"median": 7.54,
"variance": 0.12376
}
],
"illuminance":[
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 4065.45,
"max": 5221.01,
"avg": 5165.54,
"median": 5074.45,
"variance": 45.5
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 5065.45,
"max": 6221.01,
"avg": 6165.54,
"median": 6074.45,
"variance": 45.5
}
],
"avg_rains": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"avg_rains": 0.0
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"avg_rains": 0.0
}
]
}
},
{
"aggregated_values": {
"air_temperature": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 14.5,
"max": 15.1,
"avg": 14.82,
"median": 14.7,
"variance": 0.357
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 14.3,
"max": 14.9,
"avg": 14.62,
"median": 14.5,
"variance": 0.357
}
],
"air_humidity": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 71.5,
"max": 83.36,
"avg": 78.89,
"median": 73.34,
"variance": 3.359
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 71.7,
"max": 83.56,
"avg": 79.09,
"median": 73.54,
"variance": 3.359
}
],
"wind_speed": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 6.21,
"max": 6.87,
"avg": 6.72,
"median": 6.34,
"variance": 0.12376
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 6.41,
"max": 7.07,
"avg": 6.92,
"median": 6.54,
"variance": 0.12376
}
],
"illuminance":[
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 4055.45,
"max": 5211.01,
"avg": 5155.54,
"median": 5064.45,
"variance": 45.5
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 3055.45,
"max": 4211.01,
"avg": 4155.54,
"median": 4064.45,
"variance": 45.5
}
],
"avg_rains": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"avg_rains": 3.5
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"avg_rains": 1.5
}
]
}
}
]
}
Другой пример тела ответа в формате JSON, если флаг need_split_by_coordinates в теле запроса был равен false:
{
"is_success": true,
"click_house_query_execution_time": 1248,
"sensor_aggregated_values": [
{
"aggregated_values": {
"air_temperature": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 14.5,
"max": 15.1,
"avg": 14.82,
"median": 14.7,
"variance": 0.357
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 14.3,
"max": 14.9,
"avg": 14.62,
"median": 14.5,
"variance": 0.357
}
],
"air_humidity": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 71.5,
"max": 83.36,
"avg": 78.89,
"median": 73.34,
"variance": 3.359
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 71.7,
"max": 83.56,
"avg": 79.09,
"median": 73.54,
"variance": 3.359
}
],
"wind_speed": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 6.21,
"max": 6.87,
"avg": 6.72,
"median": 6.34,
"variance": 0.12376
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 6.41,
"max": 7.07,
"avg": 6.92,
"median": 6.54,
"variance": 0.12376
}
],
"illuminance":[
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"min": 4055.45,
"max": 5211.01,
"avg": 5155.54,
"median": 5064.45,
"variance": 45.5
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"min": 3055.45,
"max": 4211.01,
"avg": 4155.54,
"median": 4064.45,
"variance": 45.5
}
],
"avg_rains": [
{
"timestamp": "2019-12-01 17:00:00.000+0300",
"avg_rains": 3.5
},
{
"timestamp": "2019-12-01 18:00:00.000+0300",
"avg_rains": 1.5
}
]
}
}
]
}
Другой пример тела ответа в формате JSON, если не найдено ни одного датчика или показаний датчика для указанных в запросе ограничений по координатам и времени:
{
"is_success": true,
"click_house_query_execution_time": 971
}
Другой пример тела ответа в формате JSON, если произошла ошибка выполнения запроса:
{
"is_success": false,
"error_message": "There were some errors:\ncoordinateInterval.to [55.854573] should be not less than coordinateInterval.from [57.755831]\ntimestampInterval.to [2019-12-01T 20:18:48.126Z] should be not less than timestampInterval.from [2019-12-02T 17:18:48.126Z]"
}