diff --git a/showcase-dev/examples/datasource-sweapifetch/datasource-sweapifetch.html b/showcase-dev/examples/datasource-consysapi/datasource-consysapi.html
similarity index 100%
rename from showcase-dev/examples/datasource-sweapifetch/datasource-sweapifetch.html
rename to showcase-dev/examples/datasource-consysapi/datasource-consysapi.html
diff --git a/showcase-dev/examples/datasource-sweapifetch/datasource-sweapifetch.js b/showcase-dev/examples/datasource-consysapi/datasource-consysapi.js
similarity index 76%
rename from showcase-dev/examples/datasource-sweapifetch/datasource-sweapifetch.js
rename to showcase-dev/examples/datasource-consysapi/datasource-consysapi.js
index 4ee4225ca1..199a296213 100644
--- a/showcase-dev/examples/datasource-sweapifetch/datasource-sweapifetch.js
+++ b/showcase-dev/examples/datasource-consysapi/datasource-consysapi.js
@@ -1,9 +1,9 @@
 import {EventType} from 'osh-js/core/event/EventType';
-// #region snippet_datasource_sweapifetch
-import SweApiFetch from "osh-js/core/datasource/sweapi/SweApi.datasource.js";
+// #region snippet_datasource_consysapi
+import ConSysApi from "osh-js/core/datasource/consysapi/ConSysApi.datasource.js";
 import {Mode} from "osh-js/core/datasource/Mode";
 
