{"info":{"_postman_id":"17fa5c4e-3836-49ce-8769-df5e9bba674e","name":"NGSI-LD QuantumLeap","description":"<html><head></head><body><p>This tutorial is an introduction to <a href=\"https://smartsdk.github.io/ngsi-timeseries-api/\">FIWARE QuantumLeap</a> - a generic\nenabler which is used to persist context data into a <strong>CrateDB</strong> database. The tutorial activates the IoT sensors\nconnected in the <a href=\"https://github.com/FIWARE/tutorials.IoT-Agent\">previous tutorial</a> and persists measurements from those\nsensors into the database. To retrieve time-based aggregations of such data, users can either use <strong>QuantumLeap</strong> query\nAPI or connect directly to the <strong>CrateDB</strong> HTTP endpoint. Results are visualised on a graph or via the <strong>Grafana</strong> time\nseries analytics tool.</p>\n<p>The <code>docker-compose</code> files for this tutorial can be found on GitHub: </p>\n<p><img src=\"https://fiware.github.io/tutorials.Time-Series-Data/icon/GitHub-Mark-32px.png\" alt=\"GitHub\"> <a href=\"https://github.com/Fiware/tutorials.Time-Series-Data\">FIWARE 301: Persisting Context Data</a></p>\n<blockquote>\n<p>\"Forever is composed of nows.\"</p>\n<p>— Emily Dickinson</p>\n</blockquote>\n<p>FIWARE <a href=\"https://smartsdk.github.io/ngsi-timeseries-api/\">QuantumLeap</a> is an time-based data-persistence generic enabler\ncreated specifically to persist and query time-series database (currently CrateDB and TimescaleDB). The component can\nrespond to NGSI-v2 or NGSI-LD subscriptions.</p>\n<p><a href=\"https://crate.io/\">CrateDB</a> is a distributed SQL DBMS designed for use with the internet of Things. It is capable of\ningesting a large number of data points per second and can be queried in real-time. The database is designed for the\nexecution of complex queries such as geospatial and time series data. Retrieval of this historic context data allows for\nthe creation of graphs and dashboards displaying trends over time.</p>\n<p><a href=\"https://www.timescale.com/\">TimescaleDB</a> scales PostgreSQL for time-series data via automatic partitioning across time\nand space (partitioning key), yet retains the standard PostgreSQL interface. In other words, TimescaleDB exposes what\nlook like regular tables, but are actually only an abstraction (or a virtual view) of many individual tables comprising\nthe actual data. In combination with <a href=\"https://postgis.net/\">PostGIS</a> extension can support geo-timeseries.</p>\n<h2 id=\"analyzing-time-series-data\">Analyzing time series data</h2>\n<p>The appropriate use of time series data analysis will depend on your use case and the reliability of the data\nmeasurements you receive. Time series data analysis can be used to answer questions such as:</p>\n<ul>\n<li>What was the maximum measurement of a device within a given time period?</li>\n<li>What was the average measurement of a device within a given time period?</li>\n<li>What was the sum of the measurements sent by a device within a given time period?</li>\n</ul>\n<p>It can also be used to reduce the significance of each individual data point to exclude outliers by smoothing.</p>\n<h4 id=\"grafana\">Grafana</h4>\n<p><a href=\"https://grafana.com/\">Grafana</a> is an open source software for time series analytics tool which will be used during this\ntutorial. It integrates with a variety of time-series databases including <strong>CrateDB</strong> and <strong>TimescaleDB</strong>. It is\navailable licensed under the Apache License 2.0. More information can be found at <code>https://grafana.com/</code>.</p>\n<h4 id=\"device-monitor\">Device Monitor</h4>\n<p>For the purpose of this tutorial, a series of dummy agricultural IoT devices have been created, which will be attached\nto the context broker. Details of the architecture and protocol used can be found in the\n<a href=\"https://github.com/FIWARE/tutorials.IoT-Sensors/tree/NGSI-LD\">IoT Sensors tutorial</a> The state of each device can be\nseen on the UltraLight device monitor web page found at: <code>http://localhost:3000/device/monitor</code></p>\n<p><img src=\"https://fiware.github.io/tutorials.Time-Series-Data/img/farm-devices.png\" alt=\"FIWARE Monitor\"></p>\n<h4 id=\"device-history\">Device History</h4>\n<p>Once <strong>QuantumLeap</strong> has started aggregating data, the historical state of each device can be seen on the device history\nweb page found at: <code>http://localhost:3000/device/history/urn:ngsi-ld:Farm:001</code></p>\n<p><img src=\"https://fiware.github.io/tutorials.Time-Series-Data/img/history-graphs.png\" alt=\"\"></p>\n<h1 id=\"architecture\">Architecture</h1>\n<p>This application builds on the components and dummy IoT devices created in\n<a href=\"https://github.com/FIWARE/tutorials.IoT-Agent/\">previous tutorials</a>. It will use three FIWARE components: the\n<a href=\"https://fiware-orion.readthedocs.io/en/latest/\">Orion Context Broker</a>, the\n<a href=\"https://fiware-iotagent-ul.readthedocs.io/en/latest/\">IoT Agent for Ultralight 2.0</a>, and\n<a href=\"https://smartsdk.github.io/ngsi-timeseries-api/\">QuantumLeap</a> .</p>\n<p>Therefore the overall architecture will consist of the following elements:</p>\n<ul>\n<li><p>The <strong>FIWARE Generic Enablers</strong>:</p>\n<ul>\n<li>The <a href=\"https://fiware-orion.readthedocs.io/en/latest/\">Orion Context Broker</a> which will receive requests using\n<a href=\"https://forge.etsi.org/swagger/ui/?url=https://forge.etsi.org/gitlab/NGSI-LD/NGSI-LD/raw/master/spec/updated/full_api.json\">NGSI-LD</a></li>\n<li>The FIWARE <a href=\"https://fiware-iotagent-ul.readthedocs.io/en/latest/\">IoT Agent for UltraLight 2.0</a> which will\nreceive southbound requests using\n<a href=\"https://forge.etsi.org/swagger/ui/?url=https://forge.etsi.org/gitlab/NGSI-LD/NGSI-LD/raw/master/spec/updated/full_api.json\">NGSI-LD</a>\nand convert them to\n<a href=\"https://fiware-iotagent-ul.readthedocs.io/en/latest/usermanual/index.html#user-programmers-manual\">UltraLight 2.0</a>\ncommands for the devices</li>\n<li>FIWARE <a href=\"https://smartsdk.github.io/ngsi-timeseries-api/\">QuantumLeap</a> subscribed to context changes and\npersisting them into a <strong>CrateDB</strong> database</li>\n</ul>\n</li>\n<li><p>A <a href=\"https://www.mongodb.com/\">MongoDB</a> database:</p>\n<ul>\n<li>Used by the <strong>Orion Context Broker</strong> to hold context data information such as data entities, subscriptions and\nregistrations</li>\n<li>Used by the <strong>IoT Agent</strong> to hold device information such as device URLs and Keys</li>\n</ul>\n</li>\n<li><p>A <a href=\"https://crate.io/\">CrateDB</a> database:</p>\n<ul>\n<li>Used as a data sink to hold time-based historical context data</li>\n<li>offers an HTTP endpoint to interpret time-based data queries</li>\n</ul>\n</li>\n<li><p>The <strong>Tutorial Application</strong> does the following:</p>\n<ul>\n<li>Offers static <code>@context</code> files defining the context entities within the system.</li>\n<li>Acts as set of dummy <a href=\"https://github.com/FIWARE/tutorials.IoT-Sensors/tree/NGSI-LD\">agricultural IoT devices</a>\nusing the\n<a href=\"https://fiware-iotagent-ul.readthedocs.io/en/latest/usermanual/index.html#user-programmers-manual\">UltraLight 2.0</a>\nprotocol running over HTTP.</li>\n</ul>\n</li>\n</ul>\n<p>Since all interactions between the elements are initiated by HTTP requests, the entities can be containerized and run\nfrom exposed ports.</p>\n<p>The overall architecture can be seen below:</p>\n<p><img src=\"https://fiware.github.io/tutorials.Time-Series-Data/img/architecture.png\" alt=\"\"></p>\n<h1 id=\"prerequisites\">Prerequisites</h1>\n<h2 id=\"docker-and-docker-compose\">Docker and Docker Compose</h2>\n<p>To keep things simple all components will be run using <a href=\"https://www.docker.com\">Docker</a>. <strong>Docker</strong> is a container\ntechnology which allows to different components isolated into their respective environments.</p>\n<ul>\n<li>To install Docker on Windows follow the instructions <a href=\"https://docs.docker.com/docker-for-windows/\">here</a></li>\n<li>To install Docker on Mac follow the instructions <a href=\"https://docs.docker.com/docker-for-mac/\">here</a></li>\n<li>To install Docker on Linux follow the instructions <a href=\"https://docs.docker.com/install/\">here</a></li>\n</ul>\n<p><strong>Docker Compose</strong> is a tool for defining and running multi-container Docker applications. A series of\n<a href=\"https://raw.githubusercontent.com/Fiware/tutorials.Time-Series-Data/master/docker-compose.yml\">YAML files</a> are used to\nconfigure the required services for the application. This means all container services can be brought up in a single\ncommand. Docker Compose is installed by default as part of Docker for Windows and Docker for Mac, however Linux users\nwill need to follow the instructions found <a href=\"https://docs.docker.com/compose/install/\">here</a></p>\n<p>You can check your current <strong>Docker</strong> and <strong>Docker Compose</strong> versions using the following commands:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">docker-compose -v\ndocker version\n</code></pre>\n<p>Please ensure that you are using Docker version 18.03 or higher and Docker Compose 1.21 or higher and upgrade if\nnecessary.</p>\n<h2 id=\"cygwin-for-windows\">Cygwin for Windows</h2>\n<p>We will start up our services using a simple Bash script. Windows users should download <a href=\"http://www.cygwin.com/\">cygwin</a>\nto provide a command-line functionality similar to a Linux distribution on Windows.</p>\n<h1 id=\"start-up\">Start Up</h1>\n<p>Before you start, you should ensure that you have obtained or built the necessary Docker images locally. Please clone\nthe repository and create the necessary images by running the commands as shown:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">git clone https://github.com/FIWARE/tutorials.Time-Series-Data.git\ncd tutorials.Time-Series-Data\ngit checkout NGSI-LD\n\n./services create\n</code></pre>\n<p>Thereafter, all services can be initialized from the command-line by running the\n<a href=\"https://github.com/FIWARE/tutorials.Time-Series-Data/blob/NGSI-v2/services\">services</a> Bash script provided within the\nrepository:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">./services start\n</code></pre>\n<blockquote>\n<p>:information_source: <strong>Note:</strong> If you want to clean up and start over again you can do so with the following command:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">./services stop\n</code></pre>\n</blockquote>\n<h1 id=\"connecting-fiware-to-a-cratedb-database-via-quantumleap\">Connecting FIWARE to a CrateDB Database via QuantumLeap</h1>\n<p>In the configuration, <strong>QuantumLeap</strong> listens to NGSI LD notifications on port <code>8868</code> and persists historic context data\nto the <strong>CrateDB</strong>. <strong>CrateDB</strong> is accessible using port <code>4200</code> and can either be queried directly or attached to the\nGrafana analytics tool. The rest of the system providing the context data has been described in previous tutorials</p>\n<h2 id=\"cratedb-database-server-configuration\">CrateDB Database Server Configuration</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-yaml\">crate-db:\n    image: crate:4.1.4\n    hostname: crate-db\n    ports:\n        - \"4200:4200\"\n        - \"4300:4300\"\n    command:\n        crate -Clicense.enterprise=false -Cauth.host_based.enabled=false  -Ccluster.name=democluster\n        -Chttp.cors.enabled=true -Chttp.cors.allow-origin=\"*\"\n    environment:\n        - CRATE_HEAP_SIZE=2g\n</code></pre>\n<p>If CrateDB exits immediately with a\n<code>max virtual memory areas vm.max_map_filling [65530] is too low, increase to at least [262144]</code> error, this can be fixed\nby running the <code>sudo sysctl -w vm.max_map_filling=262144</code> command on the host machine. For further information look\nwithin the CrateDB\n<a href=\"https://crate.io/docs/crate/howtos/en/latest/admin/bootstrap-checks.html#bootstrap-checks\">documentation</a> and Docker\n<a href=\"https://crate.io/docs/crate/howtos/en/latest/deployment/containers/docker.html#troubleshooting\">troubleshooting guide</a></p>\n<h2 id=\"quantumleap-configuration\">QuantumLeap Configuration</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-yaml\">quantumleap:\n    image: smartsdk/quantumleap\n    hostname: quantumleap\n    ports:\n        - \"8668:8668\"\n    depends_on:\n        - crate-db\n    environment:\n        - CRATE_HOST=crate-db\n</code></pre>\n<h2 id=\"grafana-configuration\">Grafana Configuration</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-yaml\">grafana:\n    image: grafana/grafana\n    depends_on:\n        - cratedb\n    ports:\n        - \"3003:3000\"\n    environment:\n        - GF_INSTALL_PLUGINS=https://github.com/orchestracities/grafana-map-plugin/archive/master.zip;grafana-map-plugin,grafana-clock-panel,grafana-worldmap-panel\n</code></pre>\n<p>The <code>quantumleap</code> container is listening on one port:</p>\n<ul>\n<li>The Operations for port for QuantumLeap - <code>8668</code> is where the service will be listening for notifications from the\nOrion context broker and where users can query data from.</li>\n</ul>\n<p>The <code>CRATE_HOST</code> environment variable defines the location where the data will be persisted.</p>\n<p>The <code>cratedb</code> container is listening on two ports:</p>\n<ul>\n<li>The Admin UI is available on port <code>4200</code></li>\n<li>The transport protocol is available on <code>port 4300</code></li>\n</ul>\n<p>The <code>grafana</code> container has connected up port <code>3000</code> internally with port <code>3003</code> externally. This is because the Grafana\nUI is usually available on port <code>3000</code>, but this port has already been taken by the dummy devices UI so it has been\nshifted to another port. The Grafana Environment variables are described within their own\n<a href=\"https://grafana.com/docs/installation/configuration/\">documentation</a>. The configuration ensures we will be able to\nconnect to the <strong>CrateDB</strong> database later on in the tutorial. The configuration also imports a custom map plugin that\nhelps you in displaying NGSI v2 entities over a map.</p>\n<h3 id=\"generating-context-data\">Generating Context Data</h3>\n<p>For the purpose of this tutorial, we must be monitoring a system where the context is periodically being updated. The\ndummy IoT Sensors can be used to do this.</p>\n<p>Details of various buildings around the farm can be found in the tutorial application. Open\n<code>http://localhost:3000/app/farm/urn:ngsi-ld:Building:farm001</code> to display a building with an associated filling sensor\nand thermostat.</p>\n<p><img src=\"https://fiware.github.io/tutorials.Subscriptions/img/fmis.png\" alt=\"\"></p>\n<p>Remove some hay from the barn, update the thermostat and open the device monitor page at\n<code>http://localhost:3000/device/monitor</code> and start a <strong>Tractor</strong> and switch on a <strong>Smart Lamp</strong>. This can be done by\nselecting an appropriate command from the drop down list and pressing the <code>send</code> button. The stream of measurements\ncoming from the devices can then be seen on the same page.</p>\n</body></html>","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","toc":[{"content":"Architecture","slug":"architecture"},{"content":"Prerequisites","slug":"prerequisites"},{"content":"Start Up","slug":"start-up"},{"content":"Connecting FIWARE to a CrateDB Database via QuantumLeap","slug":"connecting-fiware-to-a-cratedb-database-via-quantumleap"}],"owner":"513743","collectionId":"17fa5c4e-3836-49ce-8769-df5e9bba674e","publishedId":"TWDUpxxx","public":true,"customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"233c68"},"publishDate":"2021-02-17T10:17:37.000Z"},"item":[{"name":"Setting up Subscriptions","item":[{"name":"Orion - QuantumLeap - Aggregate Filling Sensor filling Events","id":"542396b8-0fd3-4a52-8e8a-0087652ae877","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"NGSILD-Tenant","value":"openiot"},{"key":"fiware-servicepath","value":"/"},{"key":"Link","value":"<http://context/ngsi-context.jsonld>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"}],"body":{"mode":"raw","raw":"{\n  \"description\": \"Notify me of all feedstock changes\",\n  \"type\": \"Subscription\",\n  \"entities\": [{\"type\": \"FillingLevelSensor\"}],\n  \"watchedAttributes\": [\"filling\"],\n  \"notification\": {\n    \"attributes\": [\"filling\", \"location\"],\n    \"format\": \"normalized\",\n    \"endpoint\": {\n      \"uri\": \"http://quantumleap:8668/v2/notify\",\n      \"accept\": \"application/json\",\n      \"receiverInfo\": [\n          {\"key\": \"fiware-service\", \"value\": \"openiot\"}\n      ]\n    }\n  }\n}"},"url":"http://localhost:1026/ngsi-ld/v1/subscriptions/","description":"<p>The rate of change of the <strong>Filling Sensor</strong> is driven by events in the real-world. We need to receive every event to be\nable to aggregate the results.</p>\n<p>This is done by making a POST request to the <code>/ngsi-ld/v1/subscriptions/</code> endpoint of the <strong>Orion-LD Context Broker</strong>.</p>\n<ul>\n<li>The <code>NGSILD-Tenant</code> headers is used to filter the subscription to only listen to measurements from the attached IoT\nSensors</li>\n<li>The <code>entities</code> <code>type</code> in the request body ensures that <strong>QuantumLeap</strong> will be informed of all <strong>FillingSensor</strong>\ndata changes.</li>\n<li>The <code>notification</code> URL must match the exposed port.</li>\n</ul>\n<p>With NGSI-LD the <code>observedAt</code> <em>property-of-property</em> holds the timestamp of the measure. Because the attribute being\nmonitored contains this <em>property-of-property</em>, the <code>time_index</code> column within the <strong>CrateDB</strong> database will match the\ndata found within the <strong>MongoDB</strong> database used by the <strong>Orion Context Broker</strong> rather than using the creation time of\nthe record within the <strong>CrateDB</strong> itself.</p>\n","urlObject":{"protocol":"http","path":["ngsi-ld","v1","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"542396b8-0fd3-4a52-8e8a-0087652ae877"},{"name":"Orion - QuantumLeap - Sample GPS Readings","id":"9ac80bef-050b-46dd-80a9-17365712c347","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"NGSILD-Tenant","value":"openiot"},{"key":"fiware-servicepath","value":"/"},{"key":"Link","value":"<http://context/ngsi-context.jsonld>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"}],"body":{"mode":"raw","raw":"{\n  \"description\": \"Notify me of animal locations\",\n  \"type\": \"Subscription\",\n  \"entities\": [{\"type\": \"Device\"}],\n  \"watchedAttributes\": [\"location\", \"status\", \"heartRate\"],\n  \"notification\": {\n    \"attributes\": [\"location\", \"status\", \"heartRate\"],\n    \"format\": \"normalized\",\n    \"endpoint\": {\n      \"uri\": \"http://quantumleap:8668/v2/notify\",\n      \"accept\": \"application/json\",\n      \"receiverInfo\": [\n          {\"key\": \"fiware-service\", \"value\": \"openiot\"}\n      ]\n    }\n  },\n   \"throttling\": 10\n}"},"url":"http://localhost:1026/ngsi-ld/v1/subscriptions/","description":"<p>The heart rate and GPS reading of the Animal Collars on the animals on the farm are constantly changing, we only need to\nsample the values to be able to work out relevant statistics such as minimum and maximum values and rates of change.</p>\n<p>This is done by making a POST request to the <code>/ngsi-ld/v1/subscriptions/</code> endpoint of the <strong>Orion Context Broker</strong> and\nincluding the <code>throttling</code> attribute in the request body.</p>\n<ul>\n<li>The <code>NGSILD-Tenant</code> headers is used to filter the subscription to only listen to measurements from the attached IoT\nSensors</li>\n<li>The <code>entities</code> <code>type</code> in the request body ensures that <strong>QuantumLeap</strong> will be informed of all <strong>Device</strong> data\nchanges.</li>\n<li>The <code>notification</code> URL must match the exposed port.</li>\n<li>The <code>throttling</code> value defines the rate that changes are sampled.</li>\n</ul>\n","urlObject":{"protocol":"http","path":["ngsi-ld","v1","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"9ac80bef-050b-46dd-80a9-17365712c347"},{"name":"Orion - Check Subscription is working","id":"f6725b7c-5ea3-437b-aef2-73db48bb0560","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"NGSILD-Tenant","value":"openiot"},{"key":"fiware-servicepath","value":"/"},{"key":"Link","value":"<http://context/ngsi-context.jsonld>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"}],"url":"http://localhost:1026/ngsi-ld/v1/subscriptions/","description":"<p>Before anything, check the subscriptions you created in steps one and two are working (i.e., at least one\nnotification for each was sent).</p>\n","urlObject":{"protocol":"http","path":["ngsi-ld","v1","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"f6725b7c-5ea3-437b-aef2-73db48bb0560"}],"id":"ab92a669-5e8d-47f8-a00f-3c6db86b01c9","description":"<p>Once a dynamic context system is up and running, we need to inform <strong>Quantum\nLeap</strong> directly of changes in context. As expected this is done using the\nsubscription mechanism of the <strong>Orion Context Broker</strong>. The <code>attrsFormat=legacy</code>\nattribute is not required since <strong>QuantumLeap</strong> accepts NGSI v2 notifications\ndirectly.</p>\n<p>Subscriptions will be covered in the next subsections. More details about\nsubscriptions can be found in previous tutorials or in the\n<a href=\"https://quantumleap.readthedocs.io/en/latest/user/#orion-subscription\">subscriptions section</a>\nof QuantumLeap docs.</p>\n","event":[{"listen":"prerequest","script":{"id":"4f9ade89-f6d9-47bb-b212-13bf4fb6c606","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"8957dc7f-7d70-4126-af3d-6d39c1a9744a","type":"text/javascript","exec":[""]}}],"_postman_id":"ab92a669-5e8d-47f8-a00f-3c6db86b01c9"},{"name":"Time Series Data Queries (QuantumLeap API)","item":[{"name":"QuantumLeap - Obtain version information","id":"b1152caa-fdaa-4390-88f7-c118e9c158cd","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"http://localhost:8668/version","urlObject":{"protocol":"http","path":["version"],"host":["localhost:8668"],"query":[],"variable":[]}},"response":[],"_postman_id":"b1152caa-fdaa-4390-88f7-c118e9c158cd"},{"name":"List the first N Sampled Values","id":"326f8199-6dbd-4963-a8a5-5d1fe153be56","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Accept","value":"application/json"},{"key":"Fiware-Service","value":"openiot","type":"text"}],"body":{"mode":"raw","raw":""},"url":"http://localhost:8668/v2/entities/urn:ngsi-ld:FillingLevelSensor:filling001/attrs/filling?limit=3","description":"<p>This example shows the first 3 sampled <code>luminosity</code> values from <code>Lamp:001</code>. </p>\n<p>Note the use of <code>Fiware-Service</code> and <code>Fiware-ServicePath</code> headers. These are\nrequired only when data are pushed to orion using such headers (in multitenancy\nscenarios). Failing to align these headers will result in no data being\nreturned.</p>\n","urlObject":{"protocol":"http","path":["v2","entities","urn:ngsi-ld:FillingLevelSensor:filling001","attrs","filling"],"host":["localhost:8668"],"query":[{"key":"limit","value":"3"}],"variable":[]}},"response":[],"_postman_id":"326f8199-6dbd-4963-a8a5-5d1fe153be56"},{"name":"List N Sampled Values at an Offset","id":"8087621b-9124-49df-9822-935379d4c637","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Accept","value":"application/json"},{"key":"Fiware-Service","value":"openiot","type":"text"}],"body":{"mode":"raw","raw":""},"url":"http://localhost:8668/v2/entities/urn:ngsi-ld:FillingLevelSensor:filling001/attrs/filling?limit=6&offset=3","description":"<p>This example shows the fourth, fifth and sixth sampled count values from Motion:001.</p>\n","urlObject":{"protocol":"http","path":["v2","entities","urn:ngsi-ld:FillingLevelSensor:filling001","attrs","filling"],"host":["localhost:8668"],"query":[{"key":"limit","value":"6"},{"key":"offset","value":"3"}],"variable":[]}},"response":[],"_postman_id":"8087621b-9124-49df-9822-935379d4c637"},{"name":"List the latest N Sampled Values","id":"d142d0d8-2401-4111-bc4f-e0351497f06d","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Accept","value":"application/json"},{"key":"Fiware-Service","value":"openiot","type":"text"}],"body":{"mode":"raw","raw":""},"url":"http://localhost:8668/v2/entities/urn:ngsi-ld:Device:filling001/attrs/filling?lastN=3","description":"<p>This example shows latest three sampled <code>count</code> values from <code>Motion:001</code>.</p>\n","urlObject":{"protocol":"http","path":["v2","entities","urn:ngsi-ld:Device:filling001","attrs","filling"],"host":["localhost:8668"],"query":[{"key":"lastN","value":"3"}],"variable":[]}},"response":[],"_postman_id":"d142d0d8-2401-4111-bc4f-e0351497f06d"},{"name":"List the Sum of values over a time period","id":"d57b07f5-19f5-4fc9-beac-c14e554100a8","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Accept","value":"application/json"},{"key":"Fiware-Service","value":"openiot","type":"text"}],"body":{"mode":"raw","raw":""},"url":"http://localhost:8668/v2/entities/urn:ngsi-ld:FillingLevelSensor:filling001/attrs/filling?aggrMethod=count&aggrPeriod=minute&lastN=3","description":"<p>This example shows total <code>count</code> values from <code>Motion:001</code> over each minute.</p>\n<p>You need QuantumLeap <strong>version &gt;= 0.4.1</strong>. You can check your version with a\nsimple GET like:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>curl -X GET \\\n  'http://localhost:8668/v2/version' \\\n  -H 'Accept: application/json'\n</code></pre>","urlObject":{"protocol":"http","path":["v2","entities","urn:ngsi-ld:FillingLevelSensor:filling001","attrs","filling"],"host":["localhost:8668"],"query":[{"key":"aggrMethod","value":"count"},{"key":"aggrPeriod","value":"minute"},{"key":"lastN","value":"3"}],"variable":[]}},"response":[],"_postman_id":"d57b07f5-19f5-4fc9-beac-c14e554100a8"},{"name":"List the Minimum Values over a Time Period","id":"a152aa06-e585-4438-b2f4-d4d604310fb8","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Accept","value":"application/json"},{"key":"Fiware-Service","value":"openiot","type":"text"}],"body":{"mode":"raw","raw":""},"url":"http://localhost:8668/v2/entities/urn:ngsi-ld:FillingLevelSensor:filling001/attrs/filling?aggrMethod=min&aggrPeriod=minute&lastN=3","description":"<p>This example shows minimum <code>luminosity</code> values from <code>Lamp:001</code> over each minute.</p>\n<p>You need QuantumLeap <strong>version &gt;= 0.4.1</strong>. You can check your version with a\nsimple GET like:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">curl -X GET \\\n  'http://localhost:8668/v2/version' \\\n  -H 'Accept: application/json'\n</code></pre>\n","urlObject":{"protocol":"http","path":["v2","entities","urn:ngsi-ld:FillingLevelSensor:filling001","attrs","filling"],"host":["localhost:8668"],"query":[{"key":"aggrMethod","value":"min"},{"key":"aggrPeriod","value":"minute"},{"key":"lastN","value":"3"}],"variable":[]}},"response":[],"_postman_id":"a152aa06-e585-4438-b2f4-d4d604310fb8"},{"name":"List the Maximum Values over a Time Period","id":"b59a4a94-4bc8-4085-8d2c-80173270a08c","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Content-Type","value":"application/json"},{"key":"Fiware-Service","value":"openiot","type":"text"}],"body":{"mode":"raw","raw":""},"url":"http://localhost:8668/v2/entities/urn:ngsi-ld:FillingLevelSensor:filling001/attrs/filling?aggrMethod=max&aggrPeriod=minute&lastN=3","description":"<p>This example shows maximum <code>luminosity</code> value of <code>Lamp:001</code> that occurred\nbetween from <code>2018-06-27T09:00:00</code> to <code>2018-06-30T23:59:59</code>.</p>\n<p>Alter the <code>fromDate</code> and <code>toDate</code> parameters to retrieve your current data</p>\n","urlObject":{"protocol":"http","path":["v2","entities","urn:ngsi-ld:FillingLevelSensor:filling001","attrs","filling"],"host":["localhost:8668"],"query":[{"key":"aggrMethod","value":"max"},{"key":"aggrPeriod","value":"minute"},{"key":"lastN","value":"3"}],"variable":[]}},"response":[],"_postman_id":"b59a4a94-4bc8-4085-8d2c-80173270a08c"},{"name":"List the latest N Sampled Values of Devices near a Point","id":"38aeb194-de13-42bb-a32d-e5aec3527617","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Content-Type","value":"application/json"},{"key":"Fiware-Service","type":"text","value":"openiot"}],"body":{"mode":"raw","raw":""},"url":"http://localhost:8668/v2/types/Device/attrs/heartRate?lastN=4&georel=near;maxDistance:5000&geometry=point&coords=52.518,13.357","description":"<p>This example shows the latest four sampled <code>luminosity</code> values of lamps that\nare within a 5 km radius from <code>52°33'16.9\"N 13°23'55.0\"E</code> (Bornholmer Straße\n65, Berlin, Germany). If you have turned on all the lamps available on the\ndevice monitor page, you should be able to see data for <code>Lamp:001</code> and\n<code>Lamp:004</code>.</p>\n<blockquote>\n<p><strong>Note:</strong> Geographical queries are only available\nstarting from version <code>0.5</code> of QuantumLeap which implements the full\nset of queries detailed in the Geographical Queries section of the\n<a href=\"http://fiware.github.io/specifications/ngsiv2/stable/\">NGSI v2 specification</a>.</p>\n</blockquote>\n","urlObject":{"protocol":"http","path":["","v2","types","Device","attrs","heartRate"],"host":["localhost:8668"],"query":[{"key":"lastN","value":"4"},{"key":"georel","value":"near;maxDistance:5000"},{"key":"geometry","value":"point"},{"key":"coords","value":"52.518,13.357"}],"variable":[]}},"response":[],"_postman_id":"38aeb194-de13-42bb-a32d-e5aec3527617"},{"name":"List the latest N Sampled Values of Devices in an Area","id":"3130098c-4190-4c60-b274-3878b927a214","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Content-Type","value":"application/json"},{"key":"Fiware-Service","type":"text","value":"openiot"}],"body":{"mode":"raw","raw":""},"url":"http://localhost:8668/v2/types/Device/attrs/heartRate?lastN=4&georel=coveredBy&geometry=polygon&coords=52.5537,13.3996;52.5557,13.3996;52.5557,13.3976;52.5537,13.3976;52.5537,13.3996","description":"<p>This example shows the latest four sampled <code>luminosity</code> values of lamps that\nare inside a square of side 200 m centred at <code>52°33'16.9\"N 13°23'55.0\"E</code>\n(Bornholmer Straße 65, Berlin, Germany). Even if you have turned on all the\nlamps available on the device monitor page, you should only see data for\n<code>Lamp:001</code>.</p>\n<blockquote>\n<p><strong>Note:</strong> Geographical queries are only available\nstarting from version <code>0.5</code> of QuantumLeap which implements the full\nset of queries detailed in the Geographical Queries section of the\n<a href=\"http://fiware.github.io/specifications/ngsiv2/stable/\">NGSI v2 specification</a>.</p>\n</blockquote>\n","urlObject":{"protocol":"http","path":["v2","types","Device","attrs","heartRate"],"host":["localhost:8668"],"query":[{"key":"lastN","value":"4"},{"key":"georel","value":"coveredBy"},{"key":"geometry","value":"polygon"},{"key":"coords","value":"52.5537,13.3996;52.5557,13.3996;52.5557,13.3976;52.5537,13.3976;52.5537,13.3996"}],"variable":[]}},"response":[],"_postman_id":"3130098c-4190-4c60-b274-3878b927a214"}],"id":"fd447cb1-1962-4079-bda7-1f631d9eb781","description":"<p><strong>CrateDB</strong> offers an\n<a href=\"https://crate.io/docs/crate/reference/en/latest/interfaces/http.html\">HTTP Endpoint</a>\nthat can be used to submit SQL queries. The endpoint is accessible under\n<code>&lt;servername:port&gt;/_sql</code>.</p>\n<p>SQL statements are sent as the body of POST requests in JSON format, where the\nSQL statement is the value of the <code>stmt</code> attribute.</p>\n<blockquote>\n<p>When to query <strong>CrateDB</strong> and when <strong>QuantumLeap</strong>?. As a rule of thumb,\nprefer working always with <strong>QuantumLeap</strong> for the following reasons:</p>\n<ul>\n<li>Your experience will be closer to FIWARE NGSI APIs like Orion's.</li>\n<li>Your application will not be tied to CrateDB's specifics nor QuantumLeap's\nimplementation details, which could change and break your app.</li>\n<li>QuantumLeap can be easily extended to other backends and your app will get\ncompatibility for free.</li>\n<li>If your deployment is distributed, you won't need to expose the ports of\nyour database to the outside.</li>\n</ul>\n</blockquote>\n<p>If your are sure your query is not supported by <strong>QuantumLeap</strong>, you may have to\nend up querying <strong>CrateDB</strong>, however, please open an issue in\n<a href=\"https://github.com/smartsdk/ngsi-timeseries-api/issues\">QuantumLeap's repo</a> so\nthe team is aware.</p>\n","event":[{"listen":"prerequest","script":{"id":"019f1ccb-6a46-4caa-adf6-fc3c4236f789","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"ba05f53d-adef-4a40-a2d7-cd4a32edc172","type":"text/javascript","exec":[""]}}],"_postman_id":"fd447cb1-1962-4079-bda7-1f631d9eb781"},{"name":"Time Series Data Queries (Crate-DB)","item":[{"name":"Read Schemas","id":"4900121c-04c0-43fe-96a9-fd3815c35044","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"stmt\":\"SHOW SCHEMAS\"}"},"url":"http://localhost:4200/_sql","description":"<p>Another way to see if data are being persisted is to check if a <code>table_schema</code>\nhas been created. This can be done by making a request to the <strong>CrateDB</strong> HTTP\nendpoint as shown below.</p>\n<p>Schema names are formed with the <code>mt</code> prefix followed by <code>fiware-service</code> header\nin lower case. The IoT Agent is forwarding measurements from the dummy IoT\ndevices, with the <code>FIWARE-Service</code> header <code>openiot</code>. These are being persisted\nunder the <code>mtopeniot</code> schema.</p>\n<p>If the <code>mtopeniot</code> does not exist, then the subscription to <strong>QuantumLeap</strong> has\nnot been set up correctly. Check that the subscription exists, and has been\nconfigured to send data to the correct location.</p>\n","urlObject":{"protocol":"http","path":["_sql"],"host":["localhost:4200"],"query":[],"variable":[]}},"response":[],"_postman_id":"4900121c-04c0-43fe-96a9-fd3815c35044"},{"name":"Read Tables","id":"9e55e4b4-a44f-4726-9f18-17f085a32b99","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"stmt\":\"SHOW TABLES\"}"},"url":"http://localhost:4200/_sql","description":"<p><strong>Quantum Leap</strong> will persist data into separate tables within the Crate-DB database based on the entity type. Table names are formed with the <code>et</code> prefix and the entity type name in lowercase.</p>\n<p>The response shows that both <strong>Motion Sensor</strong> data and <strong>Smart Lamp</strong> data are being persisted in the database.</p>\n","urlObject":{"protocol":"http","path":["_sql"],"host":["localhost:4200"],"query":[],"variable":[]}},"response":[],"_postman_id":"9e55e4b4-a44f-4726-9f18-17f085a32b99"},{"name":"List the first N Sampled Values","id":"9b695415-8755-4fdb-853b-d72a04febc7a","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"stmt\":\"SELECT * FROM mtopeniot.etfillinglevelsensor WHERE entity_id = 'urn:ngsi-ld:Device:filling001'  ORDER BY time_index ASC LIMIT 3\"}"},"url":"http://localhost:4200/_sql","description":"<p>This example shows the first 3 sampled <code>luminosity</code> values from <code>Lamp:001</code>. </p>\n<p>The SQL statement uses <code>ORDER BY</code> and <code>LIMIT</code> clauses to sort the data. More details can be found under within the Crate-DB <a href=\"https://crate.io/docs/crate/reference/en/latest/sql/statements/select.html\">documentation</a></p>\n","urlObject":{"protocol":"http","path":["_sql"],"host":["localhost:4200"],"query":[],"variable":[]}},"response":[],"_postman_id":"9b695415-8755-4fdb-853b-d72a04febc7a"},{"name":"List N Sampled Values at an Offset","id":"d221572c-737c-4662-878c-e56e42915d21","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"stmt\":\"SELECT * FROM mtopeniot.etdevice WHERE entity_id = 'urn:ngsi-ld:Device:pig001' ORDER BY time_index ASC  LIMIT 3 OFFSET 3\"}"},"url":"http://localhost:4200/_sql","description":"<p>This example shows the fourth, fifth and sixth sampled count values from Motion:001.</p>\n<p>The SQL statement uses an <code>OFFSET</code> clause to retrieve the required rows. \nMore details can be found under within the Crate-DB <a href=\"https://crate.io/docs/crate/reference/en/latest/sql/statements/select.html\">documentation</a></p>\n","urlObject":{"protocol":"http","path":["_sql"],"host":["localhost:4200"],"query":[],"variable":[]}},"response":[],"_postman_id":"d221572c-737c-4662-878c-e56e42915d21"},{"name":"List the latest N Sampled Values","id":"4ef1e918-d19d-41e7-a9c4-c8b996964aa1","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"stmt\":\"SELECT * FROM mtopeniot.etdevice WHERE entity_id = 'urn:ngsi-ld:Device:pig001'  ORDER BY time_index DESC LIMIT 3\"}"},"url":"http://localhost:4200/_sql","description":"<p>This example shows latest three sampled <code>count</code> values from <code>Motion:001</code>. </p>\n<p>The SQL statement uses an <code>ORDER BY ... DESC</code> clause combined with a <code>LIMIT</code> clause to retrieve \nthe last N rows. More details can be found under within the Crate-DB <a href=\"https://crate.io/docs/crate/reference/en/latest/sql/statements/select.html\">documentation</a></p>\n","urlObject":{"protocol":"http","path":["_sql"],"host":["localhost:4200"],"query":[],"variable":[]}},"response":[],"_postman_id":"4ef1e918-d19d-41e7-a9c4-c8b996964aa1"},{"name":"List the Sum of values over a time period","id":"cad12fea-3874-4011-b5ad-2c26b6dcf85f","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"stmt\":\"SELECT DATE_FORMAT (DATE_TRUNC ('minute', time_index)) AS minute, SUM (heartRate) AS sum FROM mtopeniot.etdevice WHERE entity_id = 'urn:ngsi-ld:Device:pig001' GROUP BY minute ORDER BY minute\"}"},"url":"http://localhost:4200/_sql","description":"<p>This example shows total <code>count</code> values from <code>Motion:001</code> over each minute.</p>\n<p>The SQL statement uses a <code>SUM</code> function and <code>GROUP BY</code> clause to retrieve the relevant data.\nCrate-DB offers a range of <a href=\"https://crate.io/docs/crate/reference/en/latest/general/builtins/scalar.html#date-and-time-functions\">Date-Time Function</a> to truncate and convert the timestamps into data which can be grouped.</p>\n","urlObject":{"protocol":"http","path":["_sql"],"host":["localhost:4200"],"query":[],"variable":[]}},"response":[],"_postman_id":"cad12fea-3874-4011-b5ad-2c26b6dcf85f"},{"name":"List the Minimum Values over a Time Period","id":"d560b175-2b44-4ece-b3ea-466d13c1ce5f","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"stmt\":\"SELECT DATE_FORMAT (DATE_TRUNC ('minute', time_index)) AS minute, MIN (heartRate) AS min FROM mtopeniot.etdevice WHERE entity_id = 'urn:ngsi-ld:Device:pig001' GROUP BY minute ORDER BY minute\"}"},"url":"http://localhost:4200/_sql","description":"<p>This example shows minimum <code>luminosity</code> values from <code>Lamp:001</code> over each minute.</p>\n<p>The SQL statement uses a <code>MIN</code> function and <code>GROUP BY</code> clause to retrieve the relevant data.\nCrate-DB offers a range of <a href=\"https://crate.io/docs/crate/reference/en/latest/general/builtins/scalar.html#date-and-time-functions\">Date-Time Function</a> to truncate and convert the timestamps into data which can be grouped.</p>\n","urlObject":{"protocol":"http","path":["_sql"],"host":["localhost:4200"],"query":[],"variable":[]}},"response":[],"_postman_id":"d560b175-2b44-4ece-b3ea-466d13c1ce5f"},{"name":"List the Maximum Values over a Time Period","id":"17567d98-8b11-49c6-8e96-b9b2d6ca8726","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"stmt\":\"SELECT DATE_FORMAT (DATE_TRUNC ('minute', time_index)) AS minute, MAX (filling) AS max FROM mtopeniot.etfillinglevelsensor WHERE entity_id = 'urn:ngsi-ld:Device:filling001' GROUP BY minute ORDER BY minute\"}"},"url":"http://localhost:4200/_sql","description":"<p>This example shows maximum <code>luminosity</code> values from <code>Lamp:001</code> over each minute.</p>\n<p>The SQL statement uses a <code>MAX</code> function and <code>GROUP BY</code> clause to retrieve the relevant data.\nCrate-DB offers a range of <a href=\"https://crate.io/docs/crate/reference/en/latest/general/builtins/scalar.html#date-and-time-functions\">Date-Time Function</a> to truncate and convert the timestamps into data which can be grouped.</p>\n","urlObject":{"protocol":"http","path":["_sql"],"host":["localhost:4200"],"query":[],"variable":[]}},"response":[],"_postman_id":"17567d98-8b11-49c6-8e96-b9b2d6ca8726"},{"name":"List the Average Values over a Time Period","id":"ef4fee51-b640-4d8b-8c01-f2234f2d2f6a","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"body":{"mode":"raw","raw":"{\"stmt\":\"SELECT DATE_FORMAT (DATE_TRUNC ('minute', time_index)) AS minute, AVG (filling) AS average FROM mtopeniot.etfillinglevelsensor WHERE entity_id = 'urn:ngsi-ld:Device:filling001' GROUP BY minute ORDER BY minute\"}"},"url":"http://localhost:4200/_sql","description":"<p>This example shows the average of <code>luminosity</code> values from <code>Lamp:001</code> over each minute.</p>\n<p>The SQL statement uses a <code>AVG</code> function and <code>GROUP BY</code> clause to retrieve the relevant data.\nCrate-DB offers a range of <a href=\"https://crate.io/docs/crate/reference/en/latest/general/builtins/scalar.html#date-and-time-functions\">Date-Time Function</a> to truncate and convert the timestamps into data which can be grouped.</p>\n","urlObject":{"protocol":"http","path":["_sql"],"host":["localhost:4200"],"query":[],"variable":[]}},"response":[],"_postman_id":"ef4fee51-b640-4d8b-8c01-f2234f2d2f6a"}],"id":"5ebd35e9-b623-41d8-9ced-ca1d8c5cc6cd","description":"<p><strong>Crate-DB</strong> offers an <a href=\"https://crate.io/docs/crate/reference/en/latest/interfaces/http.html\">HTTP Endpoint</a> that can be used to submit SQL queries. The endpoint is accessible under <code>&lt;servername:port&gt;/_sql</code>.</p>\n<p>SQL statements are sent as the body of POST requests in JSON format, where the SQL statement is the value of the <code>stmt</code> attribute.</p>\n","event":[{"listen":"prerequest","script":{"id":"cd1d8a3c-c46c-4da9-acfb-adfcc8262355","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"55b45dca-47e0-4050-b768-58c1fee4a013","type":"text/javascript","exec":[""]}}],"_postman_id":"5ebd35e9-b623-41d8-9ced-ca1d8c5cc6cd"}],"event":[{"listen":"prerequest","script":{"id":"d6e8406b-533a-44c4-a4e4-da3ff826cbd7","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"95081506-fa55-48b9-ae93-9c921054df17","type":"text/javascript","exec":[""]}}],"variable":[{"key":"orion","value":"localhost:1026"},{"key":"quantumleap","value":"localhost:8668"},{"key":"crate","value":"localhost:4200"},{"key":"ngsi-context.jsonld","value":"http://context/ngsi-context.jsonld","type":"string"}]}