26#include <QNetworkRequest>
27#include <nlohmann/json.hpp>
31 const QString trimmed = type.trimmed();
32 if ( trimmed.compare( QLatin1String(
"Thing" ), Qt::CaseInsensitive ) == 0 )
34 if ( trimmed.compare( QLatin1String(
"Location" ), Qt::CaseInsensitive ) == 0 )
36 if ( trimmed.compare( QLatin1String(
"HistoricalLocation" ), Qt::CaseInsensitive ) == 0 )
38 if ( trimmed.compare( QLatin1String(
"Datastream" ), Qt::CaseInsensitive ) == 0 )
40 if ( trimmed.compare( QLatin1String(
"Sensor" ), Qt::CaseInsensitive ) == 0 )
42 if ( trimmed.compare( QLatin1String(
"ObservedProperty" ), Qt::CaseInsensitive ) == 0 )
44 if ( trimmed.compare( QLatin1String(
"Observation" ), Qt::CaseInsensitive ) == 0 )
46 if ( trimmed.compare( QLatin1String(
"FeatureOfInterest" ), Qt::CaseInsensitive ) == 0 )
59 return plural ? QObject::tr(
"Things" ) : QObject::tr(
"Thing" );
61 return plural ? QObject::tr(
"Locations" ) : QObject::tr(
"Location" );
63 return plural ? QObject::tr(
"Historical Locations" ) : QObject::tr(
"Historical Location" );
65 return plural ? QObject::tr(
"Datastreams" ) : QObject::tr(
"Datastream" );
67 return plural ? QObject::tr(
"Sensors" ) : QObject::tr(
"Sensor" );
69 return plural ? QObject::tr(
"Observed Properties" ) : QObject::tr(
"Observed Property" );
71 return plural ? QObject::tr(
"Observations" ) : QObject::tr(
"Observation" );
73 return plural ? QObject::tr(
"Features of Interest" ) : QObject::tr(
"Feature of Interest" );
80 const QString trimmed = type.trimmed();
81 if ( trimmed.compare( QLatin1String(
"Things" ), Qt::CaseInsensitive ) == 0 )
83 if ( trimmed.compare( QLatin1String(
"Locations" ), Qt::CaseInsensitive ) == 0 )
85 if ( trimmed.compare( QLatin1String(
"HistoricalLocations" ), Qt::CaseInsensitive ) == 0 )
87 if ( trimmed.compare( QLatin1String(
"Datastreams" ), Qt::CaseInsensitive ) == 0 )
89 if ( trimmed.compare( QLatin1String(
"Sensors" ), Qt::CaseInsensitive ) == 0 )
91 if ( trimmed.compare( QLatin1String(
"ObservedProperties" ), Qt::CaseInsensitive ) == 0 )
93 if ( trimmed.compare( QLatin1String(
"Observations" ), Qt::CaseInsensitive ) == 0 )
95 if ( trimmed.compare( QLatin1String(
"FeaturesOfInterest" ), Qt::CaseInsensitive ) == 0 )
106 fields.
append(
QgsField( QStringLiteral(
"id" ), QVariant::String ) );
107 fields.
append(
QgsField( QStringLiteral(
"selfLink" ), QVariant::String ) );
116 fields.
append(
QgsField( QStringLiteral(
"name" ), QVariant::String ) );
117 fields.
append(
QgsField( QStringLiteral(
"description" ), QVariant::String ) );
118 fields.
append(
QgsField( QStringLiteral(
"properties" ), QVariant::Map, QStringLiteral(
"json" ), 0, 0, QString(), QVariant::String ) );
123 fields.
append(
QgsField( QStringLiteral(
"name" ), QVariant::String ) );
124 fields.
append(
QgsField( QStringLiteral(
"description" ), QVariant::String ) );
125 fields.
append(
QgsField( QStringLiteral(
"properties" ), QVariant::Map, QStringLiteral(
"json" ), 0, 0, QString(), QVariant::String ) );
130 fields.
append(
QgsField( QStringLiteral(
"time" ), QVariant::DateTime ) );
135 fields.
append(
QgsField( QStringLiteral(
"name" ), QVariant::String ) );
136 fields.
append(
QgsField( QStringLiteral(
"description" ), QVariant::String ) );
137 fields.
append(
QgsField( QStringLiteral(
"unitOfMeasurement" ), QVariant::Map, QStringLiteral(
"json" ), 0, 0, QString(), QVariant::String ) );
138 fields.
append(
QgsField( QStringLiteral(
"observationType" ), QVariant::String ) );
139 fields.
append(
QgsField( QStringLiteral(
"properties" ), QVariant::Map, QStringLiteral(
"json" ), 0, 0, QString(), QVariant::String ) );
140 fields.
append(
QgsField( QStringLiteral(
"phenomenonTimeStart" ), QVariant::DateTime ) );
141 fields.
append(
QgsField( QStringLiteral(
"phenomenonTimeEnd" ), QVariant::DateTime ) );
142 fields.
append(
QgsField( QStringLiteral(
"resultTimeStart" ), QVariant::DateTime ) );
143 fields.
append(
QgsField( QStringLiteral(
"resultTimeEnd" ), QVariant::DateTime ) );
148 fields.
append(
QgsField( QStringLiteral(
"name" ), QVariant::String ) );
149 fields.
append(
QgsField( QStringLiteral(
"description" ), QVariant::String ) );
150 fields.
append(
QgsField( QStringLiteral(
"metadata" ), QVariant::String ) );
151 fields.
append(
QgsField( QStringLiteral(
"properties" ), QVariant::Map, QStringLiteral(
"json" ), 0, 0, QString(), QVariant::String ) );
156 fields.
append(
QgsField( QStringLiteral(
"name" ), QVariant::String ) );
157 fields.
append(
QgsField( QStringLiteral(
"definition" ), QVariant::String ) );
158 fields.
append(
QgsField( QStringLiteral(
"description" ), QVariant::String ) );
159 fields.
append(
QgsField( QStringLiteral(
"properties" ), QVariant::Map, QStringLiteral(
"json" ), 0, 0, QString(), QVariant::String ) );
164 fields.
append(
QgsField( QStringLiteral(
"phenomenonTimeStart" ), QVariant::DateTime ) );
165 fields.
append(
QgsField( QStringLiteral(
"phenomenonTimeEnd" ), QVariant::DateTime ) );
168 fields.
append(
QgsField( QStringLiteral(
"result" ), QVariant::String ) );
170 fields.
append(
QgsField( QStringLiteral(
"resultTime" ), QVariant::DateTime ) );
171 fields.
append(
QgsField( QStringLiteral(
"resultQuality" ), QVariant::StringList, QString(), 0, 0, QString(), QVariant::String ) );
172 fields.
append(
QgsField( QStringLiteral(
"validTimeStart" ), QVariant::DateTime ) );
173 fields.
append(
QgsField( QStringLiteral(
"validTimeEnd" ), QVariant::DateTime ) );
174 fields.
append(
QgsField( QStringLiteral(
"parameters" ), QVariant::Map, QStringLiteral(
"json" ), 0, 0, QString(), QVariant::String ) );
179 fields.
append(
QgsField( QStringLiteral(
"name" ), QVariant::String ) );
180 fields.
append(
QgsField( QStringLiteral(
"description" ), QVariant::String ) );
181 fields.
append(
QgsField( QStringLiteral(
"properties" ), QVariant::Map, QStringLiteral(
"json" ), 0, 0, QString(), QVariant::String ) );
202 return QStringLiteral(
"location" );
205 return QStringLiteral(
"feature" );
232 QString geometryTypeString;
236 geometryTypeString = QStringLiteral(
"Point" );
239 geometryTypeString = QStringLiteral(
"Polygon" );
242 geometryTypeString = QStringLiteral(
"LineString" );
251 if ( filterTarget.isEmpty() )
254 return QStringLiteral(
"%1/type eq '%2' or %1/geometry/type eq '%2'" ).arg( filterTarget, geometryTypeString );
260 return ( extent.
isNull() || geometryField.isEmpty() )
262 : QStringLiteral(
"geo.intersects(%1, geography'%2')" ).arg( geometryField, extent.
asWktPolygon() );
267 QStringList nonEmptyFilters;
268 for (
const QString &filter : filters )
270 if ( !filter.isEmpty() )
271 nonEmptyFilters.append( filter );
273 if ( nonEmptyFilters.empty() )
275 if ( nonEmptyFilters.size() == 1 )
276 return nonEmptyFilters.at( 0 );
278 return QStringLiteral(
"(" ) + nonEmptyFilters.join( QLatin1String(
") and (" ) ) + QStringLiteral(
")" );
283 QNetworkRequest request = QNetworkRequest( QUrl( uri ) );
289 switch ( networkRequest.
get( request ) )
301 QString entityBaseUri;
306 if ( !rootContent.contains(
"value" ) )
308 QgsDebugError( QStringLiteral(
"No 'value' array in response" ) );
312 bool foundMatchingEntity =
false;
313 for (
const auto &valueJson : rootContent[
"value"] )
315 if ( valueJson.contains(
"name" ) && valueJson.contains(
"url" ) )
317 const QString name = QString::fromStdString( valueJson[
"name"].get<std::string>() );
319 if ( entityType == type )
321 const QString url = QString::fromStdString( valueJson[
"url"].get<std::string>() );
322 if ( !url.isEmpty() )
324 foundMatchingEntity =
true;
332 if ( !foundMatchingEntity )
338 catch (
const nlohmann::json::parse_error &ex )
340 QgsDebugError( QStringLiteral(
"Error parsing response: %1" ).arg( ex.what() ) );
344 auto getCountForType = [entityBaseUri, type, authCfg, feedback](
Qgis::GeometryType geometryType ) ->
long long
347 QString countUri = QStringLiteral(
"%1?$top=0&$count=true" ).arg( entityBaseUri );
350 if ( !typeFilter.isEmpty() )
351 countUri += QStringLiteral(
"&$filter=" ) + typeFilter;
353 const QUrl url( countUri );
355 QNetworkRequest request( url );
377 if ( !rootContent.contains(
"@iot.count" ) )
379 QgsDebugError( QStringLiteral(
"No '@iot.count' value in response" ) );
383 return rootContent[
"@iot.count"].get<
long long>();
385 catch (
const nlohmann::json::parse_error &ex )
387 QgsDebugError( QStringLiteral(
"Error parsing response: %1" ).arg( ex.what() ) );
393 QList<Qgis::GeometryType> types;
401 const long long matchCount = getCountForType( geometryType );
402 if ( matchCount < 0 )
404 else if ( matchCount > 0 )
405 types.append( geometryType );
SensorThingsEntity
OGC SensorThings API entity types.
@ Sensor
A Sensor is an instrument that observes a property or phenomenon with the goal of producing an estima...
@ ObservedProperty
An ObservedProperty specifies the phenomenon of an Observation.
@ Invalid
An invalid/unknown entity.
@ FeatureOfInterest
In the context of the Internet of Things, many Observations’ FeatureOfInterest can be the Location of...
@ Datastream
A Datastream groups a collection of Observations measuring the same ObservedProperty and produced by ...
@ Observation
An Observation is the act of measuring or otherwise determining the value of a property.
@ Location
A Location entity locates the Thing or the Things it associated with. A Thing’s Location entity is de...
@ Thing
A Thing is an object of the physical world (physical things) or the information world (virtual things...
@ HistoricalLocation
A Thing’s HistoricalLocation entity set provides the times of the current (i.e., last known) and prev...
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
WkbType
The WKB type describes the number of dimensions a geometry has.
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "get" operation on the specified request.
void setAuthCfg(const QString &authCfg)
Sets the authentication config id which should be used during the request.
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
@ NetworkError
A network error occurred.
@ ServerExceptionError
An exception was raised by the server.
@ NoError
No error was encountered.
@ TimeoutError
Timeout was reached before a reply was received.
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get(), post(), head() or put() request has been mad...
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
Encapsulate a field in an attribute table or data source.
Container of fields for a vector layer.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QByteArray content() const
Returns the reply content.
A rectangle specified with double values.
QString asWktPolygon() const
Returns a string representation of the rectangle as a WKT Polygon.
bool isNull() const
Test if the rectangle is null (holding no spatial information).
static QList< Qgis::GeometryType > availableGeometryTypes(const QString &uri, Qgis::SensorThingsEntity type, QgsFeedback *feedback=nullptr, const QString &authCfg=QString())
Returns a list of available geometry types for the server at the specified uri and entity type.
static Qgis::SensorThingsEntity stringToEntity(const QString &type)
Converts a string value to a Qgis::SensorThingsEntity type.
static Qgis::SensorThingsEntity entitySetStringToEntity(const QString &type)
Converts a string value corresponding to a SensorThings entity set to a Qgis::SensorThingsEntity type...
static QString combineFilters(const QStringList &filters)
Combines a set of SensorThings API filter operators.
static QString filterForWkbType(Qgis::SensorThingsEntity entityType, Qgis::WkbType wkbType)
Returns a filter string which restricts results to those matching the specified entityType and wkbTyp...
static QString displayString(Qgis::SensorThingsEntity type, bool plural=false)
Converts a Qgis::SensorThingsEntity type to a user-friendly translated string.
static bool entityTypeHasGeometry(Qgis::SensorThingsEntity type)
Returns true if the specified entity type can have geometry attached.
static QString geometryFieldForEntityType(Qgis::SensorThingsEntity type)
Returns the geometry field for a specified entity type.
static QgsFields fieldsForEntityType(Qgis::SensorThingsEntity type)
Returns the fields which correspond to a specified entity type.
static QString filterForExtent(const QString &geometryField, const QgsRectangle &extent)
Returns a filter string which restricts results to those within the specified extent.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
#define BUILTIN_UNREACHABLE
#define QgsDebugError(str)
#define QgsSetRequestInitiatorClass(request, _class)
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg, bool allowFragments)