-let gpsDataSource = new SweApiFetch("android-GPS", {
+let gpsDataSource = new ConSysApi("android-GPS", {
   endpointUrl: 'api.georobotix.io/ogc/t18/api',
   resource: '/datastreams/o7pce3e60s0ie/observations',
   tls: true,
@@ -15,7 +15,7 @@ let gpsDataSource = new SweApiFetch("android-GPS", {
   mode : Mode.REAL_TIME
 });
 
-// #endregion snippet_datasource_sweapifetch
+// #endregion snippet_datasource_consysapi
 
 gpsDataSource.subscribe(async (message) => {
   let dataEvent;
diff --git a/showcase-dev/examples/datasource-sweapifetch/package.json b/showcase-dev/examples/datasource-consysapi/package.json
similarity index 100%
rename from showcase-dev/examples/datasource-sweapifetch/package.json
rename to showcase-dev/examples/datasource-consysapi/package.json
diff --git a/showcase-dev/examples/datasource-sweapifetch/webpack.config.js b/showcase-dev/examples/datasource-consysapi/webpack.config.js
similarity index 90%
rename from showcase-dev/examples/datasource-sweapifetch/webpack.config.js
rename to showcase-dev/examples/datasource-consysapi/webpack.config.js
index bbda5fc140..2ca343f4d5 100644
--- a/showcase-dev/examples/datasource-sweapifetch/webpack.config.js
+++ b/showcase-dev/examples/datasource-consysapi/webpack.config.js
@@ -8,10 +8,10 @@ const CopyWebpackPlugin = require("copy-webpack-plugin");
 
 module.exports = {
     // Tell Webpack which file kicks off our app.
-    entry: path.resolve(__dirname,'./datasource-sweapifetch.js'),
+    entry: path.resolve(__dirname,'./datasource-consysapi.js'),
     // Tell Weback to output our bundle to ./dist/bundle.js
     output: {
-        filename: 'bundle.datasource.sweapifetch.js',
+        filename: 'bundle.datasource.consysapi.js',
         path: path.resolve(__dirname, 'dist')
     },
     // Tell Webpack which directories to look in to resolve import statements.
@@ -53,7 +53,7 @@ module.exports = {
         compress: true,
         port: 9000,
         hot: true,
-        index: 'datasource-sweapifetch.html',
+        index: 'datasource-consysapi.html',
         https:true
     },
     devtool: 'source-map',
@@ -74,8 +74,8 @@ module.exports = {
         // by the Webpack dev server. We can give it a template file (written in EJS)
         // and it will handle injecting our bundle for us.
         new HtmlWebpackPlugin({
-            filename: "datasource-sweapifetch.html",
-            template: path.resolve(__dirname, 'datasource-sweapifetch.html')
+            filename: "datasource-consysapi.html",
+            template: path.resolve(__dirname, 'datasource-consysapi.html')
         }),
         new CopyWebpackPlugin([
             { from: path.resolve(__dirname,'data'), to: 'data'}
diff --git a/showcase-dev/examples/datasynchronizer-dynamic-add-remove-realtime/datasynchronizer-dynamic-add-remove-realtime.js b/showcase-dev/examples/datasynchronizer-dynamic-add-remove-realtime/datasynchronizer-dynamic-add-remove-realtime.js
index 912a8a3b6a..901610e7a4 100644
--- a/showcase-dev/examples/datasynchronizer-dynamic-add-remove-realtime/datasynchronizer-dynamic-add-remove-realtime.js
+++ b/showcase-dev/examples/datasynchronizer-dynamic-add-remove-realtime/datasynchronizer-dynamic-add-remove-realtime.js
@@ -1,5 +1,5 @@
 import {EventType} from 'osh-js/core/event/EventType';
-import SweApiDatasource from "osh-js/core/datasource/sweapi/SweApi.datasource.js";
+import ConSysApi from "osh-js/core/datasource/consysapi/ConSysApi.datasource.js";
 import {Mode} from "osh-js/core/datasource/Mode";
 import DataSynchronizer from "../../../source/core/timesync/DataSynchronizer";
 
@@ -14,19 +14,19 @@ const commonDatasourceOpts = {
   },
 };
 
-const ds0 = new SweApiDatasource('MISB Drone - Video', {
+const ds0 = new ConSysApi('MISB Drone - Video', {
   ...commonDatasourceOpts,
   resource: '/datastreams/h225hesual08g/observations',
   responseFormat: 'application/swe+binary',
 });
 
-const ds1 = new SweApiDatasource('MISB UAS - Platform Location', {
+const ds1 = new ConSysApi('MISB UAS - Platform Location', {
   ...commonDatasourceOpts,
   resource: '/datastreams/o7pce3e60s0ie/observations',
   responseFormat: 'application/swe+json',
 });
 
-const ds2 = new SweApiDatasource('MISB UAS - Platform Attitude', {
+const ds2 = new ConSysApi('MISB UAS - Platform Attitude', {
   ...commonDatasourceOpts,
   resource: '/datastreams/mlme3gtdfepvc/observations',
   responseFormat: 'application/swe+json',
diff --git a/showcase-dev/examples/datasynchronizer-dynamic-add-remove-replay/datasynchronizer-dynamic-add-remove-replay.js b/showcase-dev/examples/datasynchronizer-dynamic-add-remove-replay/datasynchronizer-dynamic-add-remove-replay.js
index 5be98782da..2097f31666 100644
--- a/showcase-dev/examples/datasynchronizer-dynamic-add-remove-replay/datasynchronizer-dynamic-add-remove-replay.js
+++ b/showcase-dev/examples/datasynchronizer-dynamic-add-remove-replay/datasynchronizer-dynamic-add-remove-replay.js
@@ -1,5 +1,5 @@
 import {EventType} from 'osh-js/core/event/EventType';
-import SweApiDatasource from "osh-js/core/datasource/sweapi/SweApi.datasource.js";
+import ConSysApi from "osh-js/core/datasource/consysapi/ConSysApi.datasource.js";
 import {Mode} from "osh-js/core/datasource/Mode";
 import DataSynchronizer from "../../../source/core/timesync/DataSynchronizer";
 
@@ -18,19 +18,19 @@ const commonDatasourceOpts = {
   prefetchBatchSize: 50
 };
 
-const ds0 = new SweApiDatasource('MISB Drone - Video', {
+const ds0 = new ConSysApi('MISB Drone - Video', {
   ...commonDatasourceOpts,
   resource: '/datastreams/8ni90dbu4uf0g/observations',
   responseFormat: 'application/swe+binary',
 });
 
-const ds1 = new SweApiDatasource('MISB UAS - Platform Location', {
+const ds1 = new ConSysApi('MISB UAS - Platform Location', {
   ...commonDatasourceOpts,
   resource: '/datastreams/fled6eics1cl4/observations',
   responseFormat: 'application/swe+json',
 });
 
-const ds2 = new SweApiDatasource('MISB UAS - Platform Attitude', {
+const ds2 = new ConSysApi('MISB UAS - Platform Attitude', {
   ...commonDatasourceOpts,
   resource: '/datastreams/adheadf9nghts/observations',
   responseFormat: 'application/swe+json',
diff --git a/showcase-dev/examples/mqtt-utility/mqtt-utility.js b/showcase-dev/examples/mqtt-utility/mqtt-utility.js
index c6046f97a1..51c73b2784 100644
--- a/showcase-dev/examples/mqtt-utility/mqtt-utility.js
+++ b/showcase-dev/examples/mqtt-utility/mqtt-utility.js
@@ -1,6 +1,6 @@
 import MqttProvider from "osh-js/core/mqtt/MqttProvider";
 import {randomUUID} from "osh-js/core/utils/Utils";
-import ObservationFilter from "../../../source/core/sweapi/observation/ObservationFilter";
+import ObservationFilter from "../../../source/core/consysapi/observation/ObservationFilter";
 
 const textAreaElement0 =  document.getElementById("data-container0");
 const textAreaElement1 =  document.getElementById("data-container1");
diff --git a/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.html b/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.html
index 19afc9fbcc..e786514090 100644
--- a/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.html
+++ b/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.html
@@ -29,7 +29,7 @@
     <select name="services" id="services" size="1">
         <option value=""></option>
         <option value="sos">sos</option>
-        <option value="sweapi">sweapi</option>
+        <option value="consysapi">consysapi</option>
     </select>
     <button id="replay">Replay</button>
     <button id="realtime">RealTime</button>
diff --git a/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.js b/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.js
index 02fe90a551..1f760b8206 100644
--- a/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.js
+++ b/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.js
@@ -4,7 +4,7 @@ import CurveLayer from 'osh-js/core/ui/layer/CurveLayer.js';
 import SosGetResult from 'osh-js/core/datasource/sos/SosGetResult.datasource.js';
 import {Mode} from 'osh-js/core/datasource/Mode';
 import DataSynchronizer from "../../../source/core/timesync/DataSynchronizer";
-import SweApiDatasource from "../../../source/core/datasource/sweapi/SweApi.datasource";
+import ConSysApi from "../../../source/core/datasource/consysapi/ConSysApi.datasource";
 import {EventType} from "../../../source/core/event/EventType";
 
 function getRandomArbitrary(min, max) {
@@ -17,7 +17,7 @@ const dataContentElt = document.getElementById("data-content");
 const masterTimeElt = document.getElementById("master-time");
 
 let initSos = false;
-let initSweapi = false;
+let initConsysapi = false;
 
 let chartDataSource = new SosGetResult("weather", {
     endpointUrl: "sensiasoft.net/sensorhub/sos",
@@ -38,7 +38,7 @@ const sosDataSynchronizer = new DataSynchronizer({
 });
 
 async function startSosExample() {
-    await sweapiDataSynchronizer.disconnect();
+    await consysapiDataSynchronizer.disconnect();
     replayButtonElt.onclick = async () => {
         await sosDataSynchronizer.setTimeRange(
             new Date(Date.now() - 60 * 1000 * 60 * 2).toISOString(),
@@ -105,19 +105,19 @@ const commonDatasourceOpts = {
     prefetchBatchSize: 250
 };
 
-const droneLocationDataSource = new SweApiDatasource('MISB UAS - Platform Location', {
+const droneLocationDataSource = new ConSysApi('MISB UAS - Platform Location', {
     ...commonDatasourceOpts,
     resource: '/datastreams/fled6eics1cl4/observations',
     responseFormat: 'application/swe+json',
 });
 
-const droneOrientationDataSource = new SweApiDatasource('MISB UAS - Platform Attitude', {
+const droneOrientationDataSource = new ConSysApi('MISB UAS - Platform Attitude', {
     ...commonDatasourceOpts,
     resource: '/datastreams/adheadf9nghts/observations',
     responseFormat: 'application/swe+json',
 });
 
-const sweapiDataSynchronizer = new DataSynchronizer({
+const consysapiDataSynchronizer = new DataSynchronizer({
     replaySpeed: 2,
     masterTimeRefreshRate: 250,
     startTime: START_TIME,
@@ -125,11 +125,11 @@ const sweapiDataSynchronizer = new DataSynchronizer({
     dataSources: [droneOrientationDataSource, droneLocationDataSource]
 });
 
-async function startSweApiExample() {
+async function startConSysApiExample() {
     await sosDataSynchronizer.disconnect();
     replayButtonElt.onclick = async () => {
-        await sweapiDataSynchronizer.setMode(Mode.REPLAY);
-        // await sweapiDataSynchronizer.setTimeRange(
+        await consysapiDataSynchronizer.setMode(Mode.REPLAY);
+        // await consysapiDataSynchronizer.setTimeRange(
         //     START_TIME,
         //     END_TIME,
         //     2.0,
@@ -138,12 +138,12 @@ async function startSweApiExample() {
         // );
         replayButtonElt.disabled = true;
         realtimeButtonElt.disabled = false;
-        await sweapiDataSynchronizer.connect();
+        await consysapiDataSynchronizer.connect();
     }
 
     realtimeButtonElt.onclick = async () => {
-        await sweapiDataSynchronizer.setMode(Mode.REAL_TIME);
-        // await sweapiDataSynchronizer.setTimeRange(
+        await consysapiDataSynchronizer.setMode(Mode.REAL_TIME);
+        // await consysapiDataSynchronizer.setTimeRange(
         //     'now',
         //     '2055-01-01',
         //     1.0,
@@ -153,11 +153,11 @@ async function startSweApiExample() {
         realtimeButtonElt.disabled = true;
         replayButtonElt.disabled = false;
 
-        await sweapiDataSynchronizer.connect();
+        await consysapiDataSynchronizer.connect();
     }
 
-    sweapiDataSynchronizer.subscribe(message => displayData(message), [EventType.DATA]);
-    sweapiDataSynchronizer.subscribe(message => displayMasterTime(message), [EventType.MASTER_TIME]);
+    consysapiDataSynchronizer.subscribe(message => displayData(message), [EventType.DATA]);
+    consysapiDataSynchronizer.subscribe(message => displayMasterTime(message), [EventType.MASTER_TIME]);
 }
 
 const listBoxElement = document.getElementById('services');
@@ -165,8 +165,8 @@ listBoxElement.onchange = (event) => {
     let value = event.target.value;
     if(value === 'sos') {
         startSosExample();
-    } else if(value === 'sweapi') {
-        startSweApiExample()
+    } else if(value === 'consysapi') {
+        startConSysApiExample()
     }
 }
 
diff --git a/showcase-dev/index.js b/showcase-dev/index.js
index b5190e2cf1..a1ae7c7c47 100644
--- a/showcase-dev/index.js
+++ b/showcase-dev/index.js
@@ -21,13 +21,13 @@ var samples = [
         url: "datasource-file"
     },
     {
-        name: "DataSource SweApiFetch",
-        description: "Display GPS data using the SweApiFetch datasource",
-        url: "datasource-sweapifetch"
+        name: "Connected Systems DataSource",
+        description: "Display GPS data using the ConSysApi datasource",
+        url: "datasource-consysapi"
     },
     {
-        name: "DataSource SweApiFetch Json",
-        description: "Display data using the SweApiFetch datasource in JSON format",
+        name: "SOS DataSource Swe Json",
+        description: "Display data using the SOS datasource in SWE JSON format",
         url: "datasource-swejson"
     },
     {
@@ -56,8 +56,8 @@ var samples = [
         url: "multi-datasources-synchronized"
     },
     {
-        name: 'Switch between Replay & realtime using SOS or SWEAPI service',
-        description: 'Switch between Replay & realtime using SOS or SWEAPI service',
+        name: 'Switch between Replay & realtime using SOS or Connected Systems API service',
+        description: 'Switch between Replay & realtime using SOS or Connected Systems API service',
         url: 'switch-realtime-batch'
     },
     {
diff --git a/showcase-dev/webpack.config.js b/showcase-dev/webpack.config.js
index 6868f0d1ea..29f0ec0e49 100644
--- a/showcase-dev/webpack.config.js
+++ b/showcase-dev/webpack.config.js
@@ -77,7 +77,7 @@ module.exports = [{
 let directories = [
     'datasource-audio',
     'datasource-file',
-    'datasource-sweapifetch',
+    'datasource-consysapi',
     'datasource-swejson',
     'datasource-video',
     'datasources-synchronized',
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/.browserslistrc b/showcase/examples/chart-archive-realtime-synchronized-consysapi/.browserslistrc
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/.browserslistrc
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/.browserslistrc
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/.eslintignore b/showcase/examples/chart-archive-realtime-synchronized-consysapi/.eslintignore
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/.eslintignore
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/.eslintignore
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/.eslintrc.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/.eslintrc.js
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/.eslintrc.js
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/.eslintrc.js
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/.gitignore b/showcase/examples/chart-archive-realtime-synchronized-consysapi/.gitignore
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/.gitignore
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/.gitignore
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/README.md b/showcase/examples/chart-archive-realtime-synchronized-consysapi/README.md
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/README.md
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/README.md
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/babel.config.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/babel.config.js
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/babel.config.js
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/babel.config.js
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/chart-archive-realtime-synchronized-sweapi.html b/showcase/examples/chart-archive-realtime-synchronized-consysapi/chart-archive-realtime-synchronized-consysapi.html
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/chart-archive-realtime-synchronized-sweapi.html
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/chart-archive-realtime-synchronized-consysapi.html
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/chart-archive-realtime-synchronized-sweapi.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/chart-archive-realtime-synchronized-consysapi.js
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/chart-archive-realtime-synchronized-sweapi.js
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/chart-archive-realtime-synchronized-consysapi.js
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/favicon.ico b/showcase/examples/chart-archive-realtime-synchronized-consysapi/favicon.ico
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/favicon.ico
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/favicon.ico
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-192x192.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-192x192.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-192x192.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-192x192.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-512x512.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-512x512.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-512x512.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-512x512.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-maskable-192x192.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-maskable-192x192.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-maskable-192x192.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-maskable-192x192.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-maskable-512x512.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-maskable-512x512.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-maskable-512x512.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-maskable-512x512.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-120x120.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-120x120.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-120x120.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-120x120.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-152x152.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-152x152.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-152x152.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-152x152.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-180x180.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-180x180.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-180x180.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-180x180.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-60x60.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-60x60.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-60x60.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-60x60.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-76x76.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-76x76.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-76x76.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-76x76.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/favicon-16x16.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/favicon-16x16.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/favicon-16x16.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/favicon-16x16.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/favicon-32x32.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/favicon-32x32.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/favicon-32x32.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/favicon-32x32.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/msapplication-icon-144x144.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/msapplication-icon-144x144.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/msapplication-icon-144x144.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/msapplication-icon-144x144.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/mstile-150x150.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/mstile-150x150.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/mstile-150x150.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/mstile-150x150.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/safari-pinned-tab.svg b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/safari-pinned-tab.svg
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/safari-pinned-tab.svg
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/safari-pinned-tab.svg
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/main.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/main.js
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/main.js
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/main.js
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/package.json b/showcase/examples/chart-archive-realtime-synchronized-consysapi/package.json
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/package.json
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/package.json
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/patches/nouislider+14.4.0.patch b/showcase/examples/chart-archive-realtime-synchronized-consysapi/patches/nouislider+14.4.0.patch
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/patches/nouislider+14.4.0.patch
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/patches/nouislider+14.4.0.patch
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/robots.txt b/showcase/examples/chart-archive-realtime-synchronized-consysapi/robots.txt
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/robots.txt
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/robots.txt
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/src/App.vue b/showcase/examples/chart-archive-realtime-synchronized-consysapi/src/App.vue
similarity index 94%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/src/App.vue
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/src/App.vue
index a97607cb1b..c28dd9a64e 100644
--- a/showcase/examples/chart-archive-realtime-synchronized-sweapi/src/App.vue
+++ b/showcase/examples/chart-archive-realtime-synchronized-consysapi/src/App.vue
@@ -18,7 +18,7 @@ import TimeController from 'osh-js/vue/components/TimeController.vue';
 
 import DataSynchronizer from 'osh-js/core/timesync/DataSynchronizer';
 import {Mode} from 'osh-js/core/datasource/Mode';
-import SweApiDatasource from "osh-js/core/datasource/sweapi/SweApi.datasource";
+import ConSysApi from "osh-js/core/datasource/consysapi/ConSysApi.datasource.js";
 
 export default {
   components: {
@@ -55,7 +55,7 @@ export default {
       prefetchBatchSize: 250
     };
 
-    const chartDataSource1 = new SweApiDatasource('Simulated Weather Sensor - weather', {
+    const chartDataSource1 = new ConSysApi('Simulated Weather Sensor - weather', {
       ...commonDatasourceOpts,
       resource: '/datastreams/0tsop3f16nvp8/observations',
       responseFormat: 'application/swe+json',
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/src/assets/logo.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/src/assets/logo.png
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/src/assets/logo.png
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/src/assets/logo.png
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/src/config/index.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/src/config/index.js
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/src/config/index.js
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/src/config/index.js
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/src/main.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/src/main.js
similarity index 100%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/src/main.js
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/src/main.js
diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/webpack.config.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/webpack.config.js
similarity index 90%
rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/webpack.config.js
rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/webpack.config.js
index c8e2b0315f..9c2d627a55 100644
--- a/showcase/examples/chart-archive-realtime-synchronized-sweapi/webpack.config.js
+++ b/showcase/examples/chart-archive-realtime-synchronized-consysapi/webpack.config.js
@@ -8,9 +8,9 @@ const path = require('path');
 
 // Now, using the cesiumConfig in your real configuration
 const config = {
-  entry: path.resolve(__dirname,'chart-archive-realtime-synchronized-sweapi.js'),
+  entry: path.resolve(__dirname,'chart-archive-realtime-synchronized-consysapi.js'),
   output: {
-    filename: 'bundle.chart-archive-realtime-synchronized-sweapi.js',
+    filename: 'bundle.chart-archive-realtime-synchronized-consysapi.js',
     path: path.resolve(__dirname, 'dist'),
   },
 
@@ -85,15 +85,15 @@ const config = {
     compress: true,
     port: 9000,
     hot: true,
-    index: 'chart-archive-realtime-synchronized-sweapi.html',
+    index: 'chart-archive-realtime-synchronized-consysapi.html',
     https:true
   },
   plugins: [
     new VueLoaderPlugin(),
     new CleanWebpackPlugin(),
     new HtmlWebpackPlugin({
-      template: path.resolve(__dirname, 'chart-archive-realtime-synchronized-sweapi.html'),
-      filename: './chart-archive-realtime-synchronized-sweapi.html',
+      template: path.resolve(__dirname, 'chart-archive-realtime-synchronized-consysapi.html'),
+      filename: './chart-archive-realtime-synchronized-consysapi.html',
       favicon: path.resolve(__dirname,'favicon.ico')
     }),
     new DefinePlugin({
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.browserslistrc b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/.browserslistrc
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.browserslistrc
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/.browserslistrc
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.eslintignore b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/.eslintignore
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.eslintignore
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/.eslintignore
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.eslintrc.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/.eslintrc.js
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.eslintrc.js
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/.eslintrc.js
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.gitignore b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/.gitignore
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.gitignore
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/.gitignore
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/README.md b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/README.md
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/README.md
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/README.md
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/babel.config.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/babel.config.js
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/babel.config.js
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/babel.config.js
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/favicon.ico b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/favicon.ico
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/favicon.ico
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/favicon.ico
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-192x192.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-192x192.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-192x192.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-192x192.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-512x512.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-512x512.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-512x512.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-512x512.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-192x192.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-192x192.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-192x192.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-192x192.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-512x512.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-512x512.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-512x512.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-512x512.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-120x120.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-120x120.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-120x120.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-120x120.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-152x152.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-152x152.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-152x152.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-152x152.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-180x180.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-180x180.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-180x180.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-180x180.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-60x60.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-60x60.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-60x60.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-60x60.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-76x76.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-76x76.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-76x76.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-76x76.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/favicon-16x16.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/favicon-16x16.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/favicon-16x16.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/favicon-16x16.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/favicon-32x32.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/favicon-32x32.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/favicon-32x32.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/favicon-32x32.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/msapplication-icon-144x144.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/msapplication-icon-144x144.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/msapplication-icon-144x144.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/msapplication-icon-144x144.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/mstile-150x150.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/mstile-150x150.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/mstile-150x150.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/mstile-150x150.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/safari-pinned-tab.svg b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/safari-pinned-tab.svg
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/safari-pinned-tab.svg
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/safari-pinned-tab.svg
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/main.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/main.js
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/main.js
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/main.js
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/package.json b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/package.json
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/package.json
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/package.json
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/patches/nouislider+14.4.0.patch b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/patches/nouislider+14.4.0.patch
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/patches/nouislider+14.4.0.patch
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/patches/nouislider+14.4.0.patch
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/robots.txt b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/robots.txt
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/robots.txt
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/robots.txt
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/App.vue b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/App.vue
similarity index 93%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/App.vue
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/App.vue
index 4d505c0e22..08a7919ccd 100644
--- a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/App.vue
+++ b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/App.vue
@@ -19,7 +19,7 @@
 import TimeController from 'osh-js/vue/components/TimeController.vue';
 import FFMPEGView from 'osh-js/core/ui/view/video/FFMPEGView';
 import DataSynchronizer from 'osh-js/core/timesync/DataSynchronizer';
-import SweApiFetch from 'osh-js/core/datasource/sweapi/SweApi.datasource.js';
+import ConSysApi from 'osh-js/core/datasource/consysapi/ConSysApi.datasource.js';
 import {Mode} from 'osh-js/core/datasource/Mode';
 import VideoView from 'osh-js/core/ui/view/video/VideoView';
 import VideoDataLayer from 'osh-js/core/ui/layer/VideoDataLayer';
@@ -49,19 +49,19 @@ export default {
       prefetchBatchSize: 250
     };
 
-    const dataSource0 = new SweApiFetch("drone-Video", {
+    const dataSource0 = new ConSysApi("drone-Video", {
       ...opts
     });
 
-    const dataSource1 = new SweApiFetch("drone-Video1", {
+    const dataSource1 = new ConSysApi("drone-Video1", {
       ...opts
     });
 
-    const dataSource2 = new SweApiFetch("drone-Video2", {
+    const dataSource2 = new ConSysApi("drone-Video2", {
       ...opts
     });
 
-    const dataSource3 = new SweApiFetch("drone-Video3", {
+    const dataSource3 = new ConSysApi("drone-Video3", {
       ...opts
     });
 
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/assets/logo.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/assets/logo.png
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/assets/logo.png
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/assets/logo.png
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/config/index.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/config/index.js
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/config/index.js
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/config/index.js
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/main.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/main.js
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/main.js
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/main.js
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.html b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.html
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.html
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.html
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.js
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.js
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.js
diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/webpack.config.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/webpack.config.js
similarity index 100%
rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/webpack.config.js
rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/webpack.config.js
diff --git a/showcase/examples/mqtt/mqtt.js b/showcase/examples/mqtt/mqtt.js
index e7fd0c9a61..a11c67f40a 100644
--- a/showcase/examples/mqtt/mqtt.js
+++ b/showcase/examples/mqtt/mqtt.js
@@ -1,5 +1,5 @@
 // create data source for Android phone GPS
-import SweApiFetch from 'osh-js/core/datasource/sweapi/SweApi.datasource.js';
+import ConSysApi from 'osh-js/core/datasource/consysapi/ConSysApi.datasource.js';
 import PointMarkerLayer from 'osh-js/core/ui/layer/PointMarkerLayer.js';
 import LeafletView from 'osh-js/core/ui/view/map/LeafletView.js';
 import ChartJsView from 'osh-js/core/ui/view/chart/ChartJsView';
@@ -16,7 +16,7 @@ const mqttProps = {
     password: 'WR6zlso9h#'
 };
 
-let gpsDataSource = new SweApiFetch("android-GPS", {
+let gpsDataSource = new ConSysApi("android-GPS", {
     endpointUrl:  'api.georobotix.io/ogc/t18/api',
     resource: '/datastreams/rbnag2hrc04mm/observations',
     tls: true,
@@ -25,7 +25,7 @@ let gpsDataSource = new SweApiFetch("android-GPS", {
     mode: Mode.REAL_TIME
 });
 
-const isaDataSource = new SweApiFetch("ISA-bio-sensor", {
+const isaDataSource = new ConSysApi("ISA-bio-sensor", {
     endpointUrl:  'api.georobotix.io/ogc/t18/api',
     resource: '/datastreams/b4runsn23q66o/observations',
     tls: true,
diff --git a/showcase/examples/tasking/tasking.js b/showcase/examples/tasking/tasking.js
index 79453ab3db..f21d037123 100644
--- a/showcase/examples/tasking/tasking.js
+++ b/showcase/examples/tasking/tasking.js
@@ -1,10 +1,10 @@
-import Systems from "osh-js/core/sweapi/system/Systems";
+import Systems from "osh-js/core/consysapi/system/Systems";
 import {EventType} from "osh-js/core/event/EventType";
-import ControlFilter from "osh-js/core/sweapi/control/ControlFilter";
-import SweApiFetch from "osh-js/core/datasource/sweapi/SweApi.datasource";
+import ConSysApi from "osh-js/core/datasource/consysapi/ConSysApi.datasource.js";
 import PointMarkerLayer from "osh-js/core/ui/layer/PointMarkerLayer";
 import LeafletView from "osh-js/core/ui/view/map/LeafletView";
 import PolylineLayer from "osh-js/core/ui/layer/PolylineLayer";
+import ControlStreamFilter from "../../../source/core/consysapi/controlstream/ControlStreamFilter";
 
 var prevTime = 0;
 
@@ -22,7 +22,7 @@ const mqttProps = {
     password: password
 };
 
-let gpsDataSource = new SweApiFetch("supersonic drone GPS", {
+let gpsDataSource = new ConSysApi("supersonic drone GPS", {
     resource: `/api/datastreams/${posDsId}/observations`,
     endpointUrl: 'api.georobotix.io/ogc/t18/api',
     protocol: 'ws',
@@ -101,9 +101,9 @@ async function startListening() {
     gpsDataSource.connect();
 
     const system = await systems.getSystemById(systemId);
-    const control = await system.getControlById(cmdStreamId);
+    const control = await system.getControlStreamById(cmdStreamId);
 
-    control.streamStatus(new ControlFilter({}), async (message) =>{
+    control.streamStatus(new ControlStreamFilter({}), async (message) =>{
         textCommandElt.innerHTML = "";
         const status = message;
         textStatusElt.innerHTML = JSON.stringify(status, null, 2);
diff --git a/showcase/index.html b/showcase/index.html
index 72adfd3df4..90d1bae864 100644
--- a/showcase/index.html
+++ b/showcase/index.html
@@ -201,6 +201,14 @@
         height: 64px;
         width: 64px;
     }
+
+    span.badge {
+      background-color: red;
+      color: white;
+      padding: 4px 8px;
+      text-align: center;
+      border-radius: 0px;
+    }
   </style>
 
 </head>
@@ -224,13 +232,13 @@
 <div id="card-template" hidden="true" aria-hidden="true">
   <div class="col-md-4 p-3 d-flex">
     <div class="card shadow-sm flex-fill">
+      <span id="badge" class="badge">helo</span>
       <img class="bd-placeholder-img card-img-top" src=""/>
       <div class="card-body">
         <p class="card-text" style="margin-bottom:50px">sample description</p>
         <div class="d-flex justify-content-between align-items-center" style="position:absolute; bottom:20px">
           <div class="btn-group">
             <button role="button" class="btn btn-sm btn-outline-secondary">View</button>
-            <!--<button type="button" class="btn btn-sm btn-outline-secondary">Edit</button>-->
           </div>
         </div>
       </div>
diff --git a/showcase/index.js b/showcase/index.js
index 2efdf27a73..0ef3665a47 100644
--- a/showcase/index.js
+++ b/showcase/index.js
@@ -7,163 +7,193 @@ var Normalizer = require('prismjs/plugins/normalize-whitespace/prism-normalize-w
 var samples = [{
         name: "FOI Locations (CesiumJS)",
         description: "Display the location of several features of interest on a CesiumJS globe.",
-        url: "cesium-fois"
+        url: "cesium-fois",
+        datasourceType: 'SOS',
     },
     {
         name: "Moving Location (CesiumJS)",
         description: "Display a moving marker on a CesiumJS globe, tracking the current location of a vehicle.",
-        url: "cesium-location"
+        url: "cesium-location",
+        datasourceType: 'SOS',
     },
     {
         name: "Moving Location with custom viewer properties(CesiumJS)",
         description: "Display a moving marker on a CesiumJS globe, tracking the current location of a vehicle and define some custom cesium viewer properties.",
-        url: "cesium-location-opts"
+        url: "cesium-location-opts",
+        datasourceType: 'SOS',
     },
     {
         name: "Moving Location  + path (CesiumJS)",
         description: "Display a moving marker and a polyline on a CesiumJS map, showing both the current location of a vehicle and the historical track.",
-        url: "cesium-location-path"
+        url: "cesium-location-path",
+        datasourceType: 'SOS',
     },
     {
         name: "Moving Location (Deck.gl)",
         description: "Display a moving marker on a Deck.gl canvas, tracking the current location of a vehicle.",
-        url: "deckgl-location"
+        url: "deckgl-location",
+        datasourceType: 'SOS',
     },
     {
         name: "Simple Chart (Chart.js)",
         description: "Display a chart with time series of weather measurements.",
-        url: "chart"
+        url: "chart",
+        datasourceType: 'SOS',
     },
     {
         name: "Moving Location (Leaflet)",
         description: "Display a moving marker on a Leaflet map, tracking the current location of a vehicle.",
-        url: "leaflet-location"
+        url: "leaflet-location",
+        datasourceType: 'SOS',
     },
     {
         name: "FOI Locations (Leaflet)",
         description: "Display the location of several features of interest on a Leaflet map.",
         url: "leaflet-location-fois",
-        screenshot: "images/screenshots/leaflet-fois.png"
+        screenshot: "images/screenshots/leaflet-fois.png",
+        datasourceType: 'SOS',
     },
     {
         name: "Moving Location + Heading (Leaflet)",
         description: "Display a moving marker on a Leaflet map, tracking the current location and heading of a vehicle.",
-        url: "leaflet-location-heading"
+        url: "leaflet-location-heading",
+        datasourceType: 'SOS',
     },
     {
         name: "Moving Location + Path (Leaflet)",
         description: "Display a moving marker and a polyline on a Leaflet map, showing both the current location of a vehicle and the historical track.",
-        url: "leaflet-location-path"
+        url: "leaflet-location-path",
+        datasourceType: 'SOS',
     },
     {
         name: "Moving Location (OpenLayers)",
         description: "Display a moving marker on an OpenLayers map, tracking the current location of a vehicle.",
-        url: "openlayers-location"
+        url: "openlayers-location",
+        datasourceType: 'SOS',
     },
     {
         name: "Moving Location + Heading (OpenLayers)",
         description: "Display a moving marker on an OpenLayers map, tracking the current location and heading of a vehicle.",
-        url: "openlayers-location-heading"
+        url: "openlayers-location-heading",
+        datasourceType: 'SOS',
     },
     {
         name: "Moving Location + Path + Heading (Mapbox)",
         description: "Display a moving marker and a polyline on a Mapbox map, showing both the current location of a vehicle and the historical track.",
-        url: "mapbox-location-path-heading"
+        url: "mapbox-location-path-heading",
+        datasourceType: 'SOS',
     },
     {
         name: "Moving Location + Heading + Video (Leaflet)",
         description: "Display a moving marker on an Leaflet map, tracking the current location of a vehicle and its corresponding" +
             "video. Create duplicated dataSources running at different time to check there is no collision between data. The " +
             "2 datasets are using a DataSynchronizer object. Each one should be independent.",
-        url: "video-map-multiple-datasource"
+        url: "video-map-multiple-datasource",
+        datasourceType: 'SOS',
     },
     {
         name: "Z-Index ordering",
         description: "Display a moving marker on an Leaflet, DeckGl,Cesium and Openlayers map using a z-Index between markers",
-        url: "zIndex-location-path"
+        url: "zIndex-location-path",
+        datasourceType: 'SOS',
     },
     {
         name: "Resizable H264 Video",
         description: "Display an H264 video in a simple resizable DIV using our FFMPEG-JS decoder.",
-        url: "video-h264"
+        url: "video-h264",
+        datasourceType: 'SOS',
     },
     {
         name: "H264 Video using WebCodecAPI",
         description: "Display an H264 video in a simple DIV using Experimental Hardware WebCodecAPI decoder.",
-        url: "video-h264-webcodec-api"
+        url: "video-h264-webcodec-api",
+        datasourceType: 'SOS',
     },
     {
         name: "H264 Image draping Video",
         description: "Display an H264 video in a simple DIV using our FFMPEG-JS decoder and drap the decoded frame onto the terrain.",
-        url: "video-h264-draping"
+        url: "video-h264-draping",
+        datasourceType: 'SOS',
     },
     {
         name: "Resizable MJPEG Video",
         description: "Display an MJPEG video in a simple resizable DIV.",
-        url: "video-mjpeg"
+        url: "video-mjpeg",
+        datasourceType: 'SOS',
     },
     {
         name: 'VueJs component: Multiple Video with control',
         description: 'Display multiple videos using forward/pause/play/backward control using the same DataSynchronizer',
         url: 'video-with-control-vuejs-synchronized',
-        code: 'vue/App_examples/video-with-control-vuejs-synchronized.vue'
+        code: 'vue/App_examples/video-with-control-vuejs-synchronized.vue',
+        datasourceType: 'SOS',
     },
     {
         name: 'AVL data using multiple ids',
         description: 'Display multiple markers corresponding to a unique id provided by the same DataSource',
-        url: 'avl'
+        url: 'avl',
+        datasourceType: 'SOS',
     },
     {
         name: 'AVL data using multiple ids and Time controller in VueJS',
         description: 'Display multiple markers corresponding to a unique id provided by the same DataSource with a Time controller in VueJS',
         url: 'avl-with-control-vuejs',
-        code: 'vue/App_examples/avl-with-control-vuejs.vue'
+        code: 'vue/App_examples/avl-with-control-vuejs.vue',
+        datasourceType: 'SOS',
     },
     {
         name: 'ISA Biological & MISB UAS sensor data using MQTT protocol',
         description: 'Display biological and GPS sensors from ISA Biological Sensor & MISB UAS using MQTT protocol',
-        url: 'mqtt'
+        url: 'mqtt',
+        datasourceType: 'Connected Systems',
     },
     {
         name: "Chart with Time controller (Chart.js)",
         description: "Display a chart with time series of weather measurements and time controller.",
         url: "chart-archive-realtime",
-        code: 'vue/App_examples/chart-archive-realtime.vue'
+        code: 'vue/App_examples/chart-archive-realtime.vue',
+        datasourceType: 'SOS',
     },
     {
         name: "Chart with Time controller (Chart.js) in batch mode",
         description: "Display a chart using full batch mode with time series of weather measurements and time controller.",
         url: "chart-archive-realtime-batch",
-        code: 'vue/App_examples/chart-archive-realtime-batch.vue'
+        code: 'vue/App_examples/chart-archive-realtime-batch.vue',
+        datasourceType: 'SOS',
     },
     {
         name: "Chart with Time controller and Synchronizer (Chart.js)",
         description: "Display a chart with time series of weather measurements and time controller.",
         url: "chart-archive-realtime-synchronized",
-        code: 'vue/App_examples/chart-archive-realtime-synchronized.vue'
+        code: 'vue/App_examples/chart-archive-realtime-synchronized.vue',
+        datasourceType: 'SOS',
     },
     {
         name: "Chart with Time controller and Synchronizer using 'trackRealtime' option(Chart.js)",
         description: "Display a chart with time series of weather measurements and time controller and tracking realtime.",
-        url: "chart-archive-realtime-synchronized-sweapi",
-        code: 'vue/App_examples/chart-archive-realtime-synchronized-sweapi.vue'
+        url: "chart-archive-realtime-synchronized-consysapi",
+        code: 'vue/App_examples/chart-archive-realtime-synchronized-consysapi.vue',
+        datasourceType: 'Connected Systems',
     },
     {
         name: "Audio WebCodec/FFmpeg.js decoding",
         description: "Listen audio stream using WebCodec/FFmpeg.js",
-        url: "audio"
+        url: "audio",
+        datasourceType: 'SOS',
     },
     {
         name: "Audio WebCodec/FFmpeg.js decoding with time controller",
         description: "Listen audio stream using WebCodec/FFmpeg.js with time controller",
         url: 'audio-with-control-vuejs',
-        code: 'vue/App_examples/audio-with-control-vuejs.vue'
+        code: 'vue/App_examples/audio-with-control-vuejs.vue',
+        datasourceType: 'SOS',
     },
     {
         name: "Audio & Video WebCodec/FFmpeg.js decoding with time controller",
         description: "Listen audio stream using WebCodec/FFmpeg.js with time controller and associated Video",
         url: 'audio-video-synchronized-with-control-vuejs',
-        code: 'vue/App_examples/audio-video-synchronized-with-control-vuejs.vue'
+        code: 'vue/App_examples/audio-video-synchronized-with-control-vuejs.vue',
+        datasourceType: 'SOS',
     }
 ];
 
@@ -172,6 +202,10 @@ var currentSample;
 samples.forEach(s => {
     var $newElt = $($("#card-template").html());
     $("p.card-text", $newElt).html(s.description);
+
+    $("span.badge", $newElt).text(s.datasourceType);
+    $("span.badge", $newElt).css("background-color", s.datasourceType === "SOS" ? "gray" : "red");
+
     $("img", $newElt)
         .on("error", e => e.target.src = "https://opensensorhub.files.wordpress.com/2017/08/opensensorhub-logo2.png")
         .attr("title", s.name)
diff --git a/showcase/webpack.config.js b/showcase/webpack.config.js
index d84c80b186..7eda5d1c08 100644
--- a/showcase/webpack.config.js
+++ b/showcase/webpack.config.js
@@ -102,7 +102,7 @@ let directories = [
     'chart-archive-realtime',
     'chart-archive-realtime-batch',
     'chart-archive-realtime-synchronized',
-    'chart-archive-realtime-synchronized-sweapi',
+    'chart-archive-realtime-synchronized-consysapi',
     'audio',
     'audio-with-control-vuejs',
     'audio-video-synchronized-with-control-vuejs',
diff --git a/source/core/OSH.js b/source/core/OSH.js
index 9a7b051afe..69f753a723 100644
--- a/source/core/OSH.js
+++ b/source/core/OSH.js
@@ -9,6 +9,7 @@ export { default as  DataSynchronizer } from './timesync/DataSynchronizer.js';
 export { default as  DataSource } from './datasource/DataSource.js';
 export { default as  SosGetResult } from './datasource/sos/SosGetResult.js';
 export { default as  SweApiFetch } from './datasource/sweapi/SweApiFetch.js';
+export { default as ConSysApi } from './datasource/consysapi/ConSysApi.datasource.js'
 export { default as  OrientationQuaternion  } from '../ext/datasource/OrientationQuaternion.js';
 export { default as  SosGetFois } from './datasource/sos/SosGetFois.js';
 export { default as  TimeSeriesDataSource } from './datasource/TimeSeriesDataSource.js';
@@ -50,31 +51,59 @@ export { default as  AudioFrequencyChartJsVisualizer } from './ui/view/audio/vis
 export { default as  AudioSpectrogramVisualizer } from './ui/view/audio/visualizer/spectrogram/AudioSpectrogramVisualizer.js';
 export { default as  AudioRollingSpectrogramCanvasVisualizer } from './ui/view/audio/visualizer/spectrogram/AudioRollingSpectrogramCanvasVisualizer.js';
 export { default as  View } from './ui/view/View.js';
-export { default as  Command } from './sweapi/command/Command.js';
-export { default as  Commands } from './sweapi/command/Commands.js';
-export { default as  CommandFilter } from './sweapi/command/CommandFilter.js';
-export { default as  Control } from './sweapi/control/Control.js';
-export { default as  Controls } from './sweapi/control/Controls.js';
-export { default as  ControlFilter } from './sweapi/control/ControlFilter.js';
-export { default as  DataStream } from './sweapi/datastream/DataStream.js';
-export { default as  DataStreams } from './sweapi/datastream/DataStreams.js';
-export { default as  DataStreamFilter } from './sweapi/datastream/DataStreamFilter.js';
-export { default as  Event } from './sweapi/event/Event.js';
-export { default as  Events } from './sweapi/event/Events.js';
-export { default as  EventFilter } from './sweapi/event/EventFilter.js';
-export { default as  FeatureOfInterest } from './sweapi/featureofinterest/FeatureOfInterest.js';
-export { default as  FeatureOfInterests } from './sweapi/featureofinterest/FeatureOfInterests.js';
-export { default as  FeatureOfInterestFilter } from './sweapi/featureofinterest/FeatureOfInterestFilter.js';
-export { default as  SystemHistoryFilter } from './sweapi/history/SystemHistoryFilter.js';
-export { default as  Observation } from './sweapi/observation/Observation.js';
-export { default as  Observations } from './sweapi/observation/Observations.js';
-export { default as  ObservationFilter } from './sweapi/observation/ObservationFilter.js';
-export { default as  System } from './sweapi/system/System.js';
-export { default as  Systems } from './sweapi/system/Systems.js';
-export { default as  SystemFilter } from './sweapi/system/SystemFilter.js';
-export { default as  Collection } from './sweapi/Collection.js';
-export { default as  ObservationsCollection } from './sweapi/ObservationsCollection.js';
-export { default as  SensorWebApi } from './sweapi/SensorWebApi.js';
+// SWE API
+// export { default as  Command } from './sweapi/command/Command.js';
+// export { default as  Commands } from './sweapi/command/Commands.js';
+// export { default as  CommandFilter } from './sweapi/command/CommandFilter.js';
+// export { default as  Control } from './sweapi/control/Control.js';
+// export { default as  Controls } from './sweapi/control/Controls.js';
+// export { default as  ControlFilter } from './sweapi/control/ControlFilter.js';
+// export { default as  DataStream } from './sweapi/datastream/DataStream.js';
+// export { default as  DataStreams } from './sweapi/datastream/DataStreams.js';
+// export { default as  DataStreamFilter } from './sweapi/datastream/DataStreamFilter.js';
+// export { default as  Event } from './sweapi/event/Event.js';
+// export { default as  Events } from './sweapi/event/Events.js';
+// export { default as  EventFilter } from './sweapi/event/EventFilter.js';
+// export { default as  FeatureOfInterest } from './sweapi/featureofinterest/FeatureOfInterest.js';
+// export { default as  FeatureOfInterests } from './sweapi/featureofinterest/FeatureOfInterests.js';
+// export { default as  FeatureOfInterestFilter } from './sweapi/featureofinterest/FeatureOfInterestFilter.js';
+// export { default as  SystemHistoryFilter } from './sweapi/history/SystemHistoryFilter.js';
+// export { default as  Observation } from './sweapi/observation/Observation.js';
+// export { default as  Observations } from './sweapi/observation/Observations.js';
+// export { default as  ObservationFilter } from './sweapi/observation/ObservationFilter.js';
+// export { default as  System } from './sweapi/system/System.js';
+// export { default as  Systems } from './sweapi/system/Systems.js';
+// export { default as  SystemFilter } from './sweapi/system/SystemFilter.js';
+// export { default as  Collection } from './sweapi/Collection.js';
+// export { default as  ObservationsCollection } from './sweapi/ObservationsCollection.js';
+// export { default as  SensorWebApi } from './sweapi/SensorWebApi.js';
+// Connected Systems API
+export { default as  Command } from './consysapi/command/Command.js';
+export { default as  Commands } from './consysapi/command/Commands.js';
+export { default as  CommandFilter } from './consysapi/command/CommandFilter.js';
+export { default as  ControlStream } from './consysapi/controlstream/ControlStream.js';
+export { default as  ControlStreams } from './consysapi/controlstream/ControlStreams.js';
+export { default as  ControlStreamFilter } from './consysapi/controlstream/ControlStreamFilter.js';
+export { default as  DataStream } from './consysapi/datastream/DataStream.js';
+export { default as  DataStreams } from './consysapi/datastream/DataStreams.js';
+export { default as  DataStreamFilter } from './consysapi/datastream/DataStreamFilter.js';
+export { default as  Event } from './consysapi/event/Event.js';
+export { default as  Events } from './consysapi/event/Events.js';
+export { default as  EventFilter } from './consysapi/event/EventFilter.js';
+export { default as  SamplingFeature } from './consysapi/samplingfeature/SamplingFeature.js';
+export { default as  SamplingFeatures } from './consysapi/samplingfeature/SamplingFeatures.js';
+export { default as  SamplingFeatureFilter } from './consysapi/samplingfeature/SamplingFeatureFilter.js';
+export { default as  SystemHistoryFilter } from './consysapi/history/SystemHistoryFilter.js';
+export { default as  Observation } from './consysapi/observation/Observation.js';
+export { default as  Observations } from './consysapi/observation/Observations.js';
+export { default as  ObservationFilter } from './consysapi/observation/ObservationFilter.js';
+export { default as  System } from './consysapi/system/System.js';
+export { default as  Systems } from './consysapi/system/Systems.js';
+export { default as  SystemFilter } from './consysapi/system/SystemFilter.js';
+export { default as  Collection } from './consysapi/Collection.js';
+export { default as  ObservationsCollection } from './consysapi/ObservationsCollection.js';
+export { default as  ConnectedSystemsApi } from './consysapi/ConnectedSystemsApi.js';
+
 export { default as  File } from '../ext/datasource/File.js';
 export { default as  FileConnector } from '../ext/connector/FileConnector.js';
 
diff --git a/source/core/connector/MqttConnector.js b/source/core/connector/MqttConnector.js
index 59a8494c48..f49ff5846c 100644
--- a/source/core/connector/MqttConnector.js
+++ b/source/core/connector/MqttConnector.js
@@ -15,10 +15,9 @@
  ******************************* END LICENSE BLOCK ***************************/
 
 import DataConnector from "./DataConnector";
-import {assertDefined, isDefined, randomUUID} from "../utils/Utils";
+import {isDefined, randomUUID} from "../utils/Utils";
 import {Status} from "./Status";
 import MqttProvider from "../mqtt/MqttProvider";
-import ObservationFilter from "../sweapi/observation/ObservationFilter";
 
 /**
  * Defines the MqttConnector to connect to a remote server by creating a Mqtt channel.
diff --git a/source/core/consysapi/Collection.js b/source/core/consysapi/Collection.js
new file mode 100644
index 0000000000..61dd9bd149
--- /dev/null
+++ b/source/core/consysapi/Collection.js
@@ -0,0 +1,135 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2021 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import SweCollectionDataParser from "../parsers/consysapi/collection/SweCollectionDataParser";
+
+class Collection {
+    /**
+     *
+     */
+    constructor(url, filter, pageSize, parser, responseFormat = 'json') {
+        this.url = url;
+        this.filter = filter;
+        this.pageSize = pageSize;
+        this.parser = parser;
+        this.pageOffset = 0;
+        this.init = false;
+        this.total = 0;
+        this.collectionDataParser = new SweCollectionDataParser(filter.props.format);
+        this.responseFormat = responseFormat;
+        this.currentPage = -1;
+    }
+
+    /**
+     * Check if has next page
+     * @return {boolean}
+     */
+    hasNext() {
+        return this.pageOffset !== -1;
+    }
+
+    async fetchData(offset) {
+        const queryString = `${this.filter.toQueryString()}&offset=${offset}&limit=${this.pageSize}`;
+        const fullUrl = this.url + '?' + queryString;
+
+        const jsonResponse = await fetch(fullUrl, {
+            method: 'GET',
+            credentials: 'include',
+            headers: {}
+        }).then((response) => {
+            if (!response.ok) {
+                const err = new Error(`Got ${response.status} response from ${fullUrl}`);
+                err.response = response;
+                throw err;
+            }
+            if (this.responseFormat === 'json') {
+                return response.json();
+            } else if (this.responseFormat === 'arraybuffer') {
+                return response.arrayBuffer();
+            }
+        });
+
+        return this.parseResponse(jsonResponse);
+    }
+
+    async parseResponse(jsonResponse) {
+        const items = this.collectionDataParser.parseData(jsonResponse);
+        const data = [];
+        if (Array.isArray(items)) {
+            for (let item of items) {
+                data.push(this.parser.parseData(item));
+            }
+        } else {
+            data.push(items);
+        }
+        return data;
+    }
+
+    /**
+     * Fetches next page.
+     * @param page - the number of page to fetch
+     * @return {Promise<Array>}
+     */
+    async nextPage() {
+        if (this.hasNext()) {
+            this.currentPage++;
+            this.pageOffset = this.currentPage * this.pageSize;
+            const data = await this.fetchData(this.pageOffset);
+            if (data.length === 0 || data.length < this.pageSize) {
+                this.pageOffset = -1;
+            }
+            return data;
+        } else {
+            throw Error('Has no more pages');
+        }
+    }
+
+    async page(page) {
+        this.currentPage = page;
+        this.pageOffset = this.currentPage * this.pageSize;
+        const data = await this.fetchData(this.pageOffset);
+        if (data.length === 0 || data.length < this.pageSize) {
+            this.pageOffset = -1;
+        }
+        return data;
+    }
+
+    /**
+     * Fetches previous page.
+     * @param page - the number of page to fetch
+     * @return {Promise<Array>}
+     */
+    async previousPage() {
+        if (this.hasPrevious()) {
+            this.currentPage--;
+            this.pageOffset = this.currentPage * this.pageSize;
+            return this.fetchData(this.pageOffset);
+        } else {
+            throw Error('Has no more pages');
+        }
+    }
+
+    /**
+     * Check if has previous page
+     * @return {boolean}
+     */
+    hasPrevious() {
+        return this.currentPage > 0;
+    }
+
+}
+
+export default Collection;
diff --git a/source/core/consysapi/ConnectedSystemsApi.js b/source/core/consysapi/ConnectedSystemsApi.js
new file mode 100644
index 0000000000..6ddcf0d891
--- /dev/null
+++ b/source/core/consysapi/ConnectedSystemsApi.js
@@ -0,0 +1,160 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import WebSocketConnector from "../connector/WebSocketConnector";
+import {assertDefined, isDefined} from "../utils/Utils";
+import MqttTopicConnector from "../connector/MqttTopicConnector";
+import MqttConnector from "../connector/MqttConnector";
+
+class ConnectedSystemsApi {
+
+    /**
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     * @param {Object} networkProperties.connectorOpts - Specific connector options
+     */
+    constructor(networkProperties) {
+        assertDefined(networkProperties.endpointUrl, 'endpointUrl');
+        this.networkProperties = networkProperties;
+
+        let endpoint = networkProperties.endpointUrl;
+        if (endpoint.endsWith('/')) {
+            endpoint = endpoint.substring(0, endpoint.length - 1);
+        }
+
+        const tls = (networkProperties.tls) ? 's' : '';
+        this.url = 'http' + tls + '://' + endpoint;
+
+        this._network = {}
+        if (isDefined(networkProperties.connector)) {
+            this._network.stream = {
+                connector: networkProperties.connector,
+            };
+        } else if(isDefined(networkProperties.streamProtocol)){
+            this._network.stream = {
+                connector: this.createStreamConnector(networkProperties)
+            }
+        } else {
+            // default Stream to WS
+            this._network.stream = {
+                connector: this.createStreamConnector({
+                    ...networkProperties,
+                    streamProtocol: 'ws'
+                })
+            }
+        }
+    }
+
+    baseUrl() {
+        return this.url;
+    }
+
+    stream() {
+        return this._network.stream.connector;
+    }
+
+    createStreamConnector(networkProperties) {
+        assertDefined(networkProperties.streamProtocol, 'streamProtocol');
+
+        let endpoint = networkProperties.endpointUrl;
+        if(networkProperties.streamProtocol === 'mqtt' && isDefined(networkProperties.mqttOpts)) {
+            endpoint = networkProperties.mqttOpts.endpointUrl;
+        }
+
+        if (endpoint.endsWith('/')) {
+            endpoint = endpoint.substring(0, endpoint.length - 1);
+        }
+
+        const tls = (networkProperties.tls) ? 's' : '';
+        const url = networkProperties.streamProtocol + tls + '://' + endpoint;
+
+        if(networkProperties.streamProtocol === 'mqtt') {
+            // return new MqttConnector(url, networkProperties);
+            return new MqttTopicConnector(networkProperties.mqttOpts.bcId, networkProperties);
+        } else if(networkProperties.streamProtocol === 'ws') {
+            return new WebSocketConnector(url);
+        }
+    }
+
+    connect() {
+        this._network.stream.connector.connect();
+    }
+
+    getHeaders() {
+        const headers = {
+        };
+
+        if('connectorOpts' in this.networkProperties){
+            if('username' in this.networkProperties.connectorOpts && 'password' in this.networkProperties.connectorOpts) {
+                headers['Authorization'] = 'Basic ' +
+                    btoa(this.networkProperties.connectorOpts.username + ":" + this.networkProperties.connectorOpts.password);
+            } else {
+                for(let key in this.networkProperties.connectorOpts) {
+                    headers[key] = this.networkProperties.connectorOpts[key];
+                }
+            }
+        }
+        return headers;
+    }
+
+    fetchAsJson(apiUrl, queryString) {
+        const fullUrl = this.baseUrl() +  apiUrl + '?' +queryString;
+
+        const headers = this.getHeaders();
+
+        return fetch(fullUrl, {
+                method: 'GET',
+                credentials: 'include',
+                headers: headers
+            }
+        ).then(function (response) {
+            if (!response.ok) {
+                const err = new Error(`Got ${response.status} response from ${this.baseUrl()}`);
+                err.response = response;
+                throw err;
+            }
+            return response.json();
+        });
+    }
+
+    postAsJson(apiUrl, jsonPayload) {
+        const fullUrl = this.baseUrl() +  apiUrl;
+
+        const headers = this.getHeaders();
+
+        headers['Accept'] = 'application/json';
+        headers['Content-Type'] = 'application/json';
+
+        fetch(fullUrl, {
+            method: 'POST',
+            headers: headers,
+            credentials: 'include',
+            body: jsonPayload
+        }).then(function (response) {
+            if (!response.ok) {
+                const err = new Error(`Got ${response.status} response from ${fullUrl}`);
+                err.response = response;
+                throw err;
+            }
+        });
+    }
+}
+export default ConnectedSystemsApi;
diff --git a/source/core/consysapi/Filter.js b/source/core/consysapi/Filter.js
new file mode 100644
index 0000000000..36c78abc74
--- /dev/null
+++ b/source/core/consysapi/Filter.js
@@ -0,0 +1,58 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2021 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import {isDefined} from "../utils/Utils";
+
+class ConnectedSystemsApiFilter {
+    constructor(props) {
+        this.props = props;
+    }
+
+    /**
+     *
+     * @param {string[]} [includes=[]] list of parameters to include - all if omitted
+     * @param  {string[]} [excludes=[]] list of parameters to exclude - none if omitted
+     * @return {string}
+     */
+    toQueryString(includes= [], excludes = []) {
+        let queryString = '';
+        let separator = '';
+        excludes.push('replaySpeed');
+        for (let queryParameter in this.props) {
+            if(excludes.includes(queryParameter)) {
+                continue;
+            }
+            if((includes.length === 0 || includes.includes(queryParameter)) && isDefined(this.props[queryParameter])) {
+                // if(Array.isArray(this.props[queryParameter])) {
+                //     queryString += separator + queryParameter + '=' + encodeURIComponent(this.props[queryParameter].join());
+                /*} else*/ if(queryParameter === 'f'
+                    || queryParameter === 'format'
+                    || queryParameter === 'responseFormat'
+                    || queryParameter === 'obsFormat'
+                ) {
+                    queryString += separator + queryParameter + '=' + this.props[queryParameter].replaceAll('+','%2B');
+                // } else {
+                //     queryString += separator + queryParameter + '=' + encodeURIComponent(this.props[queryParameter]);
+                } else {
+                    queryString += separator + queryParameter + '=' + this.props[queryParameter];
+                }
+                separator = '&';
+            }
+        }
+        return queryString;
+    }
+}
+export default ConnectedSystemsApiFilter;
diff --git a/source/core/consysapi/ObservationsCollection.js b/source/core/consysapi/ObservationsCollection.js
new file mode 100644
index 0000000000..f24f09d315
--- /dev/null
+++ b/source/core/consysapi/ObservationsCollection.js
@@ -0,0 +1,32 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2021 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import Collection from "./Collection";
+
+class ObservationsCollection extends Collection {
+    /**
+     *
+     */
+    constructor(url, filter, pageSize, parser) {
+        super(url,filter ,pageSize ,parser, 'arraybuffer');
+    }
+
+    async parseResponse(encodedResponse) {
+        return this.parser.parseDataBlock(encodedResponse,this.filter.props.format);
+    }
+}
+
+export default ObservationsCollection;
diff --git a/source/core/consysapi/command/Command.js b/source/core/consysapi/command/Command.js
new file mode 100644
index 0000000000..0d4ddf9e59
--- /dev/null
+++ b/source/core/consysapi/command/Command.js
@@ -0,0 +1,82 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+import Collection from "../Collection";
+import API from "../routes.conf";
+import CommandFilter from "./CommandFilter";
+import SweCollectionDataParser from "../../parsers/consysapi/collection/SweCollectionDataParser";
+import ConSysApiResultControlStreamParser from "../../parsers/consysapi/observations/ConSysApiResult.controlstream.parser";
+
+class Command extends ConnectedSystemsApi {
+    /**
+     * @param {Object} properties - the properties of the object
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(properties, networkProperties) {
+        super(networkProperties); // network properties
+        this.properties = properties;
+        this.jsonParser = new SweCollectionDataParser(networkProperties);
+        this.sweParser = new ConSysApiResultControlStreamParser(this);
+    }
+
+    /**
+     * Get all status messages associated to a specific command
+     * route: /systems/{sysid}/controlstreams/{csid}/commands/{cmdid}/status
+     * @param {CommandFilter} [commandFilter== new CommandFilter()] - default Command filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<JSON>>} - response as JSON
+     */
+    async searchStatus(commandFilter = new CommandFilter(), pageSize= 10) {
+        return new Collection(
+            this.baseUrl() + API.commands.status.replace('{sysid}',this.properties['system@id'])
+                               .replace('{csid}', this.properties['controlstream@id'])
+                               .replace('{cmdid}', this.properties.id),
+            commandFilter,
+            pageSize,
+            this.jsonParser
+        );
+    }
+
+    /**
+     * Stream all status messages associated to a specific command
+     * route: /systems/{sysid}/controlstreams/{csid}/commands/{cmdid}/status
+     * @param {CommandFilter} [commandFilter== new CommandFilter()] - default Command filter
+     * @param {Function} callback
+     */
+    streamStatus(commandFilter = new CommandFilter(), callback = function(){}) {
+        this.stream().onMessage = async (message) => {
+            const dataBlock = await this.sweParser.parseDataBlock(message,commandFilter.props.format);
+            callback(dataBlock);
+        };
+
+        this.stream().doRequest(
+            API.commands.status.replace('{sysid}',this.properties['system@id'])
+                .replace('{csid}', this.properties['controlstream@id'])
+                .replace('{cmdid}', this.properties.id),
+            commandFilter.toQueryString(),
+            'arraybuffer'
+        );
+    }
+}
+
+export default Command;
diff --git a/source/core/consysapi/command/CommandFilter.js b/source/core/consysapi/command/CommandFilter.js
new file mode 100644
index 0000000000..3ddb972f97
--- /dev/null
+++ b/source/core/consysapi/command/CommandFilter.js
@@ -0,0 +1,52 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2021 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApiFilter from "../Filter";
+
+class CommandFilter extends ConnectedSystemsApiFilter {
+    /**
+     *
+     * @param {Object} properties - object properties
+     * @param {string[]} [properties.q=undefined] - Comma separated keywords used for full-text search
+     * @param {string[]} [properties.actuableProperty=undefined] - Comma separated list of actuable property URIs to filter command streams
+     * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude)
+     * @param {string[]} [properties.foi=undefined] - Comma separated list of feature of interest IDs to get observations for
+     * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response.
+     * @param {string} [properties.issueTime=undefined] - ISO 8601 time range to filter commands on their issue time. When this parameter is omitted,
+     * no filtering on "issueTime" is applied.
+     * @param {string} [properties.executionTime=undefined] - ISO 8601 time range to filter commands on their execution time.
+     * When this parameter is omitted, no filtering on "executionTime" is applied
+     * @param {string} [properties.reportTime=undefined] - ISO 8601 time range to filter status messages on their report time. When this parameter is omitted,
+     * no filtering on "reportTime" is applied.
+     * @param {string[]} [properties.statusCode=undefined] - Comma separated list of status codes: PENDING, ACCEPTED, REJECTED, SCHEDULED, UPDATED, CANCELED, EXECUTING, FAILED, COMPLETED
+     */
+    constructor(properties) {
+        super({
+            q: undefined,
+            actuableProperty: undefined,
+            select: undefined,
+            foi: undefined,
+            format: 'application/json',
+            issueTime: undefined,
+            executionTime: undefined,
+            reportTime: undefined,
+            statusCode: undefined,
+            ...properties // merge defined properties
+        });
+        //TODO: assertions
+    }
+}
+export default CommandFilter;
diff --git a/source/core/consysapi/command/Commands.js b/source/core/consysapi/command/Commands.js
new file mode 100644
index 0000000000..2db48b3e38
--- /dev/null
+++ b/source/core/consysapi/command/Commands.js
@@ -0,0 +1,66 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConSysApiFetchCommandParser from "../../parsers/consysapi/collection/ConSysApiFetchCommand.parser";
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+import Collection from "../Collection";
+import API from "../routes.conf";
+import CommandFilter from "./CommandFilter";
+
+class Commands extends ConnectedSystemsApi {
+    /**
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(networkProperties) {
+        super(networkProperties); // network properties
+        this.conSysApiCommandParser = new ConSysApiFetchCommandParser(networkProperties, undefined);
+    }
+
+    /**
+     * List or search all commands available through this API.
+     * @param {CommandFilter} [commandFilter=new CommandFilter()] - default Command filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<Command>>} - A Collection of Command
+     */
+    async searchCommands(commandFilter = new CommandFilter(), pageSize= 10) {
+        return new Collection(
+            this.baseUrl() + API.commands.search,
+            commandFilter,
+            pageSize,
+            this.conSysApiCommandParser
+        );
+    }
+
+    /**
+     * Get a specific command resource by ID
+     * @param {string} commandId - ID of requested command
+     * @return {Promise<Command>} - The corresponding Command
+     */
+    async getCommandById(commandId) {
+        const apiUrl = API.commands.by_id.replace('{cmdid}',commandId);
+        const jsonData = await this.fetchAsJson(apiUrl, undefined);
+        return this.conSysApiCommandParser.parseData(jsonData);
+    }
+
+}
+
+export default Commands;
diff --git a/source/core/consysapi/controlstream/ControlStream.js b/source/core/consysapi/controlstream/ControlStream.js
new file mode 100644
index 0000000000..82c1c16bf6
--- /dev/null
+++ b/source/core/consysapi/controlstream/ControlStream.js
@@ -0,0 +1,179 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+import CommandFilter from "../command/CommandFilter";
+import Collection from "../Collection";
+import API from "../routes.conf";
+import ControlStreamFilter from "./ControlStreamFilter";
+import ObservationsCollection from "../ObservationsCollection";
+import ConSysApiFetchCommandParser from "../../parsers/consysapi/collection/ConSysApiFetchCommand.parser";
+import ConSysApiResultCollectionControlStreamParser
+    from "../../parsers/consysapi/observations/ConSysApiResult.collection.controlstream.parser";
+import ConSysApiResultControlStreamParser from "../../parsers/consysapi/observations/ConSysApiResult.controlstream.parser";
+import ConSysApiControlStreamStatusParser from "../../parsers/consysapi/collection/ConSysApiControlStreamStatus.parser";
+
+class ControlStream extends ConnectedSystemsApi {
+    /**
+     * @param {Object} properties - the properties of the object
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(properties, networkProperties) {
+        super(networkProperties); // network properties
+        this.properties = properties;
+        this.commandParser = new ConSysApiFetchCommandParser(networkProperties, this.properties['system@id']);
+        this.conSysApiResultCollectionControlStreamParser = new ConSysApiResultCollectionControlStreamParser(this);
+        this.conSysApiResultControlStreamParser = new ConSysApiResultControlStreamParser(this);
+        this.conSysApiControlStreamStatusParser = new ConSysApiControlStreamStatusParser();
+    }
+
+    /**
+     * Get the list of commands received by a particular control interface
+     * route: /systems/{sysid}/controlstreams/{csid}/commands
+     * @param {CommandFilter} [commandFilter=new CommandFilter()] - default Command filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<JSON>>} - result as JSON
+     */
+    async searchCommands(commandFilter = new CommandFilter(), pageSize= 10) {
+        return new ObservationsCollection(
+            this.baseUrl() + API.controlstreams.commands.replace('{sysid}',
+                this.properties['system@id']).replace('{csid}',this.properties.id),
+            commandFilter,
+            pageSize,
+            this.conSysApiResultCollectionControlStreamParser
+        );
+    }
+
+    /**
+     * Stream all commands received by a particular control interface
+     * route: /systems/{sysid}/controlstreams/{csid}/commands
+     * @param {ControlStreamFilter} [controlStreamFilter= new ControlStreamFilter()] - default ControlStreamStream filter
+     * @param {Function} callback - A callback to get observations
+     */
+    streamCommands(controlStreamFilter = new ControlStreamFilter(), callback = function(){}) {
+        this.stream().onMessage = async (message) => {
+            const dataBlock = await this.conSysApiResultControlStreamParser.parseDataBlock(message,controlStreamFilter.props.format);
+            callback(dataBlock);
+        };
+
+        this.stream().doRequest(
+            API.controlstreams.commands.replace('{sysid}',this.properties['system@id']).replace('{csid}',this.properties.id),
+            controlFilter.toQueryString(),
+            'arraybuffer'
+        );
+    }
+
+    /**
+     * Get a specific command resource by ID.
+     * route: /systems/{sysid}/controlstreams/{csid}/commands/{cmdid}
+     * @param {String} commandId - the ID of the Command resource
+     * @param {CommandFilter} [commandFilter=new CommandFilter()] - default Command filter
+     * @returns {Promise<Command>} - The corresponding Command
+     */
+    async getCommandById(commandId,commandFilter = new CommandFilter()) {
+        const apiUrl = API.controlstreams.command_by_id
+            .replace('{sysid}',this.properties['system@id'])
+            .replace('{csid}', this.properties.id)
+            .replace('{cmdid}', commandId);
+        const queryString = commandFilter.toQueryString(['select', 'obsFormat']); //TODO: check useless obsFormat
+        const jsonData = await this.fetchAsJson(apiUrl, queryString);
+        return this.commandParser.parseData(jsonData);
+    }
+
+    /**
+     *  Send a new command to this control interface
+     *  route: /systems/{sysid}/controlstreams/{csid}/commands
+     * @param {JSON} jsonPayload - the JSON payload
+     * @param {CommandFilter} [commandFilter=new CommandFilter()] - default Command filter specifying the 'sysid' and 'csid'
+     */
+    postCommand(jsonPayload, commandFilter = new CommandFilter()) {
+        const apiUrl =  API.controlstreams.commands
+                .replace('{sysid}',this.properties['system@id'])
+                .replace('{csid}', this.properties.id);
+        this.postAsJson(apiUrl, jsonPayload);
+    }
+
+    /**
+     * Send a new command to this control interface using streaming protocol such like WS or MQTT
+     * route: /systems/{sysid}/controlstreams/{csid}/commands
+     * @param {JSON} jsonPayload - the JSON payload
+     * @param {CommandFilter} [commandFilter=new CommandFilter()] - default Command filter specifying the 'sysid' and 'csid'
+     */
+    publishCommand(payload, commandFilter = new CommandFilter()) {
+        this.stream().publishRequest(
+            API.controlstreams.commands
+                .replace('{sysid}',this.properties['system@id'])
+                .replace('{csid}', this.properties.id),
+            payload
+        );
+    }
+
+    /**
+     * Get all status messages sent by this control interface
+     * route: /systems/{sysid}/controlstreams/{csid}/status
+     * @param {ControlStreamFilter} [controlStreamFilter=new ControlStreamFilter()] - default ControlStream filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<JSON>>} - A Collection of JSON
+     */
+    async searchStatus(controlStreamFilter = new ControlStreamFilter(), pageSize= 10) {
+        return new Collection(
+            this.baseUrl() + API.controlstreams.status.replace('{sysid}',this.properties['system@id']).replace('{csid}',
+                this.properties.id),
+                controlStreamFilter,
+            pageSize,
+            this.conSysApiControlStreamStatusParser
+        );
+    }
+
+    /**
+     * Stream all status messages sent by this control interface
+     * route: /systems/{sysid}/controlstreams/{csid}/status
+     * @param {ControlStreamFilter} [controlStreamFilter= new ControlStreamFilter()] - default ControlStream filter
+     * @param {Function} callback - A callback to get observations
+     */
+    streamStatus(controlStreamFilter = new ControlStreamFilter(), callback = function(){}) {
+        this.stream().onMessage = async (message) => {
+            const dataBlock = await this.conSysApiControlStreamStatusParser.parseData(message, 'arraybuffer');
+            callback(dataBlock);
+        };
+
+        this.stream().doRequest(
+            API.controlstreams.status.replace('{sysid}',this.properties['system@id']).replace('{csid}',this.properties.id),
+            controlStreamFilter.toQueryString(),
+            'arraybuffer'
+        );
+    }
+
+    /**
+     * Get the detailed schema of command messages in a command stream
+     * route: /systems/{sysid}/controlstreams/{csid}/schema
+     * @param {ControlStreamFilter} [controlStreamFilter= new ControlStreamFilter()] - default ControlStream filter, using 'commandFormat' to select response format
+     * @returns {Promise<JSON>} - The schema as JSON
+     */
+    async getSchema(controlStreamFilter = new ControlStreamFilter()) {
+        const apiUrl = API.controlstreams.schema.replace('{sysid}',this.properties['system@id']).replace('{csid}',this.properties.id);
+        const queryString = controlStreamFilter.toQueryString(['select', 'commandFormat']);
+        return this.fetchAsJson(apiUrl, queryString);
+    }
+}
+
+export default ControlStream;
diff --git a/source/core/consysapi/controlstream/ControlStreamFilter.js b/source/core/consysapi/controlstream/ControlStreamFilter.js
new file mode 100644
index 0000000000..d2e5f3c141
--- /dev/null
+++ b/source/core/consysapi/controlstream/ControlStreamFilter.js
@@ -0,0 +1,45 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApiFilter from "../Filter";
+
+class ControlStreamFilter extends ConnectedSystemsApiFilter {
+    /**
+     *
+     * @param {Object} properties - object properties
+     * @param {string[]} [properties.q=undefined] - Comma separated keywords used for full-text search
+     * @param {string[]} [properties.actuableProperty=undefined] - Comma separated list of actuable property URIs to filter command streams
+     * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude)
+     * @param {string[]} [properties.foi=undefined] - Comma separated list of feature of interest IDs to get observations for
+     * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response.
+     * @param {string} [properties.issueTime=undefined] - ISO 8601 time range to filter commands on their issue time. When this parameter is omitted,
+     * no filtering on "issueTime" is applied.
+     */
+    constructor(properties) {
+        super({
+            q: undefined,
+            actuableProperty: undefined,
+            observedProperty: undefined,
+            issueTime: undefined,
+            select: undefined,
+            foi: undefined,
+            format: 'application/json',
+            ...properties // merge defined properties
+        });
+        //TODO: assertions
+    }
+}
+export default ControlStreamFilter;
diff --git a/source/core/consysapi/controlstream/ControlStreams.js b/source/core/consysapi/controlstream/ControlStreams.js
new file mode 100644
index 0000000000..8ff8a7249d
--- /dev/null
+++ b/source/core/consysapi/controlstream/ControlStreams.js
@@ -0,0 +1,68 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConSysApiFetchControlStreamParser from "../../parsers/consysapi/collection/ConSysApiFetchControlStream.parser";
+import Collection from "../Collection";
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+import API from "../routes.conf";
+import ControlStreamFilter from "./ControlStreamFilter";
+
+class ControlStreams extends ConnectedSystemsApi {
+    /**
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(networkProperties) {
+        super(networkProperties); // network properties
+        this.conSysApiControlStreamParser = new ConSysApiFetchControlStreamParser(networkProperties);
+    }
+
+    /**
+     * List or search all controlstreams available through this API.
+     * @param {ControlStreamFilter} [controlStreamFilter=new ControlStreamFilter()] - default ControlStream filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<ControlStream>>} - A Collection of ControlStream
+     */
+    async searchControlStreams(controlStreamFilter = new ControlStreamFilter(), pageSize= 10) {
+        return new Collection(
+            this.baseUrl() + API.controlstreams.search,
+            controlStreamFilter,
+            pageSize,
+            this.conSysApiControlStreamParser
+        );
+    }
+
+    /**
+     * Get a specific controlstream resource by ID
+     * @param {string} controlstreamId - ID of requested controlstream
+     * @param {ControlStreamFilter} [controlStreamFilter=new ControlStreamFilter()] - default controlstream filter 
+     * @return {Promise<ControlStream>} - The corresponding ControlStream
+     */
+    async getControlStreamById(controlstreamId, controlStreamFilter = new ControlStreamFilter()) {
+        const apiUrl = API.controlstreams.by_id.replace('{csid}',controlstreamId);
+        const queryString = controlStreamFilter.toQueryString(['select', 'format']);
+        const jsonData = await this.fetchAsJson(apiUrl, queryString);
+        return this.conSysApiControlStreamParser.parseData(jsonData);
+    }
+
+}
+
+export default ControlStreams;
diff --git a/source/core/consysapi/datastream/DataStream.js b/source/core/consysapi/datastream/DataStream.js
new file mode 100644
index 0000000000..36ff3af4d4
--- /dev/null
+++ b/source/core/consysapi/datastream/DataStream.js
@@ -0,0 +1,93 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+import ObservationFilter from "../observation/ObservationFilter";
+import API from "../routes.conf";
+import DataStreamFilter from "./DataStreamFilter";
+import ObservationsCollection from "../ObservationsCollection";
+import ConSysApiResultParser from "../../parsers/consysapi/observations/ConSysApiResult.datastream.parser";
+import ConSysApiResultCollectionDatastreamParser
+    from "../../parsers/consysapi/observations/ConSysApiResult.collection.datastream.parser";
+
+class DataStream extends ConnectedSystemsApi {
+    /**
+     * @param {Object} properties - the properties of the object
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(properties, networkProperties) {
+        super(networkProperties); // network properties
+        this.properties = properties;
+        this.conSysApiResultParser = new ConSysApiResultParser(this);
+        this.conSysApiResultCollectionDatastreamParser = new ConSysApiResultCollectionDatastreamParser(this);
+    }
+
+    /**
+     * Retrieve historical observations from a datastream
+     * route: /datastreams/{id}/observations
+     * @param {ObservationFilter} [observationFilter=new ObservationFilter()] - default ObservationFilter
+     * @param {Function} callback - A callback to get observations
+     */
+    streamObservations(observationFilter = new ObservationFilter(), callback = function(){}) {
+        this.stream().onMessage = async (message) => {
+            const dataBlock = await this.conSysApiResultParser.parseDataBlock(message,observationFilter.props.format);
+            callback(dataBlock);
+        }
+
+        return this.stream().doRequest(
+            API.datastreams.observations.replace('{id}',this.properties.id),
+            observationFilter.toQueryString([], ['phenomenonTime']),
+            'arraybuffer'
+        );
+    }
+
+    /**
+     * Retrieve historical observations from a datastream
+     * route: /datastreams/{id}/observations
+     * @param {ObservationFilter} [observationFilter=new ObservationFilter()] - default ObservationFilter
+     * @param {Number} [pageSize=10] - default page size
+     * @param {DataSourceParser} [parser=new ConSysApiResultParser()] - default observations parser
+     * @return {Collection<JSON>} - result observations as JSON
+     */
+    async searchObservations(observationFilter = new ObservationFilter(),  pageSize= 10, parser = this.conSysApiResultParser) {
+        return new ObservationsCollection(
+            this.baseUrl() + API.datastreams.observations.replace('{id}',this.properties.id),
+            observationFilter,
+            pageSize,
+            this.conSysApiResultCollectionDatastreamParser
+        );
+    }
+
+    /**
+     * Get the schema of a datastream
+     * route: /datastreams/{id}/schema
+     * @param {DataStreamFilter} [dataStreamFilter=new DataStreamFilter()] - default datastream filter
+     * @return {Promise<JSON>} - the JSON schema
+     */
+    async getSchema(dataStreamFilter = new DataStreamFilter()) {
+        const apiUrl = API.datastreams.schema.replace('{id}',this.properties.id);
+        const queryString = dataStreamFilter.toQueryString(['select', 'obsFormat']);
+        return this.fetchAsJson(apiUrl, queryString);
+    }
+}
+
+export default DataStream;
diff --git a/source/core/consysapi/datastream/DataStreamFilter.js b/source/core/consysapi/datastream/DataStreamFilter.js
new file mode 100644
index 0000000000..29bc7ec4c8
--- /dev/null
+++ b/source/core/consysapi/datastream/DataStreamFilter.js
@@ -0,0 +1,55 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApiFilter from "../Filter";
+
+class DataStreamFilter extends ConnectedSystemsApiFilter {
+    /**
+     *
+     * @param {Object} properties - object properties
+     * @param {string[]} [properties.q=undefined] - Comma separated keywords used for full-text search
+     * @param {number[]} [properties.bbox=undefined] - BBOX to filter resources on their location
+     * @param {string} [properties.location=undefined] - WKT geometry and operator to filter resources on their location or geometry
+     * @param {string[]} [properties.observedProperty=undefined] - Comma separated list of observed property URIs to get observations for
+     * @param {string[]} [properties.foi=undefined] - Comma separated list of feature of interest IDs to get observations for
+     * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude)
+     * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response.
+     * @param {string} [properties.validTime=undefined] - validTime - ISO 8601 time range to filter resources on their validity time.
+     * When this parameter is omitted, the implicit value is "now", except for "history" collections where the absence of this parameter means no filtering is applied.
+     * @param {string} [properties.resultTime=undefined] - validTime - ISO 8601 time range to filter observations on their result time.
+     * When this parameter is omitted, no filtering on "resultTime" is applied.
+     * @param {string} [properties.phenomenonTime=undefined] - validTime - ISO 8601 time range to filter observations on the phenomenon time.
+     * When this parameter is omitted, no filtering on "phenomenonTime" is applied.
+     */
+    constructor(properties) {
+        super({
+            q: undefined,
+            bbox: undefined,
+            location: undefined,
+            observedProperty: undefined,
+            foi: undefined,
+            select: undefined,
+            format: 'application/json',
+            obsFormat: 'application/om+json',
+            validTime: undefined,
+            phenomenonTime: undefined,
+            resultTime: undefined,
+            ...properties // merge defined properties
+        });
+        //TODO: assertions
+    }
+}
+export default DataStreamFilter;
diff --git a/source/core/consysapi/datastream/DataStreams.js b/source/core/consysapi/datastream/DataStreams.js
new file mode 100644
index 0000000000..14108f25a6
--- /dev/null
+++ b/source/core/consysapi/datastream/DataStreams.js
@@ -0,0 +1,65 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+import Collection from "../Collection";
+import DataStreamFilter from "./DataStreamFilter";
+import API from "../routes.conf";
+import ConSysApiDataStreamParser from "../../parsers/consysapi/collection/ConSysApiDataStream.parser";
+
+class DataStreams extends ConnectedSystemsApi {
+    /**
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(networkProperties) {
+        super(networkProperties);
+        this.conSysApiDataStreamParser = new ConSysApiDataStreamParser(networkProperties);
+    }
+
+    /**
+     * List or search all datastreams available through this API.
+     * @param {DataStreamFilter} [dataStreamFilter=new DataStreamFilter()] - default DataStream filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<DataStream>>} - A Collection of DataStream
+     */
+    async searchDataStreams(dataStreamFilter = new DataStreamFilter(), pageSize= 10) {
+        return new Collection(
+            this.baseUrl() + API.datastreams.search,
+            dataStreamFilter,
+            pageSize,
+            this.conSysApiDataStreamParser
+        );
+    }
+
+    /**
+     * Get a specific datastream resource by ID
+     * @param {DataStreamFilter} [dataStreamFilter=new DataStreamFilter()] - default datastream filter
+     * @return {Promise<DataStream>} - The corresponding DataStream
+     */
+    async getDataStreamById(datastreamId,dataStreamFilter = new DataStreamFilter()) {
+        const apiUrl = API.datastreams.by_id.replace('{id}',datastreamId);
+        const queryString = dataStreamFilter.toQueryString(['select','format']);
+        const jsonData = await this.fetchAsJson(apiUrl, queryString);
+        return this.conSysApiDataStreamParser.parseData(jsonData);
+    }
+}
+export default DataStreams;
diff --git a/source/core/consysapi/event/Event.js b/source/core/consysapi/event/Event.js
new file mode 100644
index 0000000000..4534184e09
--- /dev/null
+++ b/source/core/consysapi/event/Event.js
@@ -0,0 +1,36 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+
+class Event extends ConnectedSystemsApi {
+    /**
+     * @param {Object} properties - the properties of the object
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(properties, networkProperties) {
+        super(networkProperties); // network properties
+        this.properties = properties;
+    }
+}
+
+export default Event;
diff --git a/source/core/consysapi/event/EventFilter.js b/source/core/consysapi/event/EventFilter.js
new file mode 100644
index 0000000000..dfcc123fee
--- /dev/null
+++ b/source/core/consysapi/event/EventFilter.js
@@ -0,0 +1,42 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApiFilter from "../Filter";
+
+class EventFilter extends ConnectedSystemsApiFilter {
+    /**
+     *
+     * @param {Object} properties - object properties
+     * @param {string[]} [properties.q=undefined] - Comma separated keywords used for full-text search
+     * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude)
+     * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response.
+     * @param {string} [properties.eventTime=undefined] - ISO 8601 time range to filter events on their timestamp. When this parameter
+     * is omitted, no filtering on "eventTime" is applied.
+     * @param {string} [properties.eventType=undefined] - Comma separated list of event type URIs to filter system events.
+     */
+    constructor(properties) {
+        super({
+            q: undefined,
+            eventTime: undefined,
+            eventType: undefined,
+            select: undefined,
+            format: 'application/json',
+            ...properties // merge defined properties
+        });
+        //TODO: assertions
+    }
+}
+export default EventFilter;
diff --git a/source/core/consysapi/event/Events.js b/source/core/consysapi/event/Events.js
new file mode 100644
index 0000000000..7c6da6dea3
--- /dev/null
+++ b/source/core/consysapi/event/Events.js
@@ -0,0 +1,34 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+
+class Events extends ConnectedSystemsApi {
+    /**
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(networkProperties) {
+        super(networkProperties);
+    }
+}
+
+export default Events;
diff --git a/source/core/consysapi/history/SystemHistoryFilter.js b/source/core/consysapi/history/SystemHistoryFilter.js
new file mode 100644
index 0000000000..847891217f
--- /dev/null
+++ b/source/core/consysapi/history/SystemHistoryFilter.js
@@ -0,0 +1,38 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApiFilter from "../Filter";
+
+class SystemHistoryFilter extends ConnectedSystemsApiFilter {
+    /**
+     *
+     * @param {Object} properties - object properties
+     * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude)
+     * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response.
+     * @param {string} [properties.validTime=undefined] - ISO 8601 time range to filter resources on their validity time.
+     * When this parameter is omitted, the implicit value is "now", except for "history" collections where the absence of this parameter means no filtering is applied.
+     */
+    constructor(properties) {
+        super({
+            select: undefined,
+            validTime: undefined,
+            format: 'application/json',
+            ...properties // merge defined properties
+        });
+        //TODO: assertions
+    }
+}
+export default SystemHistoryFilter;
diff --git a/source/core/consysapi/observation/Observation.js b/source/core/consysapi/observation/Observation.js
new file mode 100644
index 0000000000..460a660b06
--- /dev/null
+++ b/source/core/consysapi/observation/Observation.js
@@ -0,0 +1,37 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+
+class Observation extends ConnectedSystemsApi {
+    /**
+     * @param {Object} properties - the properties of the object
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(properties, networkProperties) {
+        super(networkProperties); // network properties
+        this.properties = properties;
+    }
+
+}
+
+export default Observation;
diff --git a/source/core/consysapi/observation/ObservationFilter.js b/source/core/consysapi/observation/ObservationFilter.js
new file mode 100644
index 0000000000..106b7522e2
--- /dev/null
+++ b/source/core/consysapi/observation/ObservationFilter.js
@@ -0,0 +1,45 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+import ConnectedSystemsApiFilter from "../Filter";
+
+class ObservationFilter extends ConnectedSystemsApiFilter {
+    /**
+     *
+     * @param {Object} properties - object properties
+     * @param {any} [properties.phenomenonTime='now'] - time range <00:00:00T00:00:00Z/00:00:00T00:00:00Z> | 'now' | 'latest'
+     * @param {any} [properties.resultTime='now'] - time range <00:00:00T00:00:00Z/00:00:00T00:00:00Z> | 'latest'
+     * @param {string[]} [properties.foi=undefined] - Comma separated list of feature of interest IDs to get observations for
+     * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude)
+     * @param {number[]} [properties.bbox=undefined] - BBOX to filter resources on their location
+     * @param {string} [properties.location=undefined] - WKT geometry and operator to filter resources on their location or geometry
+     * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response.
+     * @param {string} [properties.replaySpeed=undefined] - Mime type designating the format to use to encode the response.
+     */
+    constructor(properties) {
+        super({
+            phenomenonTime: undefined,
+            resultTime: undefined,
+            foi: undefined,
+            select: undefined,
+            bbox: undefined,
+            location: undefined,
+            format: 'application/om+json',
+            replaySpeed: undefined,
+            ...properties // merge defined properties
+        });
+    }
+}
+export default ObservationFilter;
diff --git a/source/core/consysapi/observation/Observations.js b/source/core/consysapi/observation/Observations.js
new file mode 100644
index 0000000000..04ffe7a002
--- /dev/null
+++ b/source/core/consysapi/observation/Observations.js
@@ -0,0 +1,59 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+import Collection from "../Collection";
+import ConSysApiFetchObservationParser from "../../parsers/consysapi/collection/ConSysApiFetchObservation.parser";
+import ObservationFilter from "./ObservationFilter";
+import API from "../routes.conf";
+
+class Observations extends ConnectedSystemsApi {
+    /**
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(networkProperties) {
+        super(networkProperties);
+        this.conSysApiFetchObservationParser = new ConSysApiFetchObservationParser(networkProperties);
+    }
+
+    /**
+     * List or search all observations available through this API.
+     * @param {ObservationFilter} [observationFilter=new ObservationFilter()] - default observation filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<Observation>>} - A Collection of Observation
+     */
+    async searchObservations(observationFilter = new ObservationFilter(), pageSize= 10) {
+        return new Collection(this.baseUrl() + API.observations.search, observationFilter, pageSize,this.conSysApiFetchObservationParser);
+    }
+
+    /**
+     * Get a specific observation resource by ID
+     * @param {string} observationId ID of requested observation
+     * @return {Promise<Observation>} - corresponding observation
+     */
+    async getObservationById(observationId) {
+        const apiUrl = API.observations.by_id.replace('{id}', observationId);
+        const jsonData = await this.fetchAsJson(apiUrl, undefined);
+        return this.conSysApiFetchObservationParser.parseData(jsonData);
+    }
+}
+export default Observations;
diff --git a/source/core/consysapi/routes.conf.js b/source/core/consysapi/routes.conf.js
new file mode 100644
index 0000000000..46268219b0
--- /dev/null
+++ b/source/core/consysapi/routes.conf.js
@@ -0,0 +1,61 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+const API = {
+    datastreams: {
+        search: '/datastreams',
+        by_id: '/datastreams/{id}',
+        observations: '/datastreams/{id}/observations',
+        schema: '/datastreams/{id}/schema'
+    },
+    systems: {
+        search: '/systems',
+        by_id: '/systems/{sysid}',
+        details: '/systems/{sysid}/details',
+        samplingFeatures: '/systems/{sysid}/samplingFeatures',
+        members: '/systems/{sysid}/members',
+        subsystems: '/systems/{sysid}/subsystems',
+        datastreams: '/systems/{sysid}/datastreams',
+        history_ver: '/systems/{sysid}/history/{ver}',
+        controlstream_by_id: '/systems/{sysid}/controlstreams/{csid}',
+        controlstreams: '/systems/{sysid}/controlstreams',
+        events: '/systems/{sysid}/events',
+        history: '/systems/{sysid}/history',
+    },
+    controlstreams: {
+        search: '/controlstreams',
+        by_id: '/controlstreams/{csid}',
+        commands: '/systems/{sysid}/controlstreams/{csid}/commands',
+        command_by_id: '/systems/{sysid}/controlstreams/{csid}/commands/{cmdid}',
+        status: '/systems/{sysid}/controlstreams/{csid}/status',
+        schema: '/systems/{sysid}/controlstreams/{csid}/schema'
+    },
+    commands: {
+        search: '/commands',
+        by_id: '/commands/{cmdid}',
+        status: '/systems/{sysid}/controlstreams/{csid}/commands/{cmdid}/status'
+    },
+    observations: {
+        search: '/observations',
+        by_id: '/observations/{id}',
+    },
+    samplingFeatures: {
+        search: '/samplingFeatures',
+        by_id: '/samplingFeatures/{id}',
+    },
+};
+
+export default API;
diff --git a/source/core/consysapi/samplingfeature/SamplingFeature.js b/source/core/consysapi/samplingfeature/SamplingFeature.js
new file mode 100644
index 0000000000..4add902243
--- /dev/null
+++ b/source/core/consysapi/samplingfeature/SamplingFeature.js
@@ -0,0 +1,36 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+
+class SamplingFeature extends ConnectedSystemsApi {
+    /**
+     * @param {Object} properties - the properties of the object
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(properties, networkProperties) {
+        super(networkProperties); // network properties
+        this.properties = properties;
+    }
+}
+
+export default SamplingFeature;
diff --git a/source/core/consysapi/samplingfeature/SamplingFeatureFilter.js b/source/core/consysapi/samplingfeature/SamplingFeatureFilter.js
new file mode 100644
index 0000000000..ab2f2148ac
--- /dev/null
+++ b/source/core/consysapi/samplingfeature/SamplingFeatureFilter.js
@@ -0,0 +1,48 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApiFilter from "../Filter";
+
+class SamplingFeatureFilter extends ConnectedSystemsApiFilter {
+    /**
+     *
+     * @param {Object} properties - object properties
+     * @param {string[]} [properties.q=undefined] - Comma separated keywords used for full-text search
+     * @param {number[]} [properties.bbox=undefined] - BBOX to filter resources on their location
+     * @param {string} [properties.location=undefined] - WKT geometry and operator to filter resources on their location or geometry
+     * @param {string} [properties.validTime=undefined] - validTime - ISO 8601 time range to filter resources on their validity time.
+     * When this parameter is omitted, the implicit value is "now", except for "history" collections where the absence of this parameter means no filtering is applied.
+     * @param {string[]} [properties.parent=undefined] - Comma separated list of parent resource IDs to restrict the search to or "*" to include nested resources at any level
+     * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude)
+     * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response.
+     * @param {String[]} [properties.foi=undefined] Comma separated list of feature of interest IDs to get observations for.
+     */
+    constructor(properties) {
+        super({
+            q: undefined,
+            bbox: undefined,
+            location: undefined,
+            validTime: undefined,
+            parent: undefined,
+            select: undefined,
+            foi: undefined,
+            format: 'application/json',
+            ...properties // merge defined properties
+        });
+        //TODO: assertions
+    }
+}
+export default SamplingFeatureFilter;
diff --git a/source/core/consysapi/samplingfeature/SamplingFeatures.js b/source/core/consysapi/samplingfeature/SamplingFeatures.js
new file mode 100644
index 0000000000..3df34eae2e
--- /dev/null
+++ b/source/core/consysapi/samplingfeature/SamplingFeatures.js
@@ -0,0 +1,65 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import SamplingFeatureFilter from "./SamplingFeatureFilter";
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+import Collection from "../Collection";
+import API from "../routes.conf";
+import ConSysApiFetchSamplingFeatureParser from "../../parsers/consysapi/collection/ConSysApiFetchSamplingFeature.parser";
+
+class SamplingFeatures extends ConnectedSystemsApi {
+    /**
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(networkProperties) {
+        super(networkProperties);
+        this.conSysApiFetchSamplingFeatureParser = new ConSysApiFetchSamplingFeatureParser(networkProperties);
+    }
+
+    /**
+     * List or search all sampled and sampling features available through this API. By default, only top level features
+     * and collections are listed (i.e. nested members of feature collections are ommitted) unless the "parent" query parameter is set.
+     * route: /samplingFeatures
+     * @param {SamplingFeatureFilter} [samplingFeatureFilter=new SamplingFeatureFilter()] - default SamplingFeature filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<SamplingFeatures>>} - A Collection of SamplingFeatures
+     */
+    async searchSamplingFeatures(samplingFeatureFilter = new SamplingFeatureFilter(), pageSize= 10) {
+        return new Collection(this.baseUrl() + API.samplingFeatures.search, samplingFeatureFilter, pageSize,this.conSysApiFetchSamplingFeatureParser);
+    }
+
+    /**
+     * Get a specific feature resource by ID. Note that this will return the description of the feature valid at the current time.
+     * To get the description valid for a past (or future) time, use the "history" sub-collection.
+     * route: /samplingFeatures/{id}
+     * @param {String} fId - The ID of the SamplingFeature resource
+     * @param {SamplingFeatureFilter} [samplingFeatureFilter=new SamplingFeatureFilter()] - default SamplingFeature filter
+     * @return {Promise<SamplingFeature>} - The corresponding SamplingFeatures as JSON
+     */
+    async getSamplingFeatureById(fId,samplingFeatureFilter = new SamplingFeatureFilter()) {
+        const apiUrl = API.samplingFeatures.by_id.replace('{id}',fId);
+        const queryString = samplingFeatureFilter.toQueryString(['select', 'format']);
+        const jsonData = await this.fetchAsJson(apiUrl, queryString);
+        return this.conSysApiFetchSamplingFeatureParser.parseData(jsonData);
+    }
+}
+export default SamplingFeatures;
diff --git a/source/core/consysapi/system/System.js b/source/core/consysapi/system/System.js
new file mode 100644
index 0000000000..e50180ad5b
--- /dev/null
+++ b/source/core/consysapi/system/System.js
@@ -0,0 +1,192 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import SystemFilter from "./SystemFilter";
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+import Collection from "../Collection";
+import DataStreamFilter from "../datastream/DataStreamFilter";
+import SamplingFeatureFilter from "../samplingfeature/SamplingFeatureFilter";
+import API from "../routes.conf";
+import ControlStreamFilter from "../controlstream/ControlStreamFilter";
+import EventFilter from "../event/EventFilter";
+import SystemHistoryFilter from "../history/SystemHistoryFilter";
+import ConSysApiFetchSystemParser from "../../parsers/consysapi/collection/ConSysApiFetchSystem.parser";
+import ConSysApiDataStreamParser from "../../parsers/consysapi/collection/ConSysApiDataStream.parser";
+import ConSysApiFetchSamplingFeatureParser from "../../parsers/consysapi/collection/ConSysApiFetchSamplingFeature.parser";
+import ConSysApiFetchEventParser from "../../parsers/consysapi/collection/ConSysApiFetchEvent.parser";
+import ConSysApiFetchControlStreamParser from "../../parsers/consysapi/collection/ConSysApiFetchControlStream.parser";
+
+class System extends ConnectedSystemsApi {
+    /**
+     * @param {Object} properties - the properties of the object
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(properties, networkProperties) {
+        super(networkProperties); // network properties
+        this.properties = properties;
+        this.conSysApiFetchSystemParser = new ConSysApiFetchSystemParser(networkProperties);
+        this.conSysApiDataStreamParser = new ConSysApiDataStreamParser(networkProperties);
+        this.conSysApiFetchSamplingFeatureParser = new ConSysApiFetchSamplingFeatureParser(networkProperties);
+        this.conSysApiFetchEventParser = new ConSysApiFetchEventParser(networkProperties);
+        this.conSysApiFetchControlStreamParser = new ConSysApiFetchControlStreamParser(networkProperties);
+    }
+
+    /**
+     * Get the latest specsheet of a system
+     * route: /systems/{sysid}/details
+     * @param {SystemFilter} [systemFilter=new SystemFilter()] - the system filter
+     * @return {Promise<JSON>} - SensorlML Description
+     */
+    async getDetails(systemFilter = new SystemFilter()) {
+        const apiUrl = API.systems.details.replace('{sysid}',this.properties.id);
+        const queryString = systemFilter.toQueryString(['select', 'format']);
+        return this.fetchAsJson(apiUrl, queryString);
+    }
+
+    /**
+     * Search for subsystems
+     * route: /systems/{sysid}/subsystems
+     * @param {SystemFilter} [systemFilter= new SystemFilter()] - the system filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<System>>} - A collection of System
+     */
+    async searchSubSystems(systemFilter = new SystemFilter(), pageSize = 10) {
+        return new Collection(
+            this.baseUrl() + API.systems.subsystems.replace('{sysid}',this.properties.id),
+            systemFilter,
+            pageSize,
+            this.conSysApiFetchSystemParser
+        );
+    }
+
+    /**
+     * List or search output datastreams of the selected system. Individual datastreams can be retrieved by ID directly on the root "datastreams" collection.
+     * route: /systems/{sysid}/datastreams
+     * @param {DataStreamFilter} [dataStreamFilter=new DataStreamFilter()] - default DataStream filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<DataStream>>}  - A collection of DataStream
+     */
+    async searchDataStreams(dataStreamFilter = new DataStreamFilter(), pageSize= 10) {
+        return new Collection(
+            this.baseUrl() + API.systems.datastreams.replace('{sysid}',this.properties.id),
+            dataStreamFilter,
+            pageSize,
+            this.conSysApiDataStreamParser
+        );
+    }
+
+    /**
+     * List or search sampling features of a system. Individual features can be retrieved by ID directly on the root "samplingFeatures" collection
+     * route: /systems/{sysid}/samplingFeatures
+     * @param {SamplingFeatureFilter} [samplingFeatureFilter=new SamplingFeatureFilter()] - FOI filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<SamplingFeature>>} - A collection of SamplingFeature
+     */
+    async searchSamplingFeatures(samplingFeatureFilter = new SamplingFeatureFilter(), pageSize= 10) {
+        return new Collection(
+            this.baseUrl() + API.systems.samplingFeatures.replace('{sysid}',this.properties.id),
+            samplingFeatureFilter,
+            pageSize,
+            this.conSysApiFetchSamplingFeatureParser
+        );
+    }
+
+    /**
+     * Get a list of control interfaces of a system
+     * route: /systems/{sysid}/controlstreams
+     * @param {ControlStreamFilter} [controlStreamFilter=new ControlStreamFilter()] - the controlstream filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<ControlStream>>} - A collection of ControlStream
+     */
+    async searchControlStreams(controlStreamFilter = new ControlStreamFilter(), pageSize= 10) {
+        return new Collection(
+            this.baseUrl() + API.systems.controlstreams.replace('{sysid}',this.properties.id),
+            controlStreamFilter,
+            pageSize,
+            this.conSysApiFetchControlStreamParser
+        );
+    }
+
+    /**
+     * Get a specific control interface description by ID
+     * route: /systems/{sysid}/controlstreams/{dsid}
+     * @param {String} controlstreamId - The ID of the control stream
+     * @param {ControlStreamFilter} [controlStreamFilter= new ControlStreamFilter()] - the controlstream filter
+     * @return {ControlStream} - The corresponding ControlStream
+     */
+    async getControlStreamById(controlstreamId,controlStreamFilter = new ControlStreamFilter()) {
+        const apiUrl = API.systems.controlstream_by_id.replace('{sysid}',this.properties.id).replace('{csid}', controlstreamId);
+        const queryString = controlStreamFilter.toQueryString(['select', 'format']);
+        const jsonData = await this.fetchAsJson(apiUrl, queryString);
+        return this.conSysApiFetchControlStreamParser.parseData(jsonData);
+    }
+
+    /**
+     * List or search events related to a system (e.g. maintenance events, contact change, etc.)
+     * route: /systems/{sysid}/events
+     * @param {EventFilter} [eventFilter= new EventFilter()] - the event filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<Event>>} - A collection of Event
+     */
+    async searchEvents(eventFilter = new EventFilter(), pageSize= 10) {
+        return new Collection(
+            this.baseUrl() + API.systems.events.replace('{sysid}',this.properties.id),
+            eventFilter,
+            pageSize,
+            this.conSysApiFetchEventParser
+        );
+    }
+
+    /**
+     * List or search for historical descriptions of a specific system (ordered by time of validity)
+     * route: /systems/{sysid}/history
+     * @param {SystemHistoryFilter} [systemHistoryFilter= new SystemHistoryFilter()] - the history filer
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<System>>} - A collection of System
+     */
+    async searchHistory(systemHistoryFilter = new SystemHistoryFilter(), pageSize= 10) {
+        return new Collection(
+            this.baseUrl() + API.systems.history.replace('{sysid}',this.properties.id),
+            systemHistoryFilter,
+            pageSize,
+            this.conSysApiFetchSystemParser
+        );
+    }
+
+    /**
+     * List or search members of a system group. Individual members can be retrieved by ID directly on the root "systems" collection
+     * route: /systems/{sysid}/members
+     * @param {SystemFilter} [systemFilter=new SystemFilter()] - the system filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<System>>} - A collection of System
+     */
+    async searchMembers(systemFilter = new SystemFilter(), pageSize= 10) {
+        return new Collection(
+            this.baseUrl() + API.systems.members.replace('{sysid}',this.properties.id),
+            systemFilter,
+            pageSize,
+            this.conSysApiFetchSystemParser
+        );
+    }
+}
+
+export default System;
diff --git a/source/core/consysapi/system/SystemFilter.js b/source/core/consysapi/system/SystemFilter.js
new file mode 100644
index 0000000000..7fbb25d724
--- /dev/null
+++ b/source/core/consysapi/system/SystemFilter.js
@@ -0,0 +1,48 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApiFilter from "../Filter";
+
+class SystemFilter extends ConnectedSystemsApiFilter {
+    /**
+     *
+     * @param {Object} properties - object properties
+     * @param {string[]} [properties.q=undefined] - Comma separated keywords used for full-text search
+     * @param {number[]} [properties.bbox=undefined] - BBOX to filter resources on their location
+     * @param {string} [properties.location=undefined] - WKT geometry and operator to filter resources on their location or geometry
+     * @param {string[]} [properties.parent=undefined] - Comma separated list of parent resource IDs to restrict the search to or "*" to include nested resources at any level
+     * @param {string[]} [properties.foi=undefined] - Comma separated list of feature of interest IDs to get observations for
+     * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude)
+     * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response.
+     * @param {string} [properties.validTime=undefined] - validTime - ISO 8601 time range to filter resources on their validity time.
+     When this parameter is omitted, the implicit value is "now", except for "history" collections where the absence of this parameter means no filtering is applied.
+     */
+    constructor(properties) {
+        super({
+            q: undefined,
+            bbox: undefined,
+            location: undefined,
+            parent: undefined,
+            foi: undefined,
+            select: undefined,
+            format: 'application/json',
+            validTime: undefined,
+            ...properties // merge defined properties
+        });
+        //TODO: assertions
+    }
+}
+export default SystemFilter;
diff --git a/source/core/consysapi/system/Systems.js b/source/core/consysapi/system/Systems.js
new file mode 100644
index 0000000000..07a5b08935
--- /dev/null
+++ b/source/core/consysapi/system/Systems.js
@@ -0,0 +1,65 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConnectedSystemsApi from "../ConnectedSystemsApi";
+import Collection from "../Collection";
+import SystemFilter from "./SystemFilter";
+import API from "../routes.conf";
+import ConSysApiFetchSystemParser from "../../parsers/consysapi/collection/ConSysApiFetchSystem.parser";
+
+class Systems extends ConnectedSystemsApi {
+    /**
+     * @param {Object} [networkProperties={}]
+     * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL
+     * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data
+     * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt'
+     * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt'
+     * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     */
+    constructor(networkProperties) {
+        super(networkProperties);
+        this.conSysApiFetchSystemParser = new ConSysApiFetchSystemParser(networkProperties);
+    }
+
+    /**
+     * List or search all observing systems available through this API. By default, only top level systems are listed
+     * (i.e. subsystems are ommitted) unless the "parent" query parameter is set
+     * route: /systems
+     * @param {SystemFilter} [systemFilter= new SystemFilter()] - the system filter
+     * @param {Number} [pageSize=10] - default page size
+     * @return {Promise<Collection<System>>} - A collection of System
+     */
+    async searchSystems(systemFilter = new SystemFilter(), pageSize = 10) {
+        return new Collection(this.baseUrl() + API.systems.search, systemFilter, pageSize, this.conSysApiFetchSystemParser);
+    }
+
+    /**
+     * Get a specific system resource by ID. Note that this will return the description of the system valid at the
+     * current time. To get the description valid for a past (or future) time, use the "history" sub-collection.
+     * route: /systems/{sysid}
+     * @param {String} systemId - the ID of the System resource
+     * @param {SystemFilter} [systemFilter=new SystemFilter()] - the system filter
+     * @return {System} - The corresponding System
+     */
+    async getSystemById(systemId,systemFilter = new SystemFilter()) {
+        const apiUrl = API.systems.by_id.replace('{sysid}',systemId);
+        const queryString = systemFilter.toQueryString(['select','format']);
+        const jsonData = await this.fetchAsJson(apiUrl, queryString);
+        return this.conSysApiFetchSystemParser.parseData(jsonData);
+    }
+}
+export default Systems;
diff --git a/source/core/datasource/consysapi/ConSysApi.datasource.js b/source/core/datasource/consysapi/ConSysApi.datasource.js
new file mode 100755
index 0000000000..afceb03cd0
--- /dev/null
+++ b/source/core/datasource/consysapi/ConSysApi.datasource.js
@@ -0,0 +1,91 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+
+import TimeSeriesDatasource from "../TimeSeries.datasource";
+import {Mode} from "../Mode";
+import ConSysApiDatasourceUpdater from "./ConSysApi.datasource.updater";
+
+class ConSysApi extends TimeSeriesDatasource {
+    /**
+     * @param {String} name - the datasource name
+     * @param {Object} properties - the datasource properties
+     * @param {String} properties.protocol - defines the protocol of the datasource. @see {@link DataConnector}, 'http', 'ws', 'mqtt', 'file', 'topic'
+     * @param {String} properties.endpointUrl the endpoint url, this property is ignored in case of using 'mqtt' protocol, the properties.mqttOpts.endpointUrl will be used instead
+     * @param {String} properties.resource the resource, /procedures, /fois, /observations, /tasks, /datastreams/4778/obs
+     * @param {Boolean} properties.tls - defines if use secure TLS connection
+     * @param {Boolean} properties.connectorOpts - connector specific Opts
+     * @param {Object} [properties.mqttOpts={}] - the Mqtt options if protocol is 'mqtt'
+     * @param {String} properties.mqttOpts.prefix - the Mqtt prefix value
+     * @param {String} properties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl
+     * @param {Number} [properties.responseFormat=application/om+json] the response format (e.g application/om+json)
+     * @param {String[]} [properties.parentId=undefined] the parent id
+     * @param {String[]} [properties.keywords=undefined] the keyword ids
+     * @param {String[]} [properties.includedProps=undefined] the included properties
+     * @param {String[]} [properties.excludedProps=undefined] the excluded properties
+     * @param {string} [properties.roi=undefined] - WKT geometry and operator to filter resources on their location or geometry
+     * @param {String[]} [properties.featureOfInterest=undefined] Comma separated list of feature of interest IDs to get observations for.
+     * @param {String[]} [properties.observedProperty=undefined] Comma separated list of observed property URIs to get observations for.
+     * @param {String[]} [properties.prefetchBatchSize=250] Number of elements to prefetch at a time
+     * @param {String[]} [properties.prefetchBatchDuration=5000] Duration before prefetching the next batch. N.b the next batch will be prefetched at 80% of this duration
+     */
+    constructor(name, properties) {
+        super(name, {
+            reconnectTimeout: 1000 * 5, // default if not defined into properties
+            reconnectRetry: 10,
+            startTime: 'now',
+            endTime: '2055-01-01T00:00:00Z',
+            tls: false,
+            responseFormat: 'application/swe+json',
+            protocol: 'http',
+            type: 'ConSysApiStream',
+            mode: Mode.REAL_TIME,
+            prefetchBatchSize: 250,
+            prefetchBatchDuration: 5000,
+            connectorOpts: {},
+            ...properties,
+        });
+    }
+
+    async createTimeUpdater() {
+        if(!this.timeUpdater) {
+            this.timeUpdater = new ConSysApiDatasourceUpdater(this.properties);
+            let first = true;
+            this.timeUpdater.onTimeChanged = (min, max) => {
+                if (first) {
+                    this.setMinTime(min);
+                    first = false;
+                }
+                this.setMaxTime(max);
+                if (this.getDataSynchronizer()) {
+                    this.getDataSynchronizer().minMaxChanged(first);
+                }
+            }
+            this.timeUpdater.onError = (err) => reject();
+
+            return this.timeUpdater.start();
+        } // TO CHECK: if timeUpdater has been created multiple times. Start() should not return anything
+    }
+
+    destroyTimeUpdater() {
+        if(this.timeUpdater) {
+            this.timeUpdater.destroy();
+        }
+        this.timeUpdater = undefined;
+    }
+}
+
+export default ConSysApi;
diff --git a/source/core/datasource/consysapi/ConSysApi.datasource.updater.js b/source/core/datasource/consysapi/ConSysApi.datasource.updater.js
new file mode 100644
index 0000000000..83da7968da
--- /dev/null
+++ b/source/core/datasource/consysapi/ConSysApi.datasource.updater.js
@@ -0,0 +1,55 @@
+class ConSysApiDatasourceUpdater {
+    constructor(properties) {
+        this.properties = properties;
+        this.datastreamInterval = undefined;
+    }
+
+    async fetchTime(url) {
+        return fetch(url)
+            .then(response => {
+                if (!response.ok) {
+                    // create error object and reject if not a 2xx response code
+                    let err = new Error("HTTP status code: " + response.status)
+                    err.response = response
+                    err.status = response.status
+                    this.onError(err);
+                    throw err
+                }
+                return response
+            })
+            .then(response => response.json())
+            .then(response => {
+                // update datastream times
+                if(response && response.items.length > 0 && response.items[0].phenomenonTime
+                    && response.items[0].phenomenonTime.length > 1) {
+                    const minTime = response.items[0].phenomenonTime[0];
+                    const maxTime = response.items[0].phenomenonTime[1];
+                    this.onTimeChanged(minTime, maxTime);
+                }
+            });
+    }
+    async start() {
+        const regex = new RegExp('\\/(.*\\/)(.*)\\/observations'); // /datastreams/abc13/observations
+        if(regex.test(this.properties.resource)) {
+            // is observation streaming
+            const match = regex.exec(this.properties.resource);
+            const datastreamId = match[2];
+            const url = `http${this.properties.tls? 's' : ''}://${this.properties.endpointUrl}/datastreams?id=${datastreamId}&select=id,phenomenonTime&f=application%2Fjson`;
+            return this.fetchTime(url).then(() => {
+                this.datastreamInterval = setInterval(() => {
+                    this.fetchTime(url);
+                }, 5000);
+            })
+        } else {
+            throw Error(`Cannot parse dataStream id from resource ${this.properties.resource}`);
+        }
+    }
+    onTimeChanged(min, max){}
+
+    onError(err){}
+    destroy() {
+        clearInterval(this.datastreamInterval);
+    }
+}
+
+export default ConSysApiDatasourceUpdater;
diff --git a/source/core/datasource/consysapi/context/ConSysApi.context.js b/source/core/datasource/consysapi/context/ConSysApi.context.js
new file mode 100644
index 0000000000..d31d599c0a
--- /dev/null
+++ b/source/core/datasource/consysapi/context/ConSysApi.context.js
@@ -0,0 +1,88 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import {isDefined} from "../../../utils/Utils";
+import ObservationFilter from "../../../consysapi/observation/ObservationFilter";
+import DataSourceContext from "../../common/context/DataSource.context";
+import ControlStreamFilter from "../../../consysapi/controlstream/ControlStreamFilter";
+
+class ConSysApiContext extends DataSourceContext {
+    createControlStreamFilter(properties) {
+        const props = {};
+        if(isDefined(properties.keywords)) {
+            props.q = properties.keywords;
+        }
+        if(isDefined(properties.actuableProperty)) {
+            props.actuableProperty = properties.actuableProperty;
+        }
+        if(isDefined(properties.statusCode)) {
+            props.statusCode = properties.statusCode;
+        }
+        if(isDefined(properties.responseFormat)) {
+            props.format = properties.responseFormat;
+        }
+        if(isDefined(properties.issueTime)) {
+            props.issueTime = properties.issueTime;
+        }
+        if(isDefined(properties.executionTime)) {
+            props.executionTime = properties.executionTime;
+        }
+        if(isDefined(properties.reportTime)) {
+            props.reportTime = properties.reportTime;
+        }
+
+        return new ControlStreamFilter(props);
+    }
+
+    createObservationFilter(properties) {
+        const props = {};
+        if(isDefined(properties.roi)) {
+            props.location = props.roi;
+        }
+        if(isDefined(properties.responseFormat)) {
+            props.format = properties.responseFormat;
+        }
+        if(isDefined(properties.replaySpeed)) {
+            props.replaySpeed = properties.replaySpeed;
+        }
+        if(isDefined(properties.startTime)) {
+            props.phenomenonTime = properties.startTime + '/' + properties.endTime;
+        }
+        if(isDefined(properties.resultTime)) {
+            props.resultTime = properties.resultTime;
+        }
+        if(isDefined(properties.resultTime)) {
+            props.resultTime = properties.resultTime;
+        }
+        if(isDefined(properties.featureOfInterest)) {
+            props.featureOfInterest = properties.featureOfInterest;
+        }
+        if(isDefined(properties.excludedProps)) {
+            props.select = properties.excludedProps.map(e => '!' + e);
+        }
+        if(isDefined(properties.includedProps)) {
+            if(!isDefined(props.select)) {
+                props.select = [];
+            }
+            props.select.concat(properties.includedProps);
+        }
+
+        return new ObservationFilter(props);
+    }
+}
+
+
+export default ConSysApiContext;
diff --git a/source/core/datasource/consysapi/context/ConSysApi.realtime.context.js b/source/core/datasource/consysapi/context/ConSysApi.realtime.context.js
new file mode 100644
index 0000000000..21593337f6
--- /dev/null
+++ b/source/core/datasource/consysapi/context/ConSysApi.realtime.context.js
@@ -0,0 +1,91 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConSysApiContext from "./ConSysApi.context";
+import DataStream from "../../../consysapi/datastream/DataStream";
+import {isDefined} from "../../../utils/Utils";
+import ControlStream from "../../../consysapi/controlstream/ControlStream";
+
+class ConSysApiRealTimeContext extends ConSysApiContext {
+    init(properties) {
+        this.properties = properties;
+
+        const networkProperties = {
+            ...properties,
+            streamProtocol: properties.protocol
+        };
+        let filter;
+        let regex = new RegExp('\\/systems\\/(.*)\\/controlstreams\\/(.*)\\/status');
+
+        this.streamObject = undefined;
+
+        // check control status
+        if(regex.test(properties.resource)) {
+            filter = this.createControlStreamFilter(properties);
+            // is observation streaming
+            const match = regex.exec(properties.resource);
+
+            this.streamObject = new ControlStream({
+                id: match[2],
+                'system@id': match[1]
+            }, networkProperties);
+            this.streamFunction = function() {
+                this.streamObject.streamStatus(filter, (messages) => this.onStreamMessage(messages, filter.props.format));
+            }
+        } else {
+            // check for datastream observations
+            regex = new RegExp('\\/(.*\\/)(.*)\\/observations'); // /datastreams/abc13/observations
+            if(regex.test(properties.resource)) {
+                filter = this.createObservationFilter(properties);
+                // is observation streaming
+                const match = regex.exec(properties.resource);
+                this.streamObject = new DataStream({
+                    id: match[2]
+                }, networkProperties);
+                this.streamFunction = function() {
+                    this.streamObject.streamObservations(filter, (messages) => this.onStreamMessage(messages, filter.props.format));
+                }
+            }
+        }
+        this.streamObject.stream().onChangeStatus = this.onChangeStatus.bind(this);
+    }
+    onStreamMessage(messages, format) {
+         // in case of om+json ,we have to add the timestamp which is not included for each record but at the root level
+        let results = messages;
+        let version = this.properties.version;
+        for(let message of messages) {
+            message.version = version;
+        }
+        this.handleData(results, format);
+    }
+
+    connect() {
+        this.streamFunction();
+    }
+
+    async disconnect() {
+        if(isDefined(this.streamObject)) {
+            this.streamObject.stream().disconnect();
+        }
+    }
+
+    isConnected() {
+        return this.streamObject.stream().status;
+    }
+}
+
+
+export default ConSysApiRealTimeContext;
diff --git a/source/core/datasource/consysapi/context/ConSysApi.replay.context.js b/source/core/datasource/consysapi/context/ConSysApi.replay.context.js
new file mode 100644
index 0000000000..ad3c5e5122
--- /dev/null
+++ b/source/core/datasource/consysapi/context/ConSysApi.replay.context.js
@@ -0,0 +1,138 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import ConSysApiContext from "./ConSysApi.context";
+import DataStream from "../../../consysapi/datastream/DataStream";
+import {isDefined} from "../../../utils/Utils";
+import ControlStream from "../../../consysapi/controlstream/ControlStream";
+
+class ConSysApiReplayContext extends ConSysApiContext {
+    init(properties) {
+        this.collection = undefined;
+        this.relativeStartTimestamp = undefined;
+        this.properties = properties;
+        this.replayFunction = undefined;
+
+        const networkProperties = {
+            ...properties
+        };
+        let filter;
+        let regex = new RegExp('\\/systems\\/(.*)\\/controlstreams\\/(.*)\\/status');
+
+        // check controlstream status
+        if(regex.test(properties.resource)) {
+            filter = this.createControlStreamFilter(properties);
+            // is observation streaming
+            const match = regex.exec(properties.resource);
+
+            let control = new ControlStream({
+                id: match[2],
+                'system@id': match[1]
+            }, networkProperties);
+            this.replayFunction = function(props, startTimestamp, endTimestamp) {
+                const controlFilter = this.createControlStreamFilter({
+                    ...properties,
+                    ...props,
+                    startTime: new Date(startTimestamp).toISOString(),
+                    endTime: new Date(endTimestamp).toISOString()
+                });
+                return control.searchStatus(controlFilter, 1);
+            }
+        } else {
+            // check for datastream observations
+            regex = new RegExp('\\/(.*\\/)(.*)\\/observations'); // /datastreams/abc13/observations
+            if(regex.test(properties.resource)) {
+                // is observation streaming
+                const match = regex.exec(properties.resource);
+                let dataStream = new DataStream({
+                    id: match[2]
+                }, networkProperties);
+                this.dataStream = dataStream;
+                this.replayFunction = function(props, startTime, endTime) {
+                    const obsFilter = this.createObservationFilter({
+                        ...properties,
+                        ...props,
+                        replaySpeed: undefined,
+                        startTime: startTime,
+                        endTime: endTime
+                    });
+                    return dataStream.searchObservations(obsFilter, properties.prefetchBatchSize);
+                }
+            }
+        }
+    }
+
+    async disconnect() {
+        this.collection = undefined;
+        this.relativeStartTimestamp = undefined;
+        this.replayFunction = undefined;
+    }
+
+    async nextBatch(properties, masterTimestamp, status = {cancel:false}) {
+        let version = this.properties.version;
+        return new Promise(async (resolve, reject) => {
+            try {
+                let data;
+                let results = [];
+
+                const moveTimeCursor = async () => {
+                    let relativeStartTime;
+                    if(isDefined(this.relativeStartTimestamp)) {
+                        relativeStartTime = new Date(this.relativeStartTimestamp + 1).toISOString();
+                    } else {
+                        //TOCHECK: ISO or timestamp
+                        relativeStartTime = new Date(this.properties.startTime).toISOString();
+                    }
+
+                    console.warn(`fetching ${relativeStartTime} -> ` +
+                        `${this.properties.endTime} for datasource ${this.properties.dataSourceId}`);
+                    // if disconnected, replay function is reset
+                    if(this.replayFunction) {
+                        this.collection = await this.replayFunction(properties, relativeStartTime, this.properties.endTime);
+                    }
+                }
+
+                const fetchNext = async () => {
+                    data = await this.collection.nextPage();
+                    if (status.cancel) {
+                        reject('Status has been cancelled');
+                    }
+                    if (data.length > 0) {
+                        results = data;
+                        for(let d of results) {
+                            d.version = version;
+                        }
+                        if(status.cancel) {
+                            reject('Status has been cancelled');
+                        } else {
+                            // start startTime cursor
+                            this.relativeStartTimestamp = results[results.length-1].timestamp;
+                            resolve(data);
+                        }
+                    }
+                }
+
+                await moveTimeCursor();
+                await fetchNext();
+            } catch (ex) {
+                reject(ex);
+            }
+        });
+    }
+}
+
+
+export default ConSysApiReplayContext;
diff --git a/source/core/datasource/consysapi/handler/ConSysApi.handler.js b/source/core/datasource/consysapi/handler/ConSysApi.handler.js
new file mode 100644
index 0000000000..1b79d12ba4
--- /dev/null
+++ b/source/core/datasource/consysapi/handler/ConSysApi.handler.js
@@ -0,0 +1,32 @@
+/***************************** BEGIN LICENSE BLOCK ***************************
+
+ The contents of this file are subject to the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one
+ at http://mozilla.org/MPL/2.0/.
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the License.
+
+ Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved.
+
+ Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com>
+
+ ******************************* END LICENSE BLOCK ***************************/
+
+import TimeSeriesHandler from "../../common/handler/TimeSeries.handler";
+import ConSysApiRealtimeContext from "../context/ConSysApi.realtime.context";
+import ConSysApiReplayContext from "../context/ConSysApi.replay.context";
+import {Mode} from "../../Mode";
+
+class ConSysApiHandler extends TimeSeriesHandler {
+    createContext(properties) {
+        if(properties.mode === Mode.REPLAY || properties.mode === Mode.BATCH) {
+            return new ConSysApiReplayContext();
+        } else {
+            return new ConSysApiRealtimeContext();
+        }
+    }
+}
+
+export default ConSysApiHandler;
diff --git a/source/core/datasource/worker/DataSourceWorker.js b/source/core/datasource/worker/DataSourceWorker.js
index b4a102305d..dfe95c3a48 100644
--- a/source/core/datasource/worker/DataSourceWorker.js
+++ b/source/core/datasource/worker/DataSourceWorker.js
@@ -1,6 +1,7 @@
 import SosGetResultHandler from "../sos/handler/SosGetResult.handler";
 import SosGetFoisHandler from "../sos/handler/SosGetFois.handler";
 import SweApiHandler from "../sweapi/handler/SweApi.handler";
+import ConSysApiHandler from "../consysapi/handler/ConSysApi.handler";
 
 class DataSourceWorker {
     constructor() {
@@ -116,6 +117,8 @@ class DataSourceWorker {
             return new SosGetFoisHandler();
         } else if (properties.type === 'SweApiStream') {
             return new SweApiHandler();
+        } else if (properties.type === 'ConSysApiStream') {
+            return new ConSysApiHandler();
         } else {
             throw Error('Unsupported SOS service Error');
         }
diff --git a/source/core/parsers/consysapi/collection/CollectionOmJsonParser.parser.js b/source/core/parsers/consysapi/collection/CollectionOmJsonParser.parser.js
new file mode 100644
index 0000000000..57a65c7706
--- /dev/null
+++ b/source/core/parsers/consysapi/collection/CollectionOmJsonParser.parser.js
@@ -0,0 +1,24 @@
+import OmJsonParser from "../common/OmJsonParser.parser";
+
+class OmJsonCollectionParser extends OmJsonParser {
+    constructor(rootElement) {
+        super(rootElement);
+    }
+    getTimeField() {
+        return 'phenomenonTime';
+    }
+
+    parseDataBlock(arrayBuffer) {
+        let dataBlock = this.textDecoder.decode(arrayBuffer);
+        const jsonData = JSON.parse(dataBlock);
+        const result = [];
+
+        for(let d of jsonData.items) {
+            d['timestamp'] = new Date(d[this.getTimeField()]).getTime();
+            result.push(d);
+        }
+        return result;
+    }
+}
+
+export default OmJsonCollectionParser;
diff --git a/source/core/parsers/consysapi/collection/ConSysApiCollectionObjectParser.js b/source/core/parsers/consysapi/collection/ConSysApiCollectionObjectParser.js
new file mode 100644
index 0000000000..36cfba7edf
--- /dev/null
+++ b/source/core/parsers/consysapi/collection/ConSysApiCollectionObjectParser.js
@@ -0,0 +1,9 @@
+class ConSysApiCollectionObjectParser {
+    constructor(networkProperties) {
+        this.networkProperties = networkProperties;
+    }
+
+    parseData(data) {}
+}
+
+export default ConSysApiCollectionObjectParser;
diff --git a/source/core/parsers/consysapi/collection/ConSysApiControlStreamStatus.parser.js b/source/core/parsers/consysapi/collection/ConSysApiControlStreamStatus.parser.js
new file mode 100644
index 0000000000..71c9701a4b
--- /dev/null
+++ b/source/core/parsers/consysapi/collection/ConSysApiControlStreamStatus.parser.js
@@ -0,0 +1,20 @@
+import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser";
+
+class ConSysApiControlStreamStatusParser extends ConSysApiCollectionObjectParser {
+    constructor(networkProperties) {
+        super(networkProperties);
+        this.textDecoder = new TextDecoder();
+    }
+
+    parseData(data, format) {
+        let res;
+        if(format === 'arraybuffer') {
+            res = this.textDecoder.decode(data);
+        } else {
+            res = JSON.parse(data);
+        }
+        return JSON.parse(res);
+    }
+}
+
+export default ConSysApiControlStreamStatusParser;
diff --git a/source/core/parsers/consysapi/collection/ConSysApiDataStream.parser.js b/source/core/parsers/consysapi/collection/ConSysApiDataStream.parser.js
new file mode 100644
index 0000000000..8666a30c32
--- /dev/null
+++ b/source/core/parsers/consysapi/collection/ConSysApiDataStream.parser.js
@@ -0,0 +1,16 @@
+import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser";
+import DataStream from "../../../consysapi/datastream/DataStream";
+
+class ConSysApiDataStreamParser extends ConSysApiCollectionObjectParser {
+    parseData(data) {
+        return new DataStream(
+            data,
+            {
+                streamProtocol: 'ws', // default streaming
+                ...this.networkProperties
+            }
+        );
+    }
+}
+
+export default ConSysApiDataStreamParser;
diff --git a/source/core/parsers/consysapi/collection/ConSysApiFetchCommand.parser.js b/source/core/parsers/consysapi/collection/ConSysApiFetchCommand.parser.js
new file mode 100644
index 0000000000..e10575dd8f
--- /dev/null
+++ b/source/core/parsers/consysapi/collection/ConSysApiFetchCommand.parser.js
@@ -0,0 +1,21 @@
+import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser";
+import Command from "../../../consysapi/command/Command";
+
+class ConSysApiFetchCommandParser extends ConSysApiCollectionObjectParser {
+    constructor(networkProperties, systemId) {
+        super(networkProperties);
+        this.systemId = systemId;
+    }
+
+    parseData(data) {
+        return new Command(
+            {
+                ...data,
+                systemId: this.systemId
+            },
+            this.networkProperties
+        );
+    }
+}
+
+export default ConSysApiFetchCommandParser;
diff --git a/source/core/parsers/consysapi/collection/ConSysApiFetchControlStream.parser.js b/source/core/parsers/consysapi/collection/ConSysApiFetchControlStream.parser.js
new file mode 100644
index 0000000000..f9efa12fe6
--- /dev/null
+++ b/source/core/parsers/consysapi/collection/ConSysApiFetchControlStream.parser.js
@@ -0,0 +1,16 @@
+import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser";
+import ControlStream from "../../../consysapi/controlstream/ControlStream";
+
+class ConSysApiFetchControlStreamParser extends ConSysApiCollectionObjectParser {
+    parseData(data) {
+        return new ControlStream(
+            data,
+            {
+                streamProtocol: 'ws', // default streaming
+                ...this.networkProperties
+            }
+        );
+    }
+}
+
+export default ConSysApiFetchControlStreamParser;
diff --git a/source/core/parsers/consysapi/collection/ConSysApiFetchEvent.parser.js b/source/core/parsers/consysapi/collection/ConSysApiFetchEvent.parser.js
new file mode 100644
index 0000000000..1d514b4150
--- /dev/null
+++ b/source/core/parsers/consysapi/collection/ConSysApiFetchEvent.parser.js
@@ -0,0 +1,12 @@
+import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser";
+
+class ConSysApiFetchEventParser extends ConSysApiCollectionObjectParser {
+    parseData(data) {
+        return new Event(
+            data,
+            this.networkProperties
+        );
+    }
+}
+
+export default ConSysApiFetchEventParser;
diff --git a/source/core/parsers/consysapi/collection/ConSysApiFetchObservation.parser.js b/source/core/parsers/consysapi/collection/ConSysApiFetchObservation.parser.js
new file mode 100644
index 0000000000..3be6531cec
--- /dev/null
+++ b/source/core/parsers/consysapi/collection/ConSysApiFetchObservation.parser.js
@@ -0,0 +1,13 @@
+import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser";
+import Observation from "../../../consysapi/observation/Observation";
+
+class ConSysApiFetchObservationParser extends ConSysApiCollectionObjectParser {
+    parseData(data) {
+        return new Observation(
+            data,
+            this.networkProperties
+        );
+    }
+}
+
+export default ConSysApiFetchObservationParser;
diff --git a/source/core/parsers/consysapi/collection/ConSysApiFetchSamplingFeature.parser.js b/source/core/parsers/consysapi/collection/ConSysApiFetchSamplingFeature.parser.js
new file mode 100644
index 0000000000..17bcc5b586
--- /dev/null
+++ b/source/core/parsers/consysapi/collection/ConSysApiFetchSamplingFeature.parser.js
@@ -0,0 +1,18 @@
+import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser";
+import SamplingFeature from "../../../consysapi/samplingfeature/SamplingFeature";
+
+class ConSysApiFetchSamplingFeatureParser extends ConSysApiCollectionObjectParser {
+    parseData(data) {
+        return new SamplingFeature(
+            {
+                ...data,
+                geometry: data.geometry || undefined,
+                bbox: data.bbox || undefined
+            },
+
+            this.networkProperties
+        );
+    }
+}
+
+export default ConSysApiFetchSamplingFeatureParser;
diff --git a/source/core/parsers/consysapi/collection/ConSysApiFetchSystem.parser.js b/source/core/parsers/consysapi/collection/ConSysApiFetchSystem.parser.js
new file mode 100644
index 0000000000..b627838ad9
--- /dev/null
+++ b/source/core/parsers/consysapi/collection/ConSysApiFetchSystem.parser.js
@@ -0,0 +1,13 @@
+import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser";
+import System from "../../../consysapi/system/System";
+
+class ConSysApiFetchSystemParser extends ConSysApiCollectionObjectParser {
+    parseData(data) {
+        return new System(
+            data,
+            this.networkProperties
+        );
+    }
+}
+
+export default ConSysApiFetchSystemParser;
diff --git a/source/core/parsers/consysapi/collection/SweCollectionDataParser.js b/source/core/parsers/consysapi/collection/SweCollectionDataParser.js
new file mode 100644
index 0000000000..cb1ebebb42
--- /dev/null
+++ b/source/core/parsers/consysapi/collection/SweCollectionDataParser.js
@@ -0,0 +1,37 @@
+class SweCollectionDataParser {
+
+    constructor(format = 'application/json') {
+        this.format = format;
+    }
+
+    parseData(data) {
+        if (this.format === 'application/om+json' || this.format === 'application/json') {
+            return this.parseOmJsonData(data);
+        } else if (this.format === 'application/swe+json') {
+            return this.parseSweJsonData(data);
+        } else if (this.format === 'application/swe+csv') {
+            return this.parseSweCsv(data);
+        }  else if (this.format === 'application/swe+xml') {
+            return this.parseSweXml(data);
+        }  else {
+            throw Error(`Unsupported collection format ${this.format}`);
+        }
+    }
+
+    parseOmJsonData(data) {
+        return (data instanceof ArrayBuffer) ? JSON.parse(String.fromCharCode.apply(null, new Uint8Array(data))).items : data.items;
+    }
+
+    parseSweJsonData(data) {
+        return (data instanceof ArrayBuffer) ? JSON.parse(String.fromCharCode.apply(null, new Uint8Array(data))) : data;
+    }
+
+    parseSweCsv(data) {
+        let content = (data instanceof ArrayBuffer) ? String.fromCharCode.apply(null, new Uint8Array(data)) : data;
+        return content.split('\n');
+    }
+    parseSweXml(data) {
+        return (data instanceof ArrayBuffer) ? String.fromCharCode.apply(null, new Uint8Array(data)) : data;
+    }
+}
+export default SweCollectionDataParser;
diff --git a/source/core/parsers/consysapi/common/OmJsonParser.parser.js b/source/core/parsers/consysapi/common/OmJsonParser.parser.js
new file mode 100644
index 0000000000..2f65224dbe
--- /dev/null
+++ b/source/core/parsers/consysapi/common/OmJsonParser.parser.js
@@ -0,0 +1,12 @@
+import JsonDataParser from "../../JsonDataParser";
+
+class OmJsonParser extends JsonDataParser {
+    constructor(rootElement) {
+        super(rootElement);
+    }
+    getTimeField() {
+        return 'phenomenonTime';
+    }
+}
+
+export default OmJsonParser;
diff --git a/source/core/parsers/consysapi/common/SweBinaryParser.parser.js b/source/core/parsers/consysapi/common/SweBinaryParser.parser.js
new file mode 100644
index 0000000000..d59f4b4d7c
--- /dev/null
+++ b/source/core/parsers/consysapi/common/SweBinaryParser.parser.js
@@ -0,0 +1,9 @@
+import BinaryDataParser from "../../BinaryDataParser";
+
+class SweBinaryParser extends BinaryDataParser {
+    constructor(rootElement, encoding) {
+        super(rootElement, encoding)
+    }
+}
+
+export default SweBinaryParser;
diff --git a/source/core/parsers/consysapi/common/SweCsvParser.parser.js b/source/core/parsers/consysapi/common/SweCsvParser.parser.js
new file mode 100644
index 0000000000..c4364054c1
--- /dev/null
+++ b/source/core/parsers/consysapi/common/SweCsvParser.parser.js
@@ -0,0 +1,9 @@
+import TextDataParser from "../../TextDataParser";
+
+class SweCsvParser extends TextDataParser {
+    constructor(rootElement, encoding) {
+        super(rootElement, encoding)
+    }
+}
+
+export default SweCsvParser;
diff --git a/source/core/parsers/consysapi/common/SweJsonParser.parser.js b/source/core/parsers/consysapi/common/SweJsonParser.parser.js
new file mode 100644
index 0000000000..12f818a96b
--- /dev/null
+++ b/source/core/parsers/consysapi/common/SweJsonParser.parser.js
@@ -0,0 +1,9 @@
+import JsonDataParser from "../../JsonDataParser";
+
+class SweJsonParser extends JsonDataParser {
+    constructor(rootElement) {
+        super(rootElement)
+    }
+}
+
+export default SweJsonParser;
diff --git a/source/core/parsers/consysapi/common/SweXmlParser.parser.js b/source/core/parsers/consysapi/common/SweXmlParser.parser.js
new file mode 100644
index 0000000000..705e5c3f37
--- /dev/null
+++ b/source/core/parsers/consysapi/common/SweXmlParser.parser.js
@@ -0,0 +1,9 @@
+import JsonDataParser from "../../../parsers/JsonDataParser";
+
+class SweXmlParser extends JsonDataParser {
+    constructor(rootElement) {
+        super(rootElement)
+    }
+}
+
+export default SweXmlParser;
diff --git a/source/core/parsers/consysapi/observations/ConSysApiResult.collection.controlstream.parser.js b/source/core/parsers/consysapi/observations/ConSysApiResult.collection.controlstream.parser.js
new file mode 100644
index 0000000000..46f30df86b
--- /dev/null
+++ b/source/core/parsers/consysapi/observations/ConSysApiResult.collection.controlstream.parser.js
@@ -0,0 +1,21 @@
+import ConSysApiResultControlStreamParser from "./ConSysApiResult.controlstream.parser";
+
+class ConSysApiResultCollectionControlStreamParser extends ConSysApiResultControlStreamParser {
+    constructor(dataObject) {
+        super(dataObject);
+    }
+
+    init(schema, format) {
+        if(format === 'application/swe+binary') {
+            //resultSchema
+            throw new Error(`Format not supported ${format}`);
+        } else if(format === 'application/swe+xml') {
+            //resultSchema
+            throw new Error(`Format not supported ${format}`);
+        } else {
+            super.init(schema, format);
+        }
+    }
+}
+
+export default ConSysApiResultCollectionControlStreamParser;
diff --git a/source/core/parsers/consysapi/observations/ConSysApiResult.collection.datastream.parser.js b/source/core/parsers/consysapi/observations/ConSysApiResult.collection.datastream.parser.js
new file mode 100644
index 0000000000..5016da7737
--- /dev/null
+++ b/source/core/parsers/consysapi/observations/ConSysApiResult.collection.datastream.parser.js
@@ -0,0 +1,22 @@
+import OmJsonCollectionParser from "../collection/CollectionOmJsonParser.parser";
+import ConSysApiResultDatastreamParser from "./ConSysApiResult.datastream.parser";
+
+class ConSysApiResultCollectionDatastreamParser extends ConSysApiResultDatastreamParser {
+    constructor(dataObject) {
+        super(dataObject);
+    }
+
+    init(schema, format) {
+        if(format === 'application/om+json') {
+            //resultSchema
+            this.parsers[format].parser = new OmJsonCollectionParser(schema.resultSchema);
+        } else if(format === 'application/swe+xml') {
+            //resultSchema
+            throw new Error(`Format not supported ${format}`);
+        } else {
+            super.init(schema, format);
+        }
+    }
+}
+
+export default ConSysApiResultCollectionDatastreamParser;
diff --git a/source/core/parsers/consysapi/observations/ConSysApiResult.controlstream.parser.js b/source/core/parsers/consysapi/observations/ConSysApiResult.controlstream.parser.js
new file mode 100644
index 0000000000..e47e7f3cc4
--- /dev/null
+++ b/source/core/parsers/consysapi/observations/ConSysApiResult.controlstream.parser.js
@@ -0,0 +1,34 @@
+import OmJsonParser from "../common/OmJsonParser.parser";
+import ConSysApiResultParser from "./ConSysApiResult.parser";
+import SweJsonParser from "../common/SweJsonParser.parser";
+import SweBinaryParser from "../common/SweBinaryParser.parser";
+import SweCsvParser from "../common/SweCsvParser.parser";
+
+class ConSysApiResultControlStreamParser extends ConSysApiResultParser {
+    constructor(dataObject) {
+        super(dataObject);
+    }
+
+    init(schema, format) {
+        if(format === 'application/om+json') {
+            //resultSchema
+            this.parsers[format].parser = new OmJsonParser(schema.commandSchema);
+        } else if(format === 'application/swe+json') {
+            //recordSchema
+            this.parsers[format].parser  = new SweJsonParser(schema.commandSchema);
+        } /*else if(format === 'application/swe+xml') {
+            //recordSchema
+            this.parsers[format].parser = new SweXmlParser(schema.recordSchema);
+        }*/ else if(format === 'application/swe+binary') {
+            //recordSchema
+            this.parsers[format].parser = new SweBinaryParser(schema.commandSchema, schema.commandEncoding);
+        } else if(format === 'application/swe+csv') {
+            //recordSchema
+            this.parsers[format].parser = new SweCsvParser(schema.commandSchema, schema.commandEncoding);
+        } else {
+            throw Error(`Not supported parser format: ${format}`);
+        }
+    }
+}
+
+export default ConSysApiResultControlStreamParser;
diff --git a/source/core/parsers/consysapi/observations/ConSysApiResult.datastream.parser.js b/source/core/parsers/consysapi/observations/ConSysApiResult.datastream.parser.js
new file mode 100644
index 0000000000..a3c905bdec
--- /dev/null
+++ b/source/core/parsers/consysapi/observations/ConSysApiResult.datastream.parser.js
@@ -0,0 +1,38 @@
+import OmJsonParser from "../common/OmJsonParser.parser";
+import ConSysApiResultParser from "./ConSysApiResult.parser";
+import SweJsonParser from "../common/SweJsonParser.parser";
+import SweBinaryParser from "../common/SweBinaryParser.parser";
+import SweCsvParser from "../common/SweCsvParser.parser";
+import {isDefined} from "../../../utils/Utils";
+
+class ConSysApiResultDatastreamParser extends ConSysApiResultParser {
+    constructor(dataObject) {
+        super(dataObject);
+    }
+
+    init(schema, format) {
+        if(format in this.parsers && isDefined(this.parsers[format].parser)) {
+            return this.parsers[format].parser;
+        }
+        if(format === 'application/om+json') {
+            //resultSchema
+            this.parsers[format].parser = new OmJsonParser(schema.resultSchema);
+        } else if(format === 'application/swe+json') {
+            //recordSchema
+            this.parsers[format].parser  = new SweJsonParser(schema.recordSchema);
+        } /*else if(format === 'application/swe+xml') {
+            //recordSchema
+            this.parsers[format].parser = new SweXmlParser(schema.recordSchema);
+        }*/ else if(format === 'application/swe+binary') {
+            //recordSchema
+            this.parsers[format].parser = new SweBinaryParser(schema.recordSchema, schema.recordEncoding);
+        } else if(format === 'application/swe+csv') {
+            //recordSchema
+            this.parsers[format].parser = new SweCsvParser(schema.recordSchema, schema.recordEncoding);
+        } else {
+            throw Error(`Not supported parser format: ${format}`);
+        }
+    }
+}
+
+export default ConSysApiResultDatastreamParser;
diff --git a/source/core/parsers/consysapi/observations/ConSysApiResult.parser.js b/source/core/parsers/consysapi/observations/ConSysApiResult.parser.js
new file mode 100644
index 0000000000..a12c8e3122
--- /dev/null
+++ b/source/core/parsers/consysapi/observations/ConSysApiResult.parser.js
@@ -0,0 +1,69 @@
+import ConnectedSystemsApiFilter from "../../../consysapi/Filter";
+import {isDefined} from "../../../utils/Utils";
+
+class ConSysApiResultParser  {
+    constructor(dataObject) {
+        this.dataObject = dataObject;
+        this.parsers = {
+            'application/om+json' : {
+                schemaPromise: undefined,
+                parser: undefined
+            },
+            'application/swe+json' : {
+                schemaPromise: undefined,
+                parser: undefined
+            },
+            'application/swe+xml' : {
+                schemaPromise: undefined,
+                parser: undefined
+            },
+            'application/swe+csv' : {
+                schemaPromise: undefined,
+                parser: undefined
+            },
+            'application/swe+binary' : {
+                schemaPromise: undefined,
+                parser: undefined
+            }
+        }
+    }
+
+    async checkParser(format) {
+        if(!(format in this.parsers)) {
+            throw new Error(`Not support format ${format}`);
+        }
+
+        const parser = this.parsers[format];
+        if(!isDefined(parser.parser)) {
+            if(!isDefined(parser.schemaPromise)) {
+                this.parsers[format].schemaPromise = new Promise(async (resolve, reject) => {
+                    try {
+                        const jsonSchema = await this.dataObject.getSchema(new ConnectedSystemsApiFilter({
+                            obsFormat: format
+                        }));
+                        this.init(jsonSchema, format);
+                        resolve();
+                    } catch (ex) {
+                      console.error(ex);
+                      reject(ex);
+                    }
+                });
+            }
+            await parser.schemaPromise;
+            return this.parsers[format].parser;
+        } else {
+            return parser.parser;
+        }
+    }
+
+    init(schema, format) {
+        throw new Error('Unsupported Operation')
+    }
+
+    async parseDataBlock(arrayBuffer, format = 'application/om+json') {
+        const parser = await this.checkParser(format);
+        return parser.parseDataBlock(arrayBuffer);
+    }
+}
+
+export default ConSysApiResultParser;