{"info":{"_postman_id":"30f69661-209c-43fb-bd7c-d1f1c055731c","name":"FIWARE Persisting Context Data (Apache Flume)","description":"<html><head></head><body><p>This tutorial is an introduction to <a href=\"http://fiware-cygnus.readthedocs.io/en/latest/\">FIWARE Cygnus</a> - a generic enabler which is used to persist context data into third-party databases creating a historical view of the context. The tutorial activates the IoT sensors connected in the <a href=\"https://github.com/Fiware/tutorials.IoT-Agent\">previous tutorial</a> and persists measurements\nfrom those sensors into a database for further analysis.</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.Historic-Context-Flume/icon/GitHub-Mark-32px.png\" alt=\"GitHub\"> <a href=\"https://github.com/Fiware/tutorials.Historic-Context-Flume\">FIWARE 301: Persisting Context Data</a></p>\n<h1 id=\"data-persistence\">Data Persistence</h1>\n<blockquote>\n<p>\"History will be kind to me for I intend to write it.\"</p>\n<p>— Winston Churchill</p>\n</blockquote>\n<p>Previous tutorials have introduced a set of IoT Sensors (providing measurements of the\nstate of the real world), and two FIWARE Components - the <strong>Orion Context Broker</strong> and an <strong>IoT Agent</strong>. \nThis tutorial will introduct a new data persistance component - FIWARE <strong>Cygnus</strong>.</p>\n<p>The system so far has been built up to handle the current context, in other words it holds the data entities\ndefining the state of the real-world objects at a given moment in time.</p>\n<p>From this definition you can see - context is only interested in the <strong>current</strong> state of the system\nIt is not the responsibility of any of the existing components to report on the historical state of the system,\nthe context is based on the last measurement each sensor has sent data to the context broker.</p>\n<p>In order to do this, we will need to extend the existing architecture to persist changes of state into a database whenever \nthe context is updated.</p>\n<p>Persisting historical context data is useful for big data analysis - it can be used to discover trends, or data \ncan be sampled and aggregated to remove the influence of outlying data measurements. However within each Smart Solution,\nthe significance of each entity type will differ and entities and attributes may need to be sampled at different rates.</p>\n<p>Since the business requirements for using context data differ from application to appliation, there is no one standard use \ncase  for historical data persistence - each situation is unique - it is not the case that one size fits all.\nTherefore rather than overloading the context broker with the job of historical context data persistence, this role has been\nseparated out into a separate, highly configurable component - <strong>Cygnus</strong>.</p>\n<p>As you would expect, <strong>Cygnus</strong>, as part of an Open Source platform, is technology agnostic regarding the database \nto be used for data persistance. The database you choose to use will depend upon your own business needs. </p>\n<p>However there is a cost to offering this flexibility - each part of the system must be separately configured and\nnotifications must be set up to only pass the minimal data required as necessary.</p>\n<h4 id=\"device-monitor\">Device Monitor</h4>\n<p>For the purpose of this tutorial, a series of dummy IoT devices have been created, which will be attached to the context broker.\nThe state of each device can be seen 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.Historic-Context-Flume/img/device-monitor.png\" alt=\"FIWARE Monitor\"></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 make use of three FIWARE components - \nthe <a href=\"https://fiware-orion.readthedocs.io/en/latest/\">Orion Context Broker</a>, the\n<a href=\"http://fiware-iotagent-ul.readthedocs.io/en/latest/\">IoT Agent for UltraLight 2.0</a> and introduce the\n<a href=\"http://fiware-cygnus.readthedocs.io/en/latest/\">Cygnus Generic Enabler</a> for persisting context data to a database.\nAdditional databases are now involved - both the Orion Context Broker and the IoT Agent rely on <a href=\"https://www.mongodb.com/\">MongoDB</a> technology to keep persistence of the information they hold, and we will be persisting our historical context data another database - either <strong>MySQL</strong> , <strong>PostgreSQL</strong>  or <strong>Mongo-DB</strong> database.</p>\n<p>Therefore the overall architecture will consist of the following elements:</p>\n<ul>\n<li>Three <strong>FIWARE Generic Enablers</strong>:<ul>\n<li>The FIWARE <a href=\"https://fiware-orion.readthedocs.io/en/latest/\">Orion Context Broker</a> which will receive requests using <a href=\"https://fiware.github.io/specifications/OpenAPI/ngsiv2\">NGSI</a></li>\n<li>The FIWARE <a href=\"http://fiware-iotagent-ul.readthedocs.io/en/latest/\">IoT Agent for UltraLight 2.0</a> which will receive southbound requests\nusing <a href=\"https://fiware.github.io/specifications/OpenAPI/ngsiv2\">NGSI</a> and convert them to \n<a href=\"http://fiware-iotagent-ul.readthedocs.io/en/latest/usermanual/index.html#user-programmers-manual\">UltraLight 2.0</a> commands for \nthe devices</li>\n<li>FIWARE <a href=\"http://fiware-cygnus.readthedocs.io/en/latest/\">Cygnus</a> which will subscribe to context changes and persist them into a database (<strong>MySQL</strong> , <strong>PostgreSQL</strong>  or <strong>Mongo-DB</strong>)</li>\n</ul>\n</li>\n<li>One, two or three of the following <strong>Databases</strong>:<ul>\n<li>The underlying <a href=\"https://www.mongodb.com/\">MongoDB</a> database :<ul>\n<li>Used by the <strong>Orion Context Broker</strong> to hold context data information such as data entities, subscriptions and registrations</li>\n<li>Used by the <strong>IoT Agent</strong> to hold device information such as device URLs and Keys</li>\n<li>Potentially used as a data sink to hold historical context data.</li>\n</ul>\n</li>\n<li>An additional <a href=\"https://www.postgresql.org/\">PostgreSQL</a> database :<ul>\n<li>Potentially used as a data sink to hold historical context data.</li>\n</ul>\n</li>\n<li>An additional <a href=\"https://www.mysql.com/\">MySQL</a> database :<ul>\n<li>Potentially used as a data sink to hold historical context data.</li>\n</ul>\n</li>\n</ul>\n</li>\n<li>Three <strong>Context Providers</strong>:<ul>\n<li>The <strong>Stock Management Frontend</strong> is not used in this tutorial. It does the following:<ul>\n<li>Display store information and allow users to interact with the dummy IoT devices</li>\n<li>Show which products can be bought at each store</li>\n<li>Allow users to \"buy\" products and reduce the stock count.</li>\n</ul>\n</li>\n<li>A webserver acting as set of <a href=\"https://github.com/Fiware/tutorials.IoT-Sensors\">dummy IoT devices</a> using the <a href=\"http://fiware-iotagent-ul.readthedocs.io/en/latest/usermanual/index.html#user-programmers-manual\">UltraLight 2.0</a> protocol running over HTTP.</li>\n<li>The <strong>Context Provider NGSI</strong> proxy is not used in this tutorial. It does the following:<ul>\n<li>receive requests using <a href=\"https://fiware.github.io/specifications/OpenAPI/ngsiv2\">NGSI</a></li>\n<li>makes requests to publicly available data sources using their own APIs in a proprietory format </li>\n<li>returns context data back to the Orion Context Broker in <a href=\"https://fiware.github.io/specifications/OpenAPI/ngsiv2\">NGSI</a> format.</li>\n</ul>\n</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 from exposed ports. </p>\n<p>The specific architecture of each section of the tutorial is discussed below.</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 run</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">./services create\n</code></pre>\n<blockquote>\n<p><strong>Note</strong> The <code>context-provider</code> image has not yet been pushed to Docker hub.\nFailing to build the Docker sources before proceeding will result in the following error:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>Pulling context-provider (fiware/cp-web-app:latest)...\nERROR: The image for the service you're trying to recreate has been removed.\n</code></pre></blockquote>\n<p>Thereafter, all services can be initialised from the command line by running the <a href=\"https://github.com/Fiware/tutorials.Historic-Context-Flume/blob/master/services\">services</a> Bash script provided within the repository:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">./services &lt;command&gt;\n</code></pre>\n<p>Where <code>&lt;command&gt;</code> will vary depending upon the databases we wish to activate.\nThis command will also import seed data from the previous tutorials and provision the dummy IoT sensors on startup.</p>\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</body></html>","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","toc":[{"content":"Data Persistence","slug":"data-persistence"},{"content":"Architecture","slug":"architecture"},{"content":"Start Up","slug":"start-up"}],"owner":"513743","collectionId":"30f69661-209c-43fb-bd7c-d1f1c055731c","publishedId":"RWEcR2DC","public":true,"customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"233C68"},"publishDate":"2020-01-02T11:05:59.000Z"},"item":[{"name":"Mongo DB - Persisting Context","item":[{"name":"Cygnus - Obtain version information","id":"5057efd4-669b-41c7-b7b3-23d5eb9729b8","request":{"method":"GET","header":[],"body":{"mode":"formdata","formdata":[]},"url":"http://localhost:5080/v1/version","description":"<p>Once Cygnus is running, You can check the status by making an HTTP request to the exposed <code>CYGNUS_API_PORT</code> port. \nIf the response is blank, this is usually because Cygnus is not running or is listening on another port.</p>\n<blockquote>\n<p><strong>Troubleshooting:</strong> What if the response is blank ?</p>\n<ul>\n<li>To check that a docker container is running try</li>\n</ul>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-bash\">docker ps\n</code></pre>\n<p>You should see several containers running. If <code>cygnus</code> is not running, you can restart the containers as necessary.</p>\n</blockquote>\n","urlObject":{"protocol":"http","path":["v1","version"],"host":["localhost:5080"],"query":[],"variable":[]}},"response":[],"_postman_id":"5057efd4-669b-41c7-b7b3-23d5eb9729b8"},{"name":"Orion - Subscribe to Context Changes","id":"13434c50-eae0-4366-8d5d-b44a2d0b7e4e","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"fiware-service","value":"openiot"},{"key":"fiware-servicepath","value":"/"}],"body":{"mode":"raw","raw":"{\n  \"description\": \"Notify Cygnus of all context changes\",\n  \"subject\": {\n    \"entities\": [\n      {\n        \"idPattern\": \".*\"\n      }\n    ]\n  },\n  \"notification\": {\n    \"http\": {\n      \"url\": \"http://cygnus:5051/notify\"\n    }\n  },\n  \"throttling\": 5\n}"},"url":"http://localhost:1026/v2/subscriptions/","description":"<p>Once a dynamic context system is up and running, we need to inform <strong>Cygnus</strong> of changes in context.</p>\n<p>This is done by making a POST request to the <code>/v2/subscription</code> endpoint of the Orion Context Broker.</p>\n<ul>\n<li>The <code>fiware-service</code> and <code>fiware-servicepath</code> headers are used to filter the subscription to only listen to measurements from the attached IoT Sensors</li>\n<li>The <code>idPattern</code> in the request body ensures that Cygnus will be informed of all context data changes.</li>\n<li>The notification <code>url</code> must match the configured <code>CYGNUS_MONGO_SERVICE_PORT</code></li>\n<li>The <code>attrsFormat=legacy</code> is required since Cygnus currently only accepts notifications in the older NGSI v1 format.</li>\n<li>The <code>throttling</code> value defines the rate that changes are sampled.</li>\n</ul>\n<p>As you can see, the database used to persist context data has no impact on the details of the subscription. It is the same for each database.</p>\n","urlObject":{"protocol":"http","path":["v2","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"13434c50-eae0-4366-8d5d-b44a2d0b7e4e"},{"name":"Orion - Check Subscription is working","id":"eb4be0c3-5563-444a-9539-c90ef2df0fda","request":{"method":"GET","header":[{"key":"fiware-service","value":"openiot"},{"key":"fiware-servicepath","value":"/"}],"body":{"mode":"raw","raw":""},"url":"http://localhost:1026/v2/subscriptions/","description":"<p>If a subscription has been created, you can check to see if it is firing by making a GET \nrequest to the <code>/v2/subscriptions</code> endpoint.</p>\n<p>Within the <code>notification</code> section of the response, you can see several additional <code>attributes</code> which describe the health of the subscription</p>\n<p>If the criteria of the subscription have been met, <code>timesSent</code> should be greater than <code>0</code>.\nA zero value would indicate that the <code>subject</code> of the subscription is incorrect or the subscription \nhas created with the wrong <code>fiware-service-path</code> or <code>fiware-service</code> header</p>\n<p>The <code>lastNotification</code> should be a recent timestamp - if this is not the case, then the devices\nare not regularly sending data. Remember to unlock the <strong>Smart Door</strong> and switch on the <strong>Smart Lamp</strong></p>\n<p>The <code>lastSuccess</code> should match the <code>lastNotification</code> date - if this is not the case \nthen <strong>Cygnus</strong> is not receiving the subscription properly. Check that the host name\nand port are correct. </p>\n<p>Finally, check that the <code>status</code> of the subscription is <code>active</code> - an expired subscription\nwill not fire.</p>\n","urlObject":{"protocol":"http","path":["v2","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"eb4be0c3-5563-444a-9539-c90ef2df0fda"}],"id":"63e10b25-c72c-425e-9bf6-372a39ce5284","description":"<p>Persisting historic context data using MongoDB technology is relatively simple to configure since\nwe are already using a MongoDB instance to hold data related to the Orion Context Broker and the\nIoT Agent. The MongoDB instance is listening on the standard <code>27017</code> port and the overall architecture\ncan be seen below:</p>\n<p><img src=\"https://fiware.github.io/tutorials.Historic-Context-Flume/img/cygnus-mongo.png\" alt /></p>\n<h2 id=\"mongo-db---database-server-configuration\">Mongo DB - Database Server Configuration</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-yaml\">mongo-db:\n    image: mongo:3.6\n    hostname: mongo-db\n    container_name: db-mongo\n    ports:\n        - \"27017:27017\"\n    networks:\n        - default\n    command: --bind_ip_all --smallfiles\n</code></pre>\n<h2 id=\"mongo-db---cygnus-configuration\">Mongo DB - Cygnus Configuration</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-yaml\">cygnus:\n    image: fiware/cygnus-ngsi:latest\n    hostname: cygnus\n    container_name: fiware-cygnus\n    depends_on:\n        - mongo-db\n    networks:\n        - default\n    expose:\n        - \"5080\"\n    ports:\n        - \"5051:5051\"\n        - \"5080:5080\"\n    environment:\n        - \"CYGNUS_MONGO_HOSTS=mongo-db:27017\"\n        - \"CYGNUS_MONGO_SERVICE_PORT=5051\"\n        - \"CYGNUS_LOG_LEVEL=DEBUG\"\n        - \"CYGNUS_API_PORT=5080\"\n        - \"CYGNUS_SERVICE_PORT=5051\"\n</code></pre>\n<p>The <code>cygnus</code> container is listening on two ports: </p>\n<ul>\n<li>The service will be listening on port <code>5051</code> for notifications from the Orion context broker</li>\n<li>Port <code>5080</code> is exposed purely for tutorial access - so that cUrl or Postman can make provisioning commands\nwithout being part of the same network.</li>\n</ul>\n<p>The <code>cygnus</code> container is driven by environment variables as shown:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Key</th>\n<th>Value</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>CYGNUS_MONGO_HOSTS</td>\n<td><code>mongo-db:27017</code></td>\n<td>Comma separated list of Mongo-DB servers which Cygnus will contact to persist historical context data</td>\n</tr>\n<tr>\n<td>CYGNUS_LOG_LEVEL</td>\n<td><code>DEBUG</code></td>\n<td>The logging level for Cygnus</td>\n</tr>\n<tr>\n<td>CYGNUS_SERVICE_PORT</td>\n<td><code>5051</code></td>\n<td>Notification Port that Cygnus listens when subcribing to context data changes</td>\n</tr>\n<tr>\n<td>CYGNUS_API_PORT</td>\n<td><code>5080</code></td>\n<td>Port that Cygnus listens on for operational reasons</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"mongo-db---start-up\">Mongo DB - Start up</h2>\n<p>To start the system with a <strong>Mongo DB</strong> database only, run the following command:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">./services mongodb\n</code></pre>\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.\nThe dummy IoT Sensors can be used to do this. Open the device monitor page at <code>http://localhost:3000/device/monitor</code>\nand unlock a <strong>Smart Door</strong> and switch on a <strong>Smart Lamp</strong>. This can be done by selecting an appropriate the command \nfrom the drop down list and pressing the <code>send</code> button. The stream of measurements coming from the devices can then\nbe seen on the same page:</p>\n<p><img src=\"https://fiware.github.io/tutorials.Historic-Context/img/door-open.gif\" alt /></p>\n","event":[{"listen":"prerequest","script":{"id":"a63e990e-c30a-419c-a54c-5d24baa792f2","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"d2710f35-1e52-4ac5-87ad-d7a93c640386","type":"text/javascript","exec":[""]}}],"_postman_id":"63e10b25-c72c-425e-9bf6-372a39ce5284"},{"name":"Mongo DB - Reading Data","item":[],"id":"a36d3a8e-488b-4089-80bf-4cc3c54060f0","description":"<p>To read mongo-db data from the command line, we will need access to the <code>mongo</code> tool run an interactive instance\nof the <code>mongo</code> image as shown to obtain a command line prompt:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">docker run -it --network fiware_default  --entrypoint /bin/bash mongo\n</code></pre>\n<p>You can then log into to the running <code>mongo-db</code> database by using the command line as shown:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-bash\">mongo --host mongo-db\n</code></pre>\n<h3 id=\"show-available-databases-on-the-mongodb-server\">Show Available Databases on the MongoDB server</h3>\n<p>To show the list of available databases, run the statement as shown:</p>\n<h4 id=\"query\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>show dbs\n</code></pre><h4 id=\"result\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>admin          0.000GB\niotagentul     0.000GB\nlocal          0.000GB\norion          0.000GB\norion-openiot  0.000GB\nsth_openiot    0.000GB\n</code></pre><p>The result include two databases <code>admin</code> and <code>local</code> which are set up by default by <strong>MongoDB</strong>, along with four databases\ncreated by the FIWARE platform. The Orion Context Broker has created two separate database instance for each <code>fiware-service</code></p>\n<ul>\n<li>the Store enitities were created without defining a <code>fiware-service</code> and therefore are held within the <code>orion</code> database,\nwhereas the IoT device entities were created using the <code>openiot</code> <code>fiware-service</code> header and are held separately. The IoT Agent was intialized to hold the IoT sensor data in a separate  <strong>MongoDB</strong> database called <code>iotagentul</code>.</li>\n</ul>\n<p>As a result of the subscription of Cygnus to Orion Context Broker, a new database has been created called <code>sth_openiot</code>. The default value for a <strong>Mongo DB</strong> database holding historic context consists of the <code>sth_</code> prefix followed by the <code>fiware-service</code> header - therefore <code>sth_openiot</code> holds the historic context of the IoT devices.</p>\n<h3 id=\"read-historical-context-from-the-mongodb-server\">Read Historical Context from the MongoDB server</h3>\n<h4 id=\"query-1\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>use sth_openiot\nshow collections\n</code></pre><h4 id=\"result-1\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>switched to db sth_openiot\n\nsth_/_Door:001_Door\nsth_/_Door:001_Door.aggr\nsth_/_Lamp:001_Lamp\nsth_/_Lamp:001_Lamp.aggr\nsth_/_Motion:001_Motion\nsth_/_Motion:001_Motion.aggr\n</code></pre><p>Looking within the <code>sth_openiot</code> you will see that a series of tables have been created. The names of each table consist\nof the <code>sth_</code> prefix followed by the <code>fiware-servicepath</code> header followed by the entity id. Two table are created for\neach entity - the <code>.aggr</code> table holds some aggregated data which will be accessed in a later tutorial. The raw data\ncan be seen in the tables without the <code>.aggr</code> suffix. </p>\n<p>The historical data can be seen by looking at the data within each table, by default each row will contain the sampled value of a single attribute. </p>\n<h4 id=\"query-2\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>db[\"sth_/_Door:001_Door\"].find().limit(10)\n</code></pre><h4 id=\"result-2\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>{ \"_id\" : ObjectId(\"5b1fa48630c49e0012f7635d\"), \"recvTime\" : ISODate(\"2018-06-12T10:46:30.897Z\"), \"attrName\" : \"TimeInstant\", \"attrType\" : \"ISO8601\", \"attrValue\" : \"2018-06-12T10:46:30.836Z\" }\n{ \"_id\" : ObjectId(\"5b1fa48630c49e0012f7635e\"), \"recvTime\" : ISODate(\"2018-06-12T10:46:30.897Z\"), \"attrName\" : \"close_status\", \"attrType\" : \"commandStatus\", \"attrValue\" : \"UNKNOWN\" }\n{ \"_id\" : ObjectId(\"5b1fa48630c49e0012f7635f\"), \"recvTime\" : ISODate(\"2018-06-12T10:46:30.897Z\"), \"attrName\" : \"lock_status\", \"attrType\" : \"commandStatus\", \"attrValue\" : \"UNKNOWN\" }\n{ \"_id\" : ObjectId(\"5b1fa48630c49e0012f76360\"), \"recvTime\" : ISODate(\"2018-06-12T10:46:30.897Z\"), \"attrName\" : \"open_status\", \"attrType\" : \"commandStatus\", \"attrValue\" : \"UNKNOWN\" }\n{ \"_id\" : ObjectId(\"5b1fa48630c49e0012f76361\"), \"recvTime\" : ISODate(\"2018-06-12T10:46:30.836Z\"), \"attrName\" : \"refStore\", \"attrType\" : \"Relationship\", \"attrValue\" : \"Store:001\" }\n{ \"_id\" : ObjectId(\"5b1fa48630c49e0012f76362\"), \"recvTime\" : ISODate(\"2018-06-12T10:46:30.836Z\"), \"attrName\" : \"state\", \"attrType\" : \"Text\", \"attrValue\" : \"CLOSED\" }\n{ \"_id\" : ObjectId(\"5b1fa48630c49e0012f76363\"), \"recvTime\" : ISODate(\"2018-06-12T10:45:26.368Z\"), \"attrName\" : \"unlock_info\", \"attrType\" : \"commandResult\", \"attrValue\" : \" unlock OK\" }\n{ \"_id\" : ObjectId(\"5b1fa48630c49e0012f76364\"), \"recvTime\" : ISODate(\"2018-06-12T10:45:26.368Z\"), \"attrName\" : \"unlock_status\", \"attrType\" : \"commandStatus\", \"attrValue\" : \"OK\" }\n{ \"_id\" : ObjectId(\"5b1fa4c030c49e0012f76385\"), \"recvTime\" : ISODate(\"2018-06-12T10:47:28.081Z\"), \"attrName\" : \"TimeInstant\", \"attrType\" : \"ISO8601\", \"attrValue\" : \"2018-06-12T10:47:28.038Z\" }\n{ \"_id\" : ObjectId(\"5b1fa4c030c49e0012f76386\"), \"recvTime\" : ISODate(\"2018-06-12T10:47:28.081Z\"), \"attrName\" : \"close_status\", \"attrType\" : \"commandStatus\", \"attrValue\" : \"UNKNOWN\" }\n</code></pre><p>The usual <strong>Mongo-DB</strong> query syntax can be used to filter appropriate fields and values. For example to read the rate at which the <strong>Motion Sensor</strong> with the <code>id=Motion:001_Motion</code> is accumulating, you would make a query as follows:</p>\n<h4 id=\"query-3\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>db[\"sth_/_Motion:001_Motion\"].find({attrName: \"count\"},{_id: 0, attrType: 0, attrName: 0 } ).limit(10)\n</code></pre><h4 id=\"result-3\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>{ \"recvTime\" : ISODate(\"2018-06-12T10:46:18.756Z\"), \"attrValue\" : \"8\" }\n{ \"recvTime\" : ISODate(\"2018-06-12T10:46:36.881Z\"), \"attrValue\" : \"10\" }\n{ \"recvTime\" : ISODate(\"2018-06-12T10:46:42.947Z\"), \"attrValue\" : \"11\" }\n{ \"recvTime\" : ISODate(\"2018-06-12T10:46:54.893Z\"), \"attrValue\" : \"13\" }\n{ \"recvTime\" : ISODate(\"2018-06-12T10:47:00.929Z\"), \"attrValue\" : \"15\" }\n{ \"recvTime\" : ISODate(\"2018-06-12T10:47:06.954Z\"), \"attrValue\" : \"17\" }\n{ \"recvTime\" : ISODate(\"2018-06-12T10:47:15.983Z\"), \"attrValue\" : \"19\" }\n{ \"recvTime\" : ISODate(\"2018-06-12T10:47:49.090Z\"), \"attrValue\" : \"23\" }\n{ \"recvTime\" : ISODate(\"2018-06-12T10:47:58.112Z\"), \"attrValue\" : \"25\" }\n{ \"recvTime\" : ISODate(\"2018-06-12T10:48:28.218Z\"), \"attrValue\" : \"29\" }\n</code></pre><p>To leave the MongoDB client and leave interactive mode, run the following:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">exit\n</code></pre>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">exit\n</code></pre>\n","event":[{"listen":"prerequest","script":{"id":"9e70a754-3893-4617-adc7-c0471f7372f7","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"c43d1162-ac29-4852-9094-b1b86604352b","type":"text/javascript","exec":[""]}}],"_postman_id":"a36d3a8e-488b-4089-80bf-4cc3c54060f0"},{"name":"PostgreSQL - Persisting Context","item":[{"name":"Cygnus - Obtain version information","id":"fe6c77f2-89ff-4721-b42f-dde069494258","request":{"method":"GET","header":[],"body":{"mode":"formdata","formdata":[]},"url":"http://localhost:5080/v1/version","description":"<p>Once Cygnus is running, You can check the status by making an HTTP request to the exposed <code>CYGNUS_API_PORT</code> port. \nIf the response is blank, this is usually because Cygnus is not running or is listening on another port.</p>\n<blockquote>\n<p><strong>Troubleshooting:</strong> What if the response is blank ?</p>\n<ul>\n<li>To check that a docker container is running try</li>\n</ul>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-bash\">docker ps\n</code></pre>\n<p>You should see several containers running. If <code>cygnus</code> is not running, you can restart the containers as necessary.</p>\n</blockquote>\n","urlObject":{"protocol":"http","path":["v1","version"],"host":["localhost:5080"],"query":[],"variable":[]}},"response":[],"_postman_id":"fe6c77f2-89ff-4721-b42f-dde069494258"},{"name":"Orion - Subscribe to Context Changes","id":"570dfecc-98de-41a2-b869-b60995c2acf1","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"fiware-service","value":"openiot"},{"key":"fiware-servicepath","value":"/"}],"body":{"mode":"raw","raw":"{\n  \"description\": \"Notify Cygnus of all context changes\",\n  \"subject\": {\n    \"entities\": [\n      {\n        \"idPattern\": \".*\"\n      }\n    ]\n  },\n  \"notification\": {\n    \"http\": {\n      \"url\": \"http://cygnus:5055/notify\"\n    }\n  },\n  \"throttling\": 5\n}"},"url":"http://localhost:1026/v2/subscriptions/","description":"<p>Once a dynamic context system is up and running, we need to inform <strong>Cygnus</strong> of changes in context.</p>\n<p>This is done by making a POST request to the <code>/v2/subscription</code> endpoint of the Orion Context Broker.</p>\n<ul>\n<li>The <code>fiware-service</code> and <code>fiware-servicepath</code> headers are used to filter the subscription to only listen to measurements from the attached IoT Sensors</li>\n<li>The <code>idPattern</code> in the request body ensures that Cygnus will be informed of all context data changes.</li>\n<li>The notification <code>url</code> must match the configured <code>CYGNUS_POSTGRESQL_SERVICE_PORT</code></li>\n<li>The <code>attrsFormat=legacy</code> is required since Cygnus currently only accepts notifications in the older NGSI v1 format.</li>\n<li>The <code>throttling</code> value defines the rate that changes are sampled.</li>\n</ul>\n<p>As you can see, the database used to persist context data has no impact on the details of the subscription.It is the same for each database.</p>\n","urlObject":{"protocol":"http","path":["v2","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"570dfecc-98de-41a2-b869-b60995c2acf1"},{"name":"Orion - Check Subscription is working","id":"f2184501-caed-4b0d-9095-ab51fa0c7cef","request":{"method":"GET","header":[{"key":"fiware-service","value":"openiot"},{"key":"fiware-servicepath","value":"/"}],"body":{"mode":"raw","raw":""},"url":"http://localhost:1026/v2/subscriptions/","description":"<p>If a subscription has been created, you can check to see if it is firing by making a GET \nrequest to the <code>/v2/subscriptions</code> endpoint.</p>\n<p>Within the <code>notification</code> section of the response, you can see several additional <code>attributes</code> which describe the health of the subscription</p>\n<p>If the criteria of the subscription have been met, <code>timesSent</code> should be greater than <code>0</code>.\nA zero value would indicate that the <code>subject</code> of the subscription is incorrect or the subscription \nhas created with the wrong <code>fiware-service-path</code> or <code>fiware-service</code> header</p>\n<p>The <code>lastNotification</code> should be a recent timestamp - if this is not the case, then the devices\nare not regularly sending data. Remember to unlock the <strong>Smart Door</strong> and switch on the <strong>Smart Lamp</strong></p>\n<p>The <code>lastSuccess</code> should match the <code>lastNotification</code> date - if this is not the case \nthen <strong>Cygnus</strong> is not receiving the subscription properly. Check that the host name\nand port are correct. </p>\n<p>Finally, check that the <code>status</code> of the subscription is <code>active</code> - an expired subscription\nwill not fire.</p>\n","urlObject":{"protocol":"http","path":["v2","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"f2184501-caed-4b0d-9095-ab51fa0c7cef"}],"id":"c158f118-b701-49e2-b008-964f409b162d","description":"<p>To persist historic context data into an alternative database such as <strong>PostgreSQL</strong>, we will\nneed an additional container which hosts the PostgreSQL server - the default Docker image for this\ndata can be used. The PostgreSQL instance is listening on the standard <code>5432</code> port and the overall architecture\ncan be seen below:</p>\n<p><img src=\"https://fiware.github.io/tutorials.Historic-Context-Flume/img/cygnus-postgres.png\" alt /></p>\n<p>We now have a system with two databases, since the MongoDB container is still required \nto hold data related to the Orion Context Broker and the IoT Agent. </p>\n<h2 id=\"postgresql---start-up\">PostgreSQL - Start up</h2>\n<p>To start the system with a <strong>PostgreSQL</strong> database run the following command:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">./services postgres\n</code></pre>\n<h2 id=\"postgresql--database-server-configuration\">PostgreSQL- Database Server Configuration</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-yaml\">postgres-db:\n      image: postgres:latest\n      hostname: postgres-db\n      container_name: db-postgres\n      expose:\n        - \"5432\"\n      ports:\n        - \"5432:5432\"\n      networks:\n        - default\n      environment:\n        - \"POSTGRES_PASSWORD=password\"\n        - \"POSTGRES_USER=postgres\"\n        - \"POSTGRES_DB=postgres\"\n\n</code></pre>\n<p>The <code>postgres-db</code> container is listening on a single port: </p>\n<ul>\n<li>Port <code>5432</code> is the default port for a PostgreSQL server. It has been exposed so you can also run the <code>pgAdmin4</code> tool to display database data if you wish</li>\n</ul>\n<p>The <code>postgres-db</code> container is driven by environment variables as shown:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Key</th>\n<th>Value.</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>POSTGRES_PASSWORD</td>\n<td><code>password</code></td>\n<td>Password for the PostgreSQL database user</td>\n</tr>\n<tr>\n<td>POSTGRES_USER</td>\n<td><code>postgres</code></td>\n<td>Username for the PostgreSQL database user</td>\n</tr>\n<tr>\n<td>POSTGRES_DB</td>\n<td><code>postgres</code></td>\n<td>The name of the PostgreSQL database</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"postgresql---cygnus-configuration\">PostgreSQL - Cygnus Configuration</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-yaml\">cygnus:\n    image: fiware/cygnus-ngsi:latest\n    hostname: cygnus\n    container_name: fiware-cygnus\n    networks:\n        - default\n    depends_on:\n        - postgres-db\n    expose:\n        - \"5080\"\n    ports:\n        - \"5055:5055\"\n        - \"5080:5080\"\n    environment:\n        - \"CYGNUS_POSTGRESQL_HOST=postgres-db\"\n        - \"CYGNUS_POSTGRESQL_PORT=5432\"\n        - \"CYGNUS_POSTGRESQL_USER=postgres\"\n        - \"CYGNUS_POSTGRESQL_PASS=password\"\n        - \"CYGNUS_POSTGRESQL_ENABLE_CACHE=true\"\n        - \"CYGNUS_POSTGRESQL_SERVICE_PORT=5055\"\n        - \"CYGNUS_LOG_LEVEL=DEBUG\"\n        - \"CYGNUS_API_PORT=5080\"\n        - \"CYGNUS_SERVICE_PORT=5055\"\n</code></pre>\n<p>The <code>cygnus</code> container is listening on two ports: </p>\n<ul>\n<li>The service will be listening on port <code>5055</code> for notifications from the Orion context broker</li>\n<li>Port <code>5080</code> is exposed purely for tutorial access - so that cUrl or Postman can make provisioning commands\nwithout being part of the same network.</li>\n</ul>\n<p>The <code>cygnus</code> container is driven by environment variables as shown:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Key</th>\n<th>Value</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>CYGNUS_POSTGRESQL_HOST</td>\n<td><code>postgres-db</code></td>\n<td>Hostname of the PostgreSQL server used to persist historical context data</td>\n</tr>\n<tr>\n<td>CYGNUS_POSTGRESQL_PORT</td>\n<td><code>5432</code></td>\n<td>Port that the PostgreSQL server uses to listen to commands</td>\n</tr>\n<tr>\n<td>CYGNUS_POSTGRESQL_USER</td>\n<td><code>postgres</code></td>\n<td>Username for the PostgreSQL database user</td>\n</tr>\n<tr>\n<td>CYGNUS_POSTGRESQL_PASS</td>\n<td><code>password</code></td>\n<td>Password for the PostgreSQL database user</td>\n</tr>\n<tr>\n<td>CYGNUS_LOG_LEVEL</td>\n<td><code>DEBUG</code></td>\n<td>The logging level for Cygnus</td>\n</tr>\n<tr>\n<td>CYGNUS_SERVICE_PORT</td>\n<td><code>5055</code></td>\n<td>Notification Port that Cygnus listens when subcribing to context data changes</td>\n</tr>\n<tr>\n<td>CYGNUS_API_PORT</td>\n<td><code>5080</code></td>\n<td>Port that Cygnus listens on for operational reasons</td>\n</tr>\n<tr>\n<td>CYGNUS_POSTGRESQL_ENABLE_CACHE</td>\n<td><code>true</code></td>\n<td>Switch to enable caching within the PostgreSQL configuration</td>\n</tr>\n</tbody>\n</table>\n</div><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.\nThe dummy IoT Sensors can be used to do this. Open the device monitor page at <code>http://localhost:3000/device/monitor</code>\nand unlock a <strong>Smart Door</strong> and switch on a <strong>Smart Lamp</strong>. This can be done by selecting an appropriate the command \nfrom the drop down list and pressing the <code>send</code> button. The stream of measurements coming from the devices can then\nbe seen on the same page:</p>\n<p><img src=\"https://fiware.github.io/tutorials.Historic-Context/img/door-open.gif\" alt /></p>\n","event":[{"listen":"prerequest","script":{"id":"f8ca5d71-4eb4-42b9-95e0-c3ef11567514","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"43d701ab-eb41-472e-875e-4ac51e27579a","type":"text/javascript","exec":[""]}}],"_postman_id":"c158f118-b701-49e2-b008-964f409b162d"},{"name":"PostgreSQL - Reading Data","item":[],"id":"6f53fa4a-083c-4378-8e3f-620e1d05eb52","description":"<p>To read PostgreSQL data from the command line, we will need access to the <code>postgres</code> client, to do this, run an\ninteractive instance of the <code>postgresql-client</code> image supplying the connection string as shown to obtain a command \nline prompt:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">docker run -it --rm  --network fiware_default jbergknoff/postgresql-client \\\n   postgresql://postgres:password@postgres-db:5432/postgres\n</code></pre>\n<h3 id=\"show-available-databases-on-the-postgresql-server\">Show Available Databases on the PostgreSQL server</h3>\n<p>To show the list of available databases, run the statement as shown:</p>\n<h4 id=\"query\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>\\list\n</code></pre><h4 id=\"result\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>   Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges   \n-----------+----------+----------+------------+------------+-----------------------\n postgres  | postgres | UTF8     | en_US.utf8 | en_US.utf8 | \n template0 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +\n           |          |          |            |            | postgres=CTc/postgres\n template1 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +\n           |          |          |            |            | postgres=CTc/postgres\n(3 rows)\n</code></pre><p>The result include two template databases <code>template0</code> and <code>template1</code> as well as the <code>postgres</code> database setup when the docker container was started.</p>\n<p>To show the list of available schemas, run the statement as shown:</p>\n<h4 id=\"query-1\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>\\dn\n</code></pre><h4 id=\"result-1\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>  List of schemas\n  Name   |  Owner   \n---------+----------\n openiot | postgres\n public  | postgres\n(2 rows)\n</code></pre><p>As a result of the subscription of Cygnus to Orion Context Broker, a new schema has been created called <code>openiot</code>. \nThe name of the schema matches the <code>fiware-service</code> header - therefore <code>openiot</code> holds the historic context of the\nIoT devices.</p>\n<h3 id=\"read-historical-context-from-the-postgresql-server\">Read Historical Context from the PostgreSQL server</h3>\n<p>Once running a docker container within the network, it is possible to obtain information about the running\ndatabase.</p>\n<h4 id=\"query-2\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-sql\">SELECT table_schema,table_name\nFROM information_schema.tables\nWHERE table_schema ='openiot'\nORDER BY table_schema,table_name;\n</code></pre>\n<h4 id=\"result-2\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code> table_schema |    table_name     \n--------------+-------------------\n openiot      | door_001_door\n openiot      | lamp_001_lamp\n openiot      | motion_001_motion\n(3 rows)\n</code></pre><p>The <code>table_schema</code> matches the <code>fiware-service</code> header supplied with the context data:</p>\n<p>To read the data within a table, run a select statement as shown:</p>\n<h4 id=\"query-3\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-sql\">SELECT * FROM openiot.motion_001_motion limit 10;\n</code></pre>\n<h4 id=\"result-3\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>  recvtimets   |         recvtime         | fiwareservicepath |  entityid  | entitytype |  attrname   |   attrtype   |        attrvalue         |                                    attrmd                                    \n---------------+--------------------------+-------------------+------------+------------+-------------+--------------+--------------------------+------------------------------------------------------------------------------\n 1528803005491 | 2018-06-12T11:30:05.491Z | /                 | Motion:001 | Motion     | TimeInstant | ISO8601      | 2018-06-12T11:30:05.423Z | []\n 1528803005491 | 2018-06-12T11:30:05.491Z | /                 | Motion:001 | Motion     | count       | Integer      | 7                        | [{\"name\":\"TimeInstant\",\"type\":\"ISO8601\",\"value\":\"2018-06-12T11:30:05.423Z\"}]\n 1528803005491 | 2018-06-12T11:30:05.491Z | /                 | Motion:001 | Motion     | refStore    | Relationship | Store:001                | [{\"name\":\"TimeInstant\",\"type\":\"ISO8601\",\"value\":\"2018-06-12T11:30:05.423Z\"}]\n 1528803035501 | 2018-06-12T11:30:35.501Z | /                 | Motion:001 | Motion     | TimeInstant | ISO8601      | 2018-06-12T11:30:35.480Z | []\n 1528803035501 | 2018-06-12T11:30:35.501Z | /                 | Motion:001 | Motion     | count       | Integer      | 10                       | [{\"name\":\"TimeInstant\",\"type\":\"ISO8601\",\"value\":\"2018-06-12T11:30:35.480Z\"}]\n 1528803035501 | 2018-06-12T11:30:35.501Z | /                 | Motion:001 | Motion     | refStore    | Relationship | Store:001                | [{\"name\":\"TimeInstant\",\"type\":\"ISO8601\",\"value\":\"2018-06-12T11:30:35.480Z\"}]\n 1528803041563 | 2018-06-12T11:30:41.563Z | /                 | Motion:001 | Motion     | TimeInstant | ISO8601      | 2018-06-12T11:30:41.520Z | []\n 1528803041563 | 2018-06-12T11:30:41.563Z | /                 | Motion:001 | Motion     | count       | Integer      | 12                       | [{\"name\":\"TimeInstant\",\"type\":\"ISO8601\",\"value\":\"2018-06-12T11:30:41.520Z\"}]\n 1528803041563 | 2018-06-12T11:30:41.563Z | /                 | Motion:001 | Motion     | refStore    | Relationship | Store:001                | [{\"name\":\"TimeInstant\",\"type\":\"ISO8601\",\"value\":\"2018-06-12T11:30:41.520Z\"}]\n 1528803047545 | 2018-06-12T11:30:47.545Z | /     \n</code></pre><p>The usual <strong>PostgreSQL</strong> query syntax can be used to filter appropriate fields and values. For example to read the rate at which the <strong>Motion Sensor</strong> with the <code>id=Motion:001_Motion</code> is accumulating, you would make a query as follows:</p>\n<h4 id=\"query-4\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-sql\">SELECT recvtime, attrvalue FROM openiot.motion_001_motion WHERE attrname ='count'  limit 10;\n</code></pre>\n<h4 id=\"result-4\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>         recvtime         | attrvalue \n--------------------------+-----------\n 2018-06-12T11:30:05.491Z | 7\n 2018-06-12T11:30:35.501Z | 10\n 2018-06-12T11:30:41.563Z | 12\n 2018-06-12T11:30:47.545Z | 13\n 2018-06-12T11:31:02.617Z | 15\n 2018-06-12T11:31:32.718Z | 20\n 2018-06-12T11:31:38.733Z | 22\n 2018-06-12T11:31:50.780Z | 24\n 2018-06-12T11:31:56.825Z | 25\n 2018-06-12T11:31:59.790Z | 26\n(10 rows)\n</code></pre><p>To leave the Postgres client and leave interactive mode, run the following:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">\\q\n</code></pre>\n<p> You will then return to the commmand line.</p>\n","event":[{"listen":"prerequest","script":{"id":"9547319e-f5df-4a3d-9a69-86221f7aeb2f","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"eaf3c847-e1eb-48e2-aadd-35caf0463942","type":"text/javascript","exec":[""]}}],"_postman_id":"6f53fa4a-083c-4378-8e3f-620e1d05eb52"},{"name":"MySQL - Persisting Context","item":[{"name":"Cygnus - Obtain version information","id":"87aee394-9ec5-4f33-b0a0-4e5041551eaa","request":{"method":"GET","header":[],"body":{"mode":"formdata","formdata":[]},"url":"http://localhost:5080/v1/version","description":"<p>Once Cygnus is running, You can check the status by making an HTTP request to the exposed <code>CYGNUS_API_PORT</code> port. \nIf the response is blank, this is usually because Cygnus is not running or is listening on another port.</p>\n<blockquote>\n<p><strong>Troubleshooting:</strong> What if the response is blank ?</p>\n<ul>\n<li>To check that a docker container is running try</li>\n</ul>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-bash\">docker ps\n</code></pre>\n<p>You should see several containers running. If <code>cygnus</code> is not running, you can restart the containers as necessary.</p>\n</blockquote>\n","urlObject":{"protocol":"http","path":["v1","version"],"host":["localhost:5080"],"query":[],"variable":[]}},"response":[],"_postman_id":"87aee394-9ec5-4f33-b0a0-4e5041551eaa"},{"name":"Orion - Subscribe to Context Changes","id":"bdae8a37-fdce-4bb3-b341-56c587dfa1bc","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"fiware-service","value":"openiot"},{"key":"fiware-servicepath","value":"/"}],"body":{"mode":"raw","raw":"{\n  \"description\": \"Notify Cygnus of all context changes\",\n  \"subject\": {\n    \"entities\": [\n      {\n        \"idPattern\": \".*\"\n      }\n    ]\n  },\n  \"notification\": {\n    \"http\": {\n      \"url\": \"http://cygnus:5050/notify\"\n    }\n  },\n  \"throttling\": 5\n}"},"url":"http://localhost:1026/v2/subscriptions/","description":"<p>Once a dynamic context system is up and running, we need to inform <strong>Cygnus</strong> of changes in context.</p>\n<p>This is done by making a POST request to the <code>/v2/subscription</code> endpoint of the Orion Context Broker.</p>\n<ul>\n<li>The <code>fiware-service</code> and <code>fiware-servicepath</code> headers are used to filter the subscription to only listen to measurements from the attached IoT Sensors</li>\n<li>The <code>idPattern</code> in the request body ensures that Cygnus will be informed of all context data changes.</li>\n<li>The notification <code>url</code> must match the configured <code>CYGNUS_MYSQL_SERVICE_PORT</code></li>\n<li>The <code>attrsFormat=legacy</code> is required since Cygnus currently only accepts notifications in the older NGSI v1 format.</li>\n<li>The <code>throttling</code> value defines the rate that changes are sampled.</li>\n</ul>\n<p>As you can see, the database used to persist context data has no impact on the details of the subscription. It is the same for each database.</p>\n","urlObject":{"protocol":"http","path":["v2","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"bdae8a37-fdce-4bb3-b341-56c587dfa1bc"},{"name":"Orion - Check Subscription is working","id":"62839dc3-bba3-4ef3-8ed6-f03420ff918b","request":{"method":"GET","header":[{"key":"fiware-service","value":"openiot"},{"key":"fiware-servicepath","value":"/"}],"body":{"mode":"raw","raw":""},"url":"http://localhost:1026/v2/subscriptions/","description":"<p>If a subscription has been created, you can check to see if it is firing by making a GET \nrequest to the <code>/v2/subscriptions</code> endpoint.</p>\n<p>Within the <code>notification</code> section of the response, you can see several additional <code>attributes</code> which describe the health of the subscription</p>\n<p>If the criteria of the subscription have been met, <code>timesSent</code> should be greater than <code>0</code>.\nA zero value would indicate that the <code>subject</code> of the subscription is incorrect or the subscription \nhas created with the wrong <code>fiware-service-path</code> or <code>fiware-service</code> header</p>\n<p>The <code>lastNotification</code> should be a recent timestamp - if this is not the case, then the devices\nare not regularly sending data. Remember to unlock the <strong>Smart Door</strong> and switch on the <strong>Smart Lamp</strong></p>\n<p>The <code>lastSuccess</code> should match the <code>lastNotification</code> date - if this is not the case \nthen <strong>Cygnus</strong> is not receiving the subscription properly. Check that the host name\nand port are correct. </p>\n<p>Finally, check that the <code>status</code> of the subscription is <code>active</code> - an expired subscription\nwill not fire.</p>\n","urlObject":{"protocol":"http","path":["v2","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"62839dc3-bba3-4ef3-8ed6-f03420ff918b"}],"id":"8d578098-2a2d-48af-946c-7c5e028caa7e","description":"<p>Similarly, to persisting historic context data into <strong>MySQL</strong>, we will again\nneed an additional container which hosts the MySQL server, once again the default Docker image for this\ndata can be used. The MySQL instance is listening on the standard <code>3306</code> port and the overall architecture\ncan be seen below:</p>\n<p><img src=\"https://fiware.github.io/tutorials.Historic-Context-Flume/img/cygnus-mysql.png\" alt /></p>\n<p>Once again we have a system with two databases, since the MongoDB container is still required \nto hold data related to the Orion Context Broker and the IoT Agent. </p>\n<h2 id=\"mysql---database-server-configuration\">MySQL - Database Server Configuration</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-yaml\">mysql-db:\n      restart: always\n      image: mysql:5.7\n      hostname: mysql-db\n      container_name: db-mysql\n      expose:\n        - \"3306\"\n      ports:\n        - \"3306:3306\"\n      networks:\n        - default\n      environment:\n        - \"MYSQL_ROOT_PASSWORD=123\"\n        - \"MYSQL_ROOT_HOST=%\"\n</code></pre>\n<p>The <code>mysql-db</code> container is listening on a single port: </p>\n<ul>\n<li>Port <code>3306</code> is the default port for a MySQL server. It has been exposed so you can also run other database tools to display data if you wish</li>\n</ul>\n<p>The <code>mysql-db</code> container is driven by environment variables as shown:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Key</th>\n<th>Value.</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>MYSQL_ROOT_PASSWORD</td>\n<td><code>123</code>.</td>\n<td>specifies a password that is set for the MySQL <code>root</code> account.</td>\n</tr>\n<tr>\n<td>MYSQL_ROOT_HOST</td>\n<td><code>postgres</code></td>\n<td>By default, MySQL creates the <code>root'@'localhost</code> account. This account can only be connected to from inside the container. Setting this environment variable allows root connections from other hosts</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"mysql---cygnus-configuration\">MySQL - Cygnus Configuration</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-yaml\">cygnus:\n    image: fiware/cygnus-ngsi:latest\n    hostname: cygnus\n    container_name: fiware-cygnus\n    networks:\n        - default\n    depends_on:\n        - mysql-db\n    expose:\n        - \"5080\"\n    ports:\n        - \"5080:5080\"\n    environment:\n        - \"CYGNUS_MYSQL_HOST=mysql-db\"\n        - \"CYGNUS_MYSQL_PORT=3306\"\n        - \"CYGNUS_MYSQL_USER=root\"\n        - \"CYGNUS_MYSQL_PASS=123\"\n        - \"CYGNUS_MYSQL_SERVICE_PORT=5050\"\n        - \"CYGNUS_LOG_LEVEL=DEBUG\"\n        - \"CYGNUS_API_PORT=5080\"\n        - \"CYGNUS_SERVICE_PORT=5050\"\n</code></pre>\n<p>The <code>cygnus</code> container is listening on two ports: </p>\n<ul>\n<li>The service will be listening on port <code>5050</code> for notifications from the Orion context broker</li>\n<li>Port <code>5080</code> is exposed purely for tutorial access - so that cUrl or Postman can make provisioning commands\nwithout being part of the same network.</li>\n</ul>\n<p>The <code>cygnus</code> container is driven by environment variables as shown:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Key</th>\n<th>Value</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>CYGNUS_MYSQL_HOST</td>\n<td><code>mysql-db</code></td>\n<td>Hostname of the MySQL server used to persist historical context data</td>\n</tr>\n<tr>\n<td>CYGNUS_MYSQL_PORT</td>\n<td><code>3306</code></td>\n<td>Port that the MySQL server uses to listen to commands</td>\n</tr>\n<tr>\n<td>CYGNUS_MYSQL_USER</td>\n<td><code>root</code></td>\n<td>Username for the MySQL database user</td>\n</tr>\n<tr>\n<td>CYGNUS_MYSQL_PASS</td>\n<td><code>123</code></td>\n<td>Password for the MySQL database user</td>\n</tr>\n<tr>\n<td>CYGNUS_LOG_LEVEL</td>\n<td><code>DEBUG</code></td>\n<td>The logging level for Cygnus</td>\n</tr>\n<tr>\n<td>CYGNUS_SERVICE_PORT</td>\n<td><code>5050</code></td>\n<td>Notification Port that Cygnus listens when subcribing to context data changes</td>\n</tr>\n<tr>\n<td>CYGNUS_API_PORT</td>\n<td><code>5080</code></td>\n<td>Port that Cygnus listens on for operational reasons</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"mysql---start-up\">MySQL - Start up</h2>\n<p>To start the system with a <strong>MySQL</strong> database run the following command:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">./services mysql\n</code></pre>\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.\nThe dummy IoT Sensors can be used to do this. Open the device monitor page at <code>http://localhost:3000/device/monitor</code>\nand unlock a <strong>Smart Door</strong> and switch on a <strong>Smart Lamp</strong>. This can be done by selecting an appropriate the command \nfrom the drop down list and pressing the <code>send</code> button. The stream of measurements coming from the devices can then\nbe seen on the same page:</p>\n<p><img src=\"https://fiware.github.io/tutorials.Historic-Context/img/door-open.gif\" alt /></p>\n","event":[{"listen":"prerequest","script":{"id":"1c3c984c-886c-464c-b936-a5b355263c89","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"cafefa9a-6026-45d2-8877-2298a955ba2d","type":"text/javascript","exec":[""]}}],"_postman_id":"8d578098-2a2d-48af-946c-7c5e028caa7e"},{"name":"MySQL - Reading Data","item":[],"id":"9d1b2b75-bf06-433c-9c46-b56e144dd8ca","description":"<p>To read MySQL data from the command line, we will need access to the <code>mysql</code> client, to do this, run an\ninteractive instance of the <code>mysql</code> image supplying the connection string as shown to obtain a command \nline prompt:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">docker exec -it  db-mysql mysql -h mysql-db -P 3306  -u root -p123\n</code></pre>\n<h3 id=\"show-available-databases-on-the-mysql-server\">Show Available Databases on the MySQL server</h3>\n<p>To show the list of available databases, run the statement as shown:</p>\n<h4 id=\"query\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-sql\">SHOW DATABASES;\n</code></pre>\n<h4 id=\"result\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>+--------------------+\n| Database           |\n+--------------------+\n| information_schema |\n| mysql              |\n| openiot            |\n| performance_schema |\n| sys                |\n+--------------------+\n5 rows in set (0.00 sec)\n</code></pre><p>To show the list of available schemas, run the statement as shown:</p>\n<h4 id=\"query-1\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-sql\">SHOW SCHEMAS;\n</code></pre>\n<h4 id=\"result-1\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>+--------------------+\n| Database           |\n+--------------------+\n| information_schema |\n| mysql              |\n| openiot            |\n| performance_schema |\n| sys                |\n+--------------------+\n5 rows in set (0.00 sec)\n</code></pre><p>As a result of the subscription of Cygnus to Orion Context Broker, a new schema has been created called <code>openiot</code>. \nThe name of the schema matches the <code>fiware-service</code> header - therefore <code>openiot</code> holds the historic context of the\nIoT devices.</p>\n<h3 id=\"read-historical-context-from-the-postgresql-server\">Read Historical Context from the PostgreSQL server</h3>\n<p>Once running a docker container within the network, it is possible to obtain information about the running\ndatabase.</p>\n<h4 id=\"query-2\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-sql\">SHOW tables FROM openiot;\n</code></pre>\n<h4 id=\"result-2\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code> table_schema |    table_name     \n--------------+-------------------\n openiot      | door_001_door\n openiot      | lamp_001_lamp\n openiot      | motion_001_motion\n(3 rows)\n</code></pre><p>The <code>table_schema</code> matches the <code>fiware-service</code> header supplied with the context data:</p>\n<p>To read the data within a table, run a select statement as shown:</p>\n<h4 id=\"query-3\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-sql\">SELECT * FROM openiot.Motion_001_Motion limit 10;\n</code></pre>\n<h4 id=\"result-3\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>+---------------+-------------------------+-------------------+------------+------------+-------------+--------------+--------------------------+------------------------------------------------------------------------------+\n| recvTimeTs    | recvTime                | fiwareServicePath | entityId   | entityType | attrName    | attrType     | attrValue                | attrMd                                                                       |\n+---------------+-------------------------+-------------------+------------+------------+-------------+--------------+--------------------------+------------------------------------------------------------------------------+\n| 1528804397955 | 2018-06-12T11:53:17.955 | /                 | Motion:001 | Motion     | TimeInstant | ISO8601      | 2018-06-12T11:53:17.923Z | []                                                                           |\n| 1528804397955 | 2018-06-12T11:53:17.955 | /                 | Motion:001 | Motion     | count       | Integer      | 3                        | [{\"name\":\"TimeInstant\",\"type\":\"ISO8601\",\"value\":\"2018-06-12T11:53:17.923Z\"}] |\n| 1528804397955 | 2018-06-12T11:53:17.955 | /                 | Motion:001 | Motion     | refStore    | Relationship | Store:001                | [{\"name\":\"TimeInstant\",\"type\":\"ISO8601\",\"value\":\"2018-06-12T11:53:17.923Z\"}] |\n| 1528804403954 | 2018-06-12T11:53:23.954 | /                 | Motion:001 | Motion     | TimeInstant | ISO8601      | 2018-06-12T11:53:23.928Z | []                                                                           |\n| 1528804403954 | 2018-06-12T11:53:23.954 | /                 | Motion:001 | Motion     | count       | Integer      | 5                        | [{\"name\":\"TimeInstant\",\"type\":\"ISO8601\",\"value\":\"2018-06-12T11:53:23.928Z\"}] |\n| 1528804403954 | 2018-06-12T11:53:23.954 | /                 | Motion:001 | Motion     | refStore    | Relationship | Store:001                | [{\"name\":\"TimeInstant\",\"type\":\"ISO8601\",\"value\":\"2018-06-12T11:53:23.928Z\"}] |\n| 1528804409970 | 2018-06-12T11:53:29.970 | /                 | Motion:001 | Motion     | TimeInstant | ISO8601      | 2018-06-12T11:53:29.948Z | []                                                                           |\n| 1528804409970 | 2018-06-12T11:53:29.970 | /                 | Motion:001 | Motion     | count       | Integer      | 7                        | [{\"name\":\"TimeInstant\",\"type\":\"ISO8601\",\"value\":\"2018-06-12T11:53:29.948Z\"}] |\n| 1528804409970 | 2018-06-12T11:53:29.970 | /                 | Motion:001 | Motion     | refStore    | Relationship | Store:001                | [{\"name\":\"TimeInstant\",\"type\":\"ISO8601\",\"value\":\"2018-06-12T11:53:29.948Z\"}] |\n| 1528804446083 | 2018-06-12T11:54:06.83  | /                 | Motion:001 | Motion     | TimeInstant | ISO8601      | 2018-06-12T11:54:06.062Z | []                                                                           |\n+---------------+-------------------------+-------------------+------------+------------+-------------+--------------+--------------------------+------------------------------------------------------------------------------+    \n</code></pre><p>The usual <strong>MySQL</strong> query syntax can be used to filter appropriate fields and values. For example to read the rate at which the <strong>Motion Sensor</strong> with the <code>id=Motion:001_Motion</code> is accumulating, you would make a query as follows:</p>\n<h4 id=\"query-4\">Query:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-sql\">SELECT recvtime, attrvalue FROM openiot.Motion_001_Motion WHERE attrname ='count' LIMIT 10;\n</code></pre>\n<h4 id=\"result-4\">Result:</h4>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>+-------------------------+-----------+\n| recvtime                | attrvalue |\n+-------------------------+-----------+\n| 2018-06-12T11:53:17.955 | 3         |\n| 2018-06-12T11:53:23.954 | 5         |\n| 2018-06-12T11:53:29.970 | 7         |\n| 2018-06-12T11:54:06.83  | 12        |\n| 2018-06-12T11:54:12.132 | 13        |\n| 2018-06-12T11:54:24.177 | 14        |\n| 2018-06-12T11:54:36.196 | 16        |\n| 2018-06-12T11:54:42.195 | 18        |\n| 2018-06-12T11:55:24.300 | 23        |\n| 2018-06-12T11:55:30.350 | 25        |\n+-------------------------+-----------+\n10 rows in set (0.00 sec)\n</code></pre><p>To leave the MySQL client and leave interactive mode, run the following:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">\\q\n</code></pre>\n<p> You will then return to the commmand line.</p>\n","event":[{"listen":"prerequest","script":{"id":"0a433918-9a68-4cbe-9bdc-031270322304","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"db11ec7d-1bde-4317-8318-db7b0ebf5c61","type":"text/javascript","exec":[""]}}],"_postman_id":"9d1b2b75-bf06-433c-9c46-b56e144dd8ca"},{"name":"Multi-Agent Persisting to Multiple Databases","item":[{"name":"Cygnus - Obtain version information","id":"6e2b6393-d1fe-45eb-93a3-aa79b9761132","request":{"method":"GET","header":[],"body":{"mode":"formdata","formdata":[]},"url":"http://localhost:5080/v1/version","description":"<p>Once Cygnus is running, You can check the status by making an HTTP request to the exposed <code>CYGNUS_API_PORT</code> port. \nIf the response is blank, this is usually because Cygnus is not running or is listening on another port.</p>\n<blockquote>\n<p><strong>Troubleshooting:</strong> What if the response is blank ?</p>\n<ul>\n<li>To check that a docker container is running try</li>\n</ul>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-bash\">docker ps\n</code></pre>\n<p>You should see several containers running. If <code>cygnus</code> is not running, you can restart the containers as necessary.</p>\n</blockquote>\n","urlObject":{"protocol":"http","path":["v1","version"],"host":["localhost:5080"],"query":[],"variable":[]}},"response":[],"_postman_id":"6e2b6393-d1fe-45eb-93a3-aa79b9761132"},{"name":"Orion - Subscribe to Context Changes","id":"250cd6ca-9ee6-4cbe-9fc1-9e097126fca0","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"fiware-service","value":"openiot"},{"key":"fiware-servicepath","value":"/"}],"body":{"mode":"raw","raw":"{\n  \"description\": \"Notify Cygnus of all context changes for MySQL on port 5050\",\n  \"subject\": {\n    \"entities\": [\n      {\n        \"idPattern\": \".*\"\n      }\n    ]\n  },\n  \"notification\": {\n    \"http\": {\n      \"url\": \"http://cygnus:5050/notify\"\n    }\n  },\n  \"throttling\": 5\n}"},"url":"http://localhost:1026/v2/subscriptions/","description":"<p>Once a dynamic context system is up and running, we need to inform <strong>Cygnus</strong> of changes in context.</p>\n<p>This is done by making a POST request to the <code>/v2/subscription</code> endpoint of the Orion Context Broker.</p>\n<ul>\n<li>The <code>fiware-service</code> and <code>fiware-servicepath</code> headers are used to filter the subscription to only listen to measurements from the attached IoT Sensors</li>\n<li>The <code>idPattern</code> in the request body ensures that Cygnus will be informed of all context data changes.</li>\n<li>The <code>attrsFormat=legacy</code> is required since Cygnus currently only accepts notifications in the older NGSI v1 format.</li>\n<li>The <code>throttling</code> value defines the rate that changes are sampled.</li>\n</ul>\n<p>When running in <strong>multi-agent</strong> mode, the  notification <code>url</code> for each subscription must match the defaults for the given database.</p>\n<p>The default port mapping can be seen below:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>sink</th>\n<th>port</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>mysql</td>\n<td>5050</td>\n</tr>\n<tr>\n<td>mongo</td>\n<td>5051</td>\n</tr>\n<tr>\n<td>ckan</td>\n<td>5052</td>\n</tr>\n<tr>\n<td>hdfs</td>\n<td>5053</td>\n</tr>\n<tr>\n<td>postgresql</td>\n<td>5054</td>\n</tr>\n<tr>\n<td>cartodb</td>\n<td>5055</td>\n</tr>\n</tbody>\n</table>\n</div><p>Since this subscription is using port <code>5050</code> the context data will eventually be persisted to the <em>MySQL</em> database.</p>\n","urlObject":{"protocol":"http","path":["v2","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"250cd6ca-9ee6-4cbe-9fc1-9e097126fca0"},{"name":"Orion - Check Subscription is working","id":"44b957e4-e2bf-4cf9-ad40-cadeb7da4d63","request":{"method":"GET","header":[{"key":"fiware-service","value":"openiot"},{"key":"fiware-servicepath","value":"/"}],"body":{"mode":"raw","raw":""},"url":"http://localhost:1026/v2/subscriptions/","description":"<p>If a subscription has been created, you can check to see if it is firing by making a GET \nrequest to the <code>/v2/subscriptions</code> endpoint.</p>\n<p>Within the <code>notification</code> section of the response, you can see several additional <code>attributes</code> which describe the health of the subscription</p>\n<p>If the criteria of the subscription have been met, <code>timesSent</code> should be greater than <code>0</code>.\nA zero value would indicate that the <code>subject</code> of the subscription is incorrect or the subscription \nhas created with the wrong <code>fiware-service-path</code> or <code>fiware-service</code> header</p>\n<p>The <code>lastNotification</code> should be a recent timestamp - if this is not the case, then the devices\nare not regularly sending data. Remember to unlock the <strong>Smart Door</strong> and switch on the <strong>Smart Lamp</strong></p>\n<p>The <code>lastSuccess</code> should match the <code>lastNotification</code> date - if this is not the case \nthen <strong>Cygnus</strong> is not receiving the subscription properly. Check that the host name\nand port are correct. </p>\n<p>Finally, check that the <code>status</code> of the subscription is <code>active</code> - an expired subscription\nwill not fire.</p>\n","urlObject":{"protocol":"http","path":["v2","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"44b957e4-e2bf-4cf9-ad40-cadeb7da4d63"}],"id":"2119b31f-dee7-441d-9a5b-ccbf4a3aed8f","description":"<p>It is also possible to configure Cygnus to populate multiple databases simultaneously. We can combine\nthe architecture from the three previous examples and configure cygnus to listen on multiple ports</p>\n<p><img src=\"https://fiware.github.io/tutorials.Historic-Context-Flume/img/cygnus-all-three.png\" alt /></p>\n<p>We now have a system with three databases, PostgreSQL and MySQL for data persistence and MongoDB \nfor both data persistence and holding data related to the Orion Context Broker and the IoT Agent. </p>\n<h2 id=\"cygnus-configuration-for-multiple-agents\">Cygnus Configuration for Multiple Agents</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-yaml\">cygnus:\n    image: fiware/cygnus-ngsi:latest\n    hostname: cygnus\n    container_name: fiware-cygnus\n    depends_on:\n      - mongo-db\n      - mysql-db\n      - postgres-db\n    networks:\n      - default\n    expose:\n      - \"5080\"\n      - \"5081\"\n      - \"5084\"\n    ports:\n      - \"5050:5050\"\n      - \"5051:5051\"\n      - \"5054:5054\"\n      - \"5080:5080\"\n      - \"5081:5081\"\n      - \"5084:5084\"\n    environment:\n      - \"CYGNUS_MULTIAGENT=true\"\n      - \"CYGNUS_POSTGRESQL_HOST=postgres-sb\"\n      - \"CYGNUS_POSTGRESQL_PORT=5432\"\n      - \"CYGNUS_POSTGRESQL_USER=postgres\" \n      - \"CYGNUS_POSTGRESQL_PASS=password\" \n      - \"CYGNUS_POSTGRESQL_ENABLE_CACHE=true\"\n      - \"CYGNUS_MYSQL_HOST=mysql-db\"\n      - \"CYGNUS_MYSQL_PORT=3306\"\n      - \"CYGNUS_MYSQL_USER=root\" \n      - \"CYGNUS_MYSQL_PASS=123\" \n      - \"CYGNUS_LOG_LEVEL=DEBUG\"\n</code></pre>\n<p>In multi-agent mode, the <code>cygnus</code> container is listening on multiple ports: </p>\n<ul>\n<li>The service will be listening on ports <code>5050-5055</code> for notifications from the Orion context broker</li>\n<li>Ports <code>5080-5085</code> are exposed purely for tutorial access - so that cUrl or Postman can make provisioning commands\nwithout being part of the same network.</li>\n</ul>\n<p>The default port mapping can be seen below:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>sink</th>\n<th>port</th>\n<th>admin_port</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>mysql</td>\n<td>5050</td>\n<td>5080</td>\n</tr>\n<tr>\n<td>mongo</td>\n<td>5051</td>\n<td>5081</td>\n</tr>\n<tr>\n<td>ckan</td>\n<td>5052</td>\n<td>5082</td>\n</tr>\n<tr>\n<td>hdfs</td>\n<td>5053</td>\n<td>5083</td>\n</tr>\n<tr>\n<td>postgresql</td>\n<td>5054</td>\n<td>5084</td>\n</tr>\n<tr>\n<td>cartodb</td>\n<td>5055</td>\n<td>5085</td>\n</tr>\n</tbody>\n</table>\n</div><p>Since we are not persisting CKAN, HDFS or CartoDB data, there is no need to open those ports.</p>\n<p>The <code>cygnus</code> container is driven by environment variables as shown:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Key</th>\n<th>Value</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>CYGNUS_MULTIAGENT</td>\n<td><code>true</code></td>\n<td>Whether to persist data into multiple databases.</td>\n</tr>\n<tr>\n<td>CYGNUS_MONGO_HOSTS</td>\n<td><code>mongo-db:27017</code></td>\n<td>Comma separated list of Mongo-DB servers which Cygnus will contact to persist historical context data</td>\n</tr>\n<tr>\n<td>CYGNUS_POSTGRESQL_HOST</td>\n<td><code>postgres-db</code></td>\n<td>Hostname of the PostgreSQL server used to persist historical context data</td>\n</tr>\n<tr>\n<td>CYGNUS_POSTGRESQL_PORT</td>\n<td><code>5432</code></td>\n<td>Port that the PostgreSQL server uses to listen to commands</td>\n</tr>\n<tr>\n<td>CYGNUS_POSTGRESQL_USER</td>\n<td><code>postgres</code></td>\n<td>Username for the PostgreSQL database user</td>\n</tr>\n<tr>\n<td>CYGNUS_POSTGRESQL_PASS</td>\n<td><code>password</code></td>\n<td>Password for the PostgreSQL database user</td>\n</tr>\n<tr>\n<td>CYGNUS_MYSQL_HOST</td>\n<td><code>mysql-db</code></td>\n<td>Hostname of the MySQL server used to persist historical context data</td>\n</tr>\n<tr>\n<td>CYGNUS_MYSQL_PORT</td>\n<td><code>3306</code></td>\n<td>Port that the MySQL server uses to listen to commands</td>\n</tr>\n<tr>\n<td>CYGNUS_MYSQL_USER</td>\n<td><code>root</code></td>\n<td>Username for the MySQL database user</td>\n</tr>\n<tr>\n<td>CYGNUS_MYSQL_PASS</td>\n<td><code>123</code></td>\n<td>Password for the MySQL database user</td>\n</tr>\n<tr>\n<td>CYGNUS_LOG_LEVEL</td>\n<td><code>DEBUG</code></td>\n<td>The logging level for Cygnus</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"multi-agent-start-up\">Multi-Agent Start up</h2>\n<p>To start the system with <strong>multiple</strong> databases run the following command:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">./services multiple\n</code></pre>\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.\nThe dummy IoT Sensors can be used to do this. Open the device monitor page at <code>http://localhost:3000/device/monitor</code>\nand unlock a <strong>Smart Door</strong> and switch on a <strong>Smart Lamp</strong>. This can be done by selecting an appropriate the command \nfrom the drop down list and pressing the <code>send</code> button. The stream of measurements coming from the devices can then\nbe seen on the same page:</p>\n<p><img src=\"https://fiware.github.io/tutorials.Historic-Context/img/door-open.gif\" alt /></p>\n","event":[{"listen":"prerequest","script":{"id":"1c3c984c-886c-464c-b936-a5b355263c89","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"cafefa9a-6026-45d2-8877-2298a955ba2d","type":"text/javascript","exec":[""]}}],"_postman_id":"2119b31f-dee7-441d-9a5b-ccbf4a3aed8f"},{"name":"HDFS -  Persisting Context","item":[{"name":"Cygnus - Obtain version information","id":"387b284b-b8a1-4ce9-8631-e6014b06319f","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"url":"http://localhost:5080/v1/version","description":"<p>Once Cygnus is running, You can check the status by making an HTTP request to the exposed <code>CYGNUS_API_PORT</code> port. \nIf the response is blank, this is usually because Cygnus is not running or is listening on another port.</p>\n<blockquote>\n<p><strong>Troubleshooting:</strong> What if the response is blank ?</p>\n<ul>\n<li>To check that a docker container is running try</li>\n</ul>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-bash\">docker ps\n</code></pre>\n<p>You should see several containers running. If <code>cygnus</code> is not running, you can restart the containers as necessary.</p>\n</blockquote>\n","urlObject":{"protocol":"http","path":["v1","version"],"host":["localhost:5080"],"query":[],"variable":[]}},"response":[],"_postman_id":"387b284b-b8a1-4ce9-8631-e6014b06319f"},{"name":"Orion - Subscribe to Context Changes","id":"f02788dd-897d-4736-96db-00e11f9b520e","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"fiware-service","value":"openiot"},{"key":"fiware-servicepath","value":"/"}],"body":{"mode":"raw","raw":"{\n  \"description\": \"Notify Cygnus of all context changes for HDFS on port 5053\",\n  \"subject\": {\n    \"entities\": [\n      {\n        \"idPattern\": \".*\"\n      }\n    ]\n  },\n  \"notification\": {\n    \"http\": {\n      \"url\": \"http://cygnus:5053/notify\"\n    }\n  },\n  \"throttling\": 5\n}"},"url":"http://localhost:1026/v2/subscriptions/","description":"<p>Once a dynamic context system is up and running, we need to inform <strong>Cygnus</strong> of changes in context.</p>\n<p>This is done by making a POST request to the <code>/v2/subscription</code> endpoint of the Orion Context Broker.</p>\n<ul>\n<li>The <code>fiware-service</code> and <code>fiware-servicepath</code> headers are used to filter the subscription to only listen to measurements from the attached IoT Sensors</li>\n<li>The <code>idPattern</code> in the request body ensures that Cygnus will be informed of all context data changes.</li>\n<li>The <code>attrsFormat=legacy</code> is required since Cygnus currently only accepts notifications in the older NGSI v1 format.</li>\n<li>The <code>throttling</code> value defines the rate that changes are sampled.</li>\n</ul>\n<p>When running in <strong>multi-agent</strong> mode, the  notification <code>url</code> for each subscription must match the defaults for the given database.</p>\n<p>The default port mapping can be seen below:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>sink</th>\n<th>port</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>mysql</td>\n<td>5050</td>\n</tr>\n<tr>\n<td>mongo</td>\n<td>5051</td>\n</tr>\n<tr>\n<td>ckan</td>\n<td>5052</td>\n</tr>\n<tr>\n<td>hdfs</td>\n<td>5053</td>\n</tr>\n<tr>\n<td>postgresql</td>\n<td>5054</td>\n</tr>\n<tr>\n<td>cartodb</td>\n<td>5055</td>\n</tr>\n</tbody>\n</table>\n</div><p>Since this subscription is using port <code>5050</code> the context data will eventually be persisted to the <em>MySQL</em> database.</p>\n","urlObject":{"protocol":"http","path":["v2","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"f02788dd-897d-4736-96db-00e11f9b520e"},{"name":"Orion - Check Subscription is working","id":"119bbb0c-7531-46df-83b9-89282c60f6ef","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"fiware-service","value":"openiot"},{"key":"fiware-servicepath","value":"/"}],"url":"http://localhost:1026/v2/subscriptions/","description":"<p>If a subscription has been created, you can check to see if it is firing by making a GET \nrequest to the <code>/v2/subscriptions</code> endpoint.</p>\n<p>Within the <code>notification</code> section of the response, you can see several additional <code>attributes</code> which describe the health of the subscription</p>\n<p>If the criteria of the subscription have been met, <code>timesSent</code> should be greater than <code>0</code>.\nA zero value would indicate that the <code>subject</code> of the subscription is incorrect or the subscription \nhas created with the wrong <code>fiware-service-path</code> or <code>fiware-service</code> header</p>\n<p>The <code>lastNotification</code> should be a recent timestamp - if this is not the case, then the devices\nare not regularly sending data. Remember to unlock the <strong>Smart Door</strong> and switch on the <strong>Smart Lamp</strong></p>\n<p>The <code>lastSuccess</code> should match the <code>lastNotification</code> date - if this is not the case \nthen <strong>Cygnus</strong> is not receiving the subscription properly. Check that the host name\nand port are correct. </p>\n<p>Finally, check that the <code>status</code> of the subscription is <code>active</code> - an expired subscription\nwill not fire.</p>\n","urlObject":{"protocol":"http","path":["v2","subscriptions",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"119bbb0c-7531-46df-83b9-89282c60f6ef"}],"id":"6bdaeb20-1fc0-49a8-904f-80f7aeb19a61","description":"<p>It is also possible to configure Cygnus to populate multiple databases simultaneously. We can combine\nthe architecture from the three previous examples and configure cygnus to listen on multiple ports</p>\n<p><img src=\"https://fiware.github.io/tutorials.Historic-Context-Flume/img/cygnus-all-three.png\" alt /></p>\n<p>We now have a system with three databases, PostgreSQL and MySQL for data persistence and MongoDB \nfor both data persistence and holding data related to the Orion Context Broker and the IoT Agent. </p>\n<h2 id=\"cygnus-configuration-for-multiple-agents\">Cygnus Configuration for Multiple Agents</h2>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-yaml\">cygnus:\n    image: fiware/cygnus-ngsi:latest\n    hostname: cygnus\n    container_name: fiware-cygnus\n    depends_on:\n      - mongo-db\n      - mysql-db\n      - postgres-db\n    networks:\n      - default\n    expose:\n      - \"5080\"\n      - \"5081\"\n      - \"5084\"\n    ports:\n      - \"5050:5050\"\n      - \"5051:5051\"\n      - \"5054:5054\"\n      - \"5080:5080\"\n      - \"5081:5081\"\n      - \"5084:5084\"\n    environment:\n      - \"CYGNUS_MULTIAGENT=true\"\n      - \"CYGNUS_POSTGRESQL_HOST=postgres-sb\"\n      - \"CYGNUS_POSTGRESQL_PORT=5432\"\n      - \"CYGNUS_POSTGRESQL_USER=postgres\" \n      - \"CYGNUS_POSTGRESQL_PASS=password\" \n      - \"CYGNUS_POSTGRESQL_ENABLE_CACHE=true\"\n      - \"CYGNUS_MYSQL_HOST=mysql-db\"\n      - \"CYGNUS_MYSQL_PORT=3306\"\n      - \"CYGNUS_MYSQL_USER=root\" \n      - \"CYGNUS_MYSQL_PASS=123\" \n      - \"CYGNUS_LOG_LEVEL=DEBUG\"\n</code></pre>\n<p>In multi-agent mode, the <code>cygnus</code> container is listening on multiple ports: </p>\n<ul>\n<li>The service will be listening on ports <code>5050-5055</code> for notifications from the Orion context broker</li>\n<li>Ports <code>5080-5085</code> are exposed purely for tutorial access - so that cUrl or Postman can make provisioning commands\nwithout being part of the same network.</li>\n</ul>\n<p>The default port mapping can be seen below:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>sink</th>\n<th>port</th>\n<th>admin_port</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>mysql</td>\n<td>5050</td>\n<td>5080</td>\n</tr>\n<tr>\n<td>mongo</td>\n<td>5051</td>\n<td>5081</td>\n</tr>\n<tr>\n<td>ckan</td>\n<td>5052</td>\n<td>5082</td>\n</tr>\n<tr>\n<td>hdfs</td>\n<td>5053</td>\n<td>5083</td>\n</tr>\n<tr>\n<td>postgresql</td>\n<td>5054</td>\n<td>5084</td>\n</tr>\n<tr>\n<td>cartodb</td>\n<td>5055</td>\n<td>5085</td>\n</tr>\n</tbody>\n</table>\n</div><p>Since we are not persisting CKAN, HDFS or CartoDB data, there is no need to open those ports.</p>\n<p>The <code>cygnus</code> container is driven by environment variables as shown:</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Key</th>\n<th>Value</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>CYGNUS_MULTIAGENT</td>\n<td><code>true</code></td>\n<td>Whether to persist data into multiple databases.</td>\n</tr>\n<tr>\n<td>CYGNUS_MONGO_HOSTS</td>\n<td><code>mongo-db:27017</code></td>\n<td>Comma separated list of Mongo-DB servers which Cygnus will contact to persist historical context data</td>\n</tr>\n<tr>\n<td>CYGNUS_POSTGRESQL_HOST</td>\n<td><code>postgres-db</code></td>\n<td>Hostname of the PostgreSQL server used to persist historical context data</td>\n</tr>\n<tr>\n<td>CYGNUS_POSTGRESQL_PORT</td>\n<td><code>5432</code></td>\n<td>Port that the PostgreSQL server uses to listen to commands</td>\n</tr>\n<tr>\n<td>CYGNUS_POSTGRESQL_USER</td>\n<td><code>postgres</code></td>\n<td>Username for the PostgreSQL database user</td>\n</tr>\n<tr>\n<td>CYGNUS_POSTGRESQL_PASS</td>\n<td><code>password</code></td>\n<td>Password for the PostgreSQL database user</td>\n</tr>\n<tr>\n<td>CYGNUS_MYSQL_HOST</td>\n<td><code>mysql-db</code></td>\n<td>Hostname of the MySQL server used to persist historical context data</td>\n</tr>\n<tr>\n<td>CYGNUS_MYSQL_PORT</td>\n<td><code>3306</code></td>\n<td>Port that the MySQL server uses to listen to commands</td>\n</tr>\n<tr>\n<td>CYGNUS_MYSQL_USER</td>\n<td><code>root</code></td>\n<td>Username for the MySQL database user</td>\n</tr>\n<tr>\n<td>CYGNUS_MYSQL_PASS</td>\n<td><code>123</code></td>\n<td>Password for the MySQL database user</td>\n</tr>\n<tr>\n<td>CYGNUS_LOG_LEVEL</td>\n<td><code>DEBUG</code></td>\n<td>The logging level for Cygnus</td>\n</tr>\n</tbody>\n</table>\n</div><h2 id=\"multi-agent-start-up\">Multi-Agent Start up</h2>\n<p>To start the system with <strong>multiple</strong> databases run the following command:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-console\">./services multiple\n</code></pre>\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.\nThe dummy IoT Sensors can be used to do this. Open the device monitor page at <code>http://localhost:3000/device/monitor</code>\nand unlock a <strong>Smart Door</strong> and switch on a <strong>Smart Lamp</strong>. This can be done by selecting an appropriate the command \nfrom the drop down list and pressing the <code>send</code> button. The stream of measurements coming from the devices can then\nbe seen on the same page:</p>\n<p><img src=\"https://fiware.github.io/tutorials.Historic-Context/img/door-open.gif\" alt /></p>\n","event":[{"listen":"prerequest","script":{"id":"1c3c984c-886c-464c-b936-a5b355263c89","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"cafefa9a-6026-45d2-8877-2298a955ba2d","type":"text/javascript","exec":[""]}}],"_postman_id":"6bdaeb20-1fc0-49a8-904f-80f7aeb19a61"}],"event":[{"listen":"prerequest","script":{"id":"d1cff9ac-8932-417c-b6e2-582ba712ff79","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"cc3f098c-a786-4112-a15e-b1c8c83cc657","type":"text/javascript","exec":[""]}}],"variable":[{"key":"orion","value":"localhost:1026"},{"key":"cygnus","value":"localhost:5080"}]}