From 037c1f05831b090c30f53c17fce1e023aa34fb3a Mon Sep 17 00:00:00 2001
From: Diego Francisco Carvajal Flores <diegofcarvajalf@gmail.com>
Date: Mon, 27 Jun 2022 18:19:49 +0200
Subject: [PATCH] Update

---
 Dockerfile           |   4 +-
 L5.ts                | 241 ++++++++++++++++++++++++++++++++++++
 environment.env      |  16 +--
 upmclient.ts         |  54 ++++----
 upmclientNoDocker.ts | 286 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 564 insertions(+), 37 deletions(-)
 create mode 100644 L5.ts
 create mode 100644 upmclientNoDocker.ts

diff --git a/Dockerfile b/Dockerfile
index c270c47..3cb3840 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,7 +8,7 @@ COPY . .
 
 # COPY ./client.ts ./
 
-COPY ./upmclient.ts ./
+COPY ./L5.ts ./
 
 COPY ./Logger.ts ./
 
@@ -20,4 +20,4 @@ RUN npm install typescript
 
 RUN npm install -g ts-node
 
-CMD [ "ts-node", "./upmclient.ts" ]
+CMD [ "ts-node", "./L5.ts" ]
diff --git a/L5.ts b/L5.ts
new file mode 100644
index 0000000..4e335b8
--- /dev/null
+++ b/L5.ts
@@ -0,0 +1,241 @@
+
+import { AttributeIds,OPCUAClient,DataValue,TimestampsToReturn,SecurityPolicy, NotificationMessage} from "node-opcua";
+import { Logger } from './Logger'
+import { trytypes } from './trytypes'
+
+var trayType="NA";
+var default_index = 0
+// const nodeId_TypeNoCur = "ns=4;s=\"DataHandling\".\"TypeNoCur\"";
+const dateIssued ="https://smart-data-models.github.io/data-models/terms.jsonld#/definitions/dateIssued"
+var axios= require("axios")
+//Fiware Configuration
+const fiware_url=process.env.FIWARE_SERVER_URL || undefined
+const fiware_node_id=process.env.FIWARE_NODE_ID || undefined
+//const fiware_node_id="urn:ngsi-ld:Alert:BOSH:feed-trigger-";
+
+//Line 5 configuration
+const LINE_5_URL=process.env.LINE_5_URL || undefined
+const TypeNoCur_plc_nodeid_L5=process.env.TypeNoCur_NODEID_L5 || undefined
+const BlisterEntry_plc_nodeid_L5=process.env.BlisterEntry_NODEID_L5|| undefined
+
+// interval of subscription checks
+const publishing_interval = 1000
+
+
+var notification_body ={
+    id: '',
+    type: "Alert",
+    category:{
+        type: "Property",
+        value: "feeding-trigger"
+    },
+    description: {
+        type: "Property",
+        value: '',
+                 },
+    dateIssued: {
+        type: "Property",
+        value: {
+            "@type": "DateTime",
+            "@value": new Date().toISOString()
+        }
+                },
+            
+      alertSource: {
+        type: "Relationship",
+        object: ''
+    },
+    "@context": [
+       "https://smartdatamodels.org/context.jsonld",
+       "https://raw.githubusercontent.com/shop4cf/data-models/master/docs/shop4cfcontext.jsonld"
+
+    ]       
+
+    }
+
+const connectionStrategy={
+    maxRetry: 2,
+    initialDelay: 2000,
+    maxDelay: 10 * 1000
+}
+const requestedParameter= {
+    samplingInterval: 500,
+    discardOldest: true,
+    queueSize: 10
+}
+const serverConnectionConfiguration={
+    endpointMustExist: false,
+    securityPolicy: SecurityPolicy.None,
+    applicationName: "WoT-IL",
+    connectionStrategy: connectionStrategy
+}
+
+
+async function init(){
+
+    if(fiware_node_id == undefined){
+        Logger.failure(`Undefined fiware_node_id. Actual value =${fiware_node_id}. Check environment configuration`)
+        throw new Error();
+    }
+    if(fiware_url == undefined){
+        const message=`Undefined fiware_url. Actual value =${fiware_url}. Check environment configuration`
+        Logger.failure(message)
+        throw new Error(message);
+    }
+    
+    
+    if(LINE_5_URL == undefined){
+        const message=`Undefined LINE_5_URL. Actual value =${LINE_5_URL}. Check environment configuration`
+        Logger.failure(message)
+        throw new Error(message);
+    }
+    
+    
+
+    if(TypeNoCur_plc_nodeid_L5 == undefined){
+        const message=`Undefined TypeNoCur_plc_nodeid_L5. Actual value =${TypeNoCur_plc_nodeid_L5}. Check environment configuration`
+        Logger.failure(message)
+        throw new Error(message);
+    }
+    if(BlisterEntry_plc_nodeid_L5 == undefined){
+        const message=`Undefined BlisterEntry_plc_nodeid_L5. Actual value =${BlisterEntry_plc_nodeid_L5}. Check environment configuration`
+        Logger.failure(message)
+        throw new Error(message);
+    }
+    
+    const entity_id = await getLastRecordOfType("https://uri.fiware.org/ns/data-models%23Alert")
+    if(entity_id > 0){
+        default_index = entity_id
+    }
+
+    
+    //Line 5 setup
+    const l5_client = await connectoToPLC(LINE_5_URL)
+    const TypeNoCur_subscription_L5 = await createSubscription(l5_client,TypeNoCur_plc_nodeid_L5)
+    const BlisterEntry_subscription_L5 = await createSubscription(l5_client,BlisterEntry_plc_nodeid_L5)
+
+    TypeNoCur_subscription_L5.on("changed",  async (dataValue_TypeNoCur: DataValue) => {
+        Logger.debug(`Monitoring TypeNoCur on line 5. Current value = ${dataValue_TypeNoCur.value.value.toString()}`)
+        if(trytypes.TypeA.indexOf(dataValue_TypeNoCur.value.value.toString()) != -1){
+            trayType = 'A'
+        }else if(trytypes.TypeB.indexOf(dataValue_TypeNoCur.value.value.toString()) == -1){
+            trayType = 'B'
+        }else if(trytypes.TypeC.indexOf(dataValue_TypeNoCur.value.value.toString()) == -1){
+            trayType = 'C'
+        }else{
+            Logger.warn(`L5 - tray type not defined. Given ${dataValue_TypeNoCur.value.value.toString()}`)
+        }       
+    });
+    
+    BlisterEntry_subscription_L5.on("changed",  async (dataValue_BlisterEntry: DataValue) => {
+        Logger.debug(`Monitoring BlisterEntry on line 5. Current value = ${dataValue_BlisterEntry.value.value.toString()}`)
+        if(dataValue_BlisterEntry.value.value.toString() == "false"){
+            default_index=default_index+1;
+            notification_body.id=`${fiware_node_id}${default_index}`
+            notification_body.description.value=trayType
+            notification_body.alertSource.object='urn:ngsi-ld:Asset:BOSH:LS5'
+            postRecord(notification_body)
+           }else{
+            Logger.debug("No tray needed at line L5")
+        }         
+    });
+
+}
+
+async function connectoToPLC(url:any){
+    Logger.debug(`Connecting to PLC ${url}...`)
+    const client = OPCUAClient.create(serverConnectionConfiguration);
+    try {
+        await  client.connect(url)
+        return client
+    } catch (error) {
+        Logger.failure(`Can not connect to PLC ${url} --- ${JSON.stringify(error)}`)
+    }
+}
+
+async function getLastRecordOfType(record_type:any){
+    Logger.debug(`Finding record of type ${record_type}`)
+    try {
+        var result = await axios.get(`${fiware_url}/ngsi-ld/v1/entities?type=${record_type}`).then((response:any)=>response.data)
+    if(result.length != 0 ){
+        let idStartNumber = result.map((o:any)=>o.id.split('-')
+            .slice(-1)[0])
+            .map((l:string)=>parseInt(l)).sort( (a: number,b: number) =>a - b )
+            .slice(-1)[0]
+
+    Logger.debug(`Last notification id was  ${idStartNumber}`)
+      return parseInt(idStartNumber)
+    }else{
+        Logger.debug(`There is no entity matching with ${record_type}`)
+        return 0
+    } 
+    } catch (error) {
+        Logger.failure(`EXCEPTION GIVEN - Can not get getLastRecordOfType  ${record_type } - ${JSON.stringify(error)}`)
+        return 0
+    }
+}
+
+async function createSubscription(client:any,node_id:any) {
+    Logger.debug(`Creating subscription for ${node_id}...`);
+    const session = await client.createSession();
+    const subscription = await  session.createSubscription2({
+        requestedPublishingInterval: 1000,
+        requestedLifetimeCount: 100,
+        requestedMaxKeepAliveCount: 20,
+        maxNotificationsPerPublish: 10,
+        publishingEnabled: true,
+        priority: 10
+    });
+
+    subscription
+        .on("Started", () => console.log("Subscription started - subscriptionId=", subscription.subscriptionId))
+        .on("Keepalive", () => Logger.debug(`keep alive ${node_id}`))
+        .on("Terminated", () => console.log("Subscription terminated"));
+    const itemToMonitor={
+        nodeId:node_id,
+        attributeId: AttributeIds.Value
+    }
+    const monitoredItem = await subscription.monitor(
+        itemToMonitor,
+        requestedParameter,
+        TimestampsToReturn.Both);
+return monitoredItem
+}
+
+async function readVariable(client:any,node:any){
+    const session = await client.createSession();
+    const maxAge = 0;
+    const nodeToRead = {
+      nodeId: node,
+    };
+    const dataValue =  await session.read(nodeToRead, maxAge);
+    console.log(" Value " , dataValue.toString());
+}
+
+async function browse(client:any){
+   
+    const session = await client.createSession();
+    const browseResult = await session.browse("RootFolder");
+    // const browsePath = makeBrowsePath("RootFolder", "/Objects/Server.ServerStatus.BuildInfo");
+    // const result = await session.translateBrowsePath(browsePath);
+    console.log(JSON.stringify(browseResult));
+    
+    // const productNameNodeId = result.targets[0].targetId;
+    // console.log(" Product Name nodeId = ", productNameNodeId.toString());
+}
+
+function postRecord(body:any){
+    const headers={
+        'Content-Type': 'application/ld+json',
+        }
+    Logger.debug(`body id = ${body.id}`)
+    axios.post(`${fiware_url}/ngsi-ld/v1/entities`,body,{headers:headers}).then((response:any)=>{
+        Logger.debug(JSON.stringify({response:response.status,statusText:response.statusText}))
+    },(error:any)=>{
+        Logger.failure(JSON.stringify(error))
+    }).catch((r:any)=>{
+        Logger.failure(JSON.stringify(r))
+    })
+
+}
+init()
diff --git a/environment.env b/environment.env
index 2d4e1ef..00253cb 100644
--- a/environment.env
+++ b/environment.env
@@ -1,11 +1,11 @@
-LINE_2_URL=opc.tcp://10.151.233.6:4334
-TypeNoCur_NODEID_L2=ns=1;s=DataHandling.TypeNoCur
-BlisterEntry_NODEID_L2=ns=1;s=Station090.BlisterEntry
+LINE_2_URL=opc.tcp://10.100.151.40:4840
+TypeNoCur_NODEID_L2=ns=4;s=DataHandling.TypeNoCur
+BlisterEntry_NODEID_L2=ns=4;s=Station090.BlisterEntry
 
-LINE_5_URL=opc.tcp://10.151.233.6:4334
-TypeNoCur_NODEID_L5=ns=1;s=DataHandling.TypeNoCur2
-BlisterEntry_NODEID_L5=ns=1;s=Station090.BlisterEntry2
+LINE_5_URL=opc.tcp://10.100.168.13:4840
+TypeNoCur_NODEID_L5=ns=4;s=DataHandling.TypeNoCur
+BlisterEntry_NODEID_L5=ns=4;s=Station090.BlisterEntry
 
 FIWARE_NODE_ID=urn:ngsi-ld:Alert:BOSH:feed-trigger-
-FIWARE_SERVER_URL=http://10.151.233.6:1026
-#FIWARE_RECORD_TYPE=https://uri.fiware.org/ns/data-models%23Alert
\ No newline at end of file
+FIWARE_SERVER_URL=http://10.100.147.11:1026
+#FIWARE_RECORD_TYPE=https://uri.fiware.org/ns/data-models%23Alert
diff --git a/upmclient.ts b/upmclient.ts
index aed9ea0..74316df 100644
--- a/upmclient.ts
+++ b/upmclient.ts
@@ -48,7 +48,7 @@ var notification_body ={
             
       alertSource: {
         type: "Relationship",
-        object: "urn:ngsi-ld:Asset:BOS:LS2"
+        object: ''
     },
     "@context": [
        "https://smartdatamodels.org/context.jsonld",
@@ -69,7 +69,7 @@ const requestedParameter= {
     queueSize: 10
 }
 const serverConnectionConfiguration={
-    endpoint_must_exist: false,
+    endpointMustExist: false,
     securityPolicy: SecurityPolicy.None,
     applicationName: "WoT-IL",
     connectionStrategy: connectionStrategy
@@ -79,49 +79,49 @@ const serverConnectionConfiguration={
 async function init(){
 
     if(fiware_node_id == undefined){
-        Logger.failure(`undefined fiware_node_id. Actual value =${fiware_node_id}. Check environment configuration`)
+        Logger.failure(`Undefined fiware_node_id. Actual value =${fiware_node_id}. Check environment configuration`)
         throw new Error();
     }
     if(fiware_url == undefined){
-        const message=`undefined fiware_url. Actual value =${fiware_url}. Check environment configuration`
+        const message=`Undefined fiware_url. Actual value =${fiware_url}. Check environment configuration`
         Logger.failure(message)
         throw new Error(message);
     }
     if(LINE_2_URL == undefined){
-        const message=`undefined LINE_2_URL. Actual value =${LINE_2_URL}. Check environment configuration`
+        const message=`Undefined LINE_2_URL. Actual value =${LINE_2_URL}. Check environment configuration`
         Logger.failure(message)
         throw new Error(message);
     }
     if(LINE_5_URL == undefined){
-        const message=`undefined LINE_5_URL. Actual value =${LINE_5_URL}. Check environment configuration`
+        const message=`Undefined LINE_5_URL. Actual value =${LINE_5_URL}. Check environment configuration`
         Logger.failure(message)
         throw new Error(message);
     }
     if(TypeNoCur_plc_nodeid_L2 == undefined){
-        const message=`undefined TypeNoCur_plc_nodeid_L2. Actual value =${TypeNoCur_plc_nodeid_L2}. Check environment configuration`
+        const message=`Undefined TypeNoCur_plc_nodeid_L2. Actual value =${TypeNoCur_plc_nodeid_L2}. Check environment configuration`
         Logger.failure(message)
         throw new Error(message);
     }
     if(BlisterEntry_plc_nodeid_L2 == undefined){
-        const message=`undefined BlisterEntry_plc_nodeid_L2. Actual value =${BlisterEntry_plc_nodeid_L2}. Check environment configuration`
+        const message=`Undefined BlisterEntry_plc_nodeid_L2. Actual value =${BlisterEntry_plc_nodeid_L2}. Check environment configuration`
         Logger.failure(message)
         throw new Error(message);
     }
 
     if(TypeNoCur_plc_nodeid_L5 == undefined){
-        const message=`undefined TypeNoCur_plc_nodeid_L5. Actual value =${TypeNoCur_plc_nodeid_L5}. Check environment configuration`
+        const message=`Undefined TypeNoCur_plc_nodeid_L5. Actual value =${TypeNoCur_plc_nodeid_L5}. Check environment configuration`
         Logger.failure(message)
         throw new Error(message);
     }
     if(BlisterEntry_plc_nodeid_L5 == undefined){
-        const message=`undefined BlisterEntry_plc_nodeid_L5. Actual value =${BlisterEntry_plc_nodeid_L5}. Check environment configuration`
+        const message=`Undefined BlisterEntry_plc_nodeid_L5. Actual value =${BlisterEntry_plc_nodeid_L5}. Check environment configuration`
         Logger.failure(message)
         throw new Error(message);
     }
     
     const entity_id = await getLastRecordOfType("https://uri.fiware.org/ns/data-models%23Alert")
     if(entity_id > 0){
-        default_index = 0
+        default_index = entity_id
     }
 
     //Line 2 setup
@@ -138,7 +138,7 @@ async function init(){
         }else if(trytypes.TypeC.indexOf(dataValue_TypeNoCur.value.value.toString()) == -1){
             trayType = 'C'
         }else{
-            Logger.warn(`L2 - try type not defined. Given ${dataValue_TypeNoCur.value.value.toString()}`)
+            Logger.warn(`L2 - tray type not defined. Given ${dataValue_TypeNoCur.value.value.toString()}`)
         }       
     });
     
@@ -148,10 +148,10 @@ async function init(){
             default_index=default_index+1;
             notification_body.id=`${fiware_node_id}${default_index}`
             notification_body.description.value=trayType
-            notification_body.alertSource.object='urn:ngsi-ld:Asset:BOS:LS2'
+            notification_body.alertSource.object='urn:ngsi-ld:Asset:BOSH:LS2'
             postRecord(notification_body)
            }else{
-            Logger.debug("BlisterEntry at line L2 is not needed")
+            Logger.debug("No tray needed at line L2")
         }         
     });
     //Line 5 setup
@@ -168,7 +168,7 @@ async function init(){
         }else if(trytypes.TypeC.indexOf(dataValue_TypeNoCur.value.value.toString()) == -1){
             trayType = 'C'
         }else{
-            Logger.warn(`L5 - try type not defined. Given ${dataValue_TypeNoCur.value.value.toString()}`)
+            Logger.warn(`L5 - tray type not defined. Given ${dataValue_TypeNoCur.value.value.toString()}`)
         }       
     });
     
@@ -178,10 +178,10 @@ async function init(){
             default_index=default_index+1;
             notification_body.id=`${fiware_node_id}${default_index}`
             notification_body.description.value=trayType
-            notification_body.alertSource.object='urn:ngsi-ld:Asset:BOS:LS5'
+            notification_body.alertSource.object='urn:ngsi-ld:Asset:BOSH:LS5'
             postRecord(notification_body)
            }else{
-            Logger.debug("BlisterEntry at line L5 is not needed")
+            Logger.debug("No tray needed at line L5")
         }         
     });
 
@@ -194,12 +194,12 @@ async function connectoToPLC(url:any){
         await  client.connect(url)
         return client
     } catch (error) {
-        Logger.failure(`Cant connect to PLC ${url} --- ${JSON.stringify(error)}`)
+        Logger.failure(`Can not connect to PLC ${url} --- ${JSON.stringify(error)}`)
     }
 }
 
 async function getLastRecordOfType(record_type:any){
-    Logger.debug(`finding record of type ${record_type}`)
+    Logger.debug(`Finding record of type ${record_type}`)
     try {
         var result = await axios.get(`${fiware_url}/ngsi-ld/v1/entities?type=${record_type}`).then((response:any)=>response.data)
     if(result.length != 0 ){
@@ -208,20 +208,20 @@ async function getLastRecordOfType(record_type:any){
             .map((l:string)=>parseInt(l)).sort( (a: number,b: number) =>a - b )
             .slice(-1)[0]
 
-    Logger.debug(`last notification id was  ${idStartNumber}`)
+    Logger.debug(`Last notification id was  ${idStartNumber}`)
       return parseInt(idStartNumber)
     }else{
-        Logger.debug(`there is no entity matching with ${record_type}`)
+        Logger.debug(`There is no entity matching with ${record_type}`)
         return 0
     } 
     } catch (error) {
-        Logger.failure(`EXCEPTION GIVEN - cant get getLastRecordOfType  ${record_type } - ${JSON.stringify(error)}`)
+        Logger.failure(`EXCEPTION GIVEN - Can not get getLastRecordOfType  ${record_type } - ${JSON.stringify(error)}`)
         return 0
     }
 }
 
 async function createSubscription(client:any,node_id:any) {
-    Logger.debug(`creating subscription for ${node_id}...`);
+    Logger.debug(`Creating subscription for ${node_id}...`);
     const session = await client.createSession();
     const subscription = await  session.createSubscription2({
         requestedPublishingInterval: 1000,
@@ -233,9 +233,9 @@ async function createSubscription(client:any,node_id:any) {
     });
 
     subscription
-        .on("started", () => console.log("subscription started - subscriptionId=", subscription.subscriptionId))
-        .on("keepalive", () => Logger.debug(`keep alive ${node_id}`))
-        .on("terminated", () => console.log("subscription terminated"));
+        .on("Started", () => console.log("Subscription started - subscriptionId=", subscription.subscriptionId))
+        .on("Keepalive", () => Logger.debug(`keep alive ${node_id}`))
+        .on("Terminated", () => console.log("Subscription terminated"));
     const itemToMonitor={
         nodeId:node_id,
         attributeId: AttributeIds.Value
@@ -254,7 +254,7 @@ async function readVariable(client:any,node:any){
       nodeId: node,
     };
     const dataValue =  await session.read(nodeToRead, maxAge);
-    console.log(" value " , dataValue.toString());
+    console.log(" Value " , dataValue.toString());
 }
 
 async function browse(client:any){
diff --git a/upmclientNoDocker.ts b/upmclientNoDocker.ts
new file mode 100644
index 0000000..f07cae2
--- /dev/null
+++ b/upmclientNoDocker.ts
@@ -0,0 +1,286 @@
+
+import { AttributeIds,OPCUAClient,DataValue,TimestampsToReturn,SecurityPolicy, NotificationMessage} from "node-opcua";
+import { Logger } from './Logger'
+import { trytypes } from './trytypes'
+
+var trayType="NA";
+var default_index = 0
+
+// const nodeId_TypeNoCur = "ns=4;s=\"DataHandling\".\"TypeNoCur\"";
+const dateIssued ="https://smart-data-models.github.io/data-models/terms.jsonld#/definitions/dateIssued"
+var axios= require("axios")
+//Fiware Configuration
+const fiware_url="http://localhost:1026"
+const fiware_node_id="urn:ngsi-ld:Alert:BOSH:feed-trigger-"
+
+
+//Line 2 configuration
+const LINE_2_URL="opc.tcp://localhost:4334"
+const TypeNoCur_plc_nodeid_L2="ns=1;s=DataHandling.TypeNoCur"
+const BlisterEntry_plc_nodeid_L2="ns=1;s=Station090.BlisterEntry"
+
+//Line 5 configuration
+const LINE_5_URL="opc.tcp://localhost:4334"
+const TypeNoCur_plc_nodeid_L5="ns=1;s=DataHandling.TypeNoCur2"
+const BlisterEntry_plc_nodeid_L5="ns=1;s=Station090.BlisterEntry2"
+// interval of subscription checks
+const publishing_interval = 1000
+
+
+var notification_body ={
+    id: '',
+    type: "Alert",
+    category:{
+        type: "Property",
+        value: "feeding-trigger"
+    },
+    description: {
+        type: "Property",
+        value: '',
+                 },
+    dateIssued: {
+        type: "Property",
+        value: {
+            "@type": "DateTime",
+            "@value": new Date().toISOString()
+        }
+                },
+            
+      alertSource: {
+        type: "Relationship",
+        object: "urn:ngsi-ld:Asset:BOSH:LS2"
+    },
+    "@context": [
+       "https://smartdatamodels.org/context.jsonld",
+       "https://raw.githubusercontent.com/shop4cf/data-models/master/docs/shop4cfcontext.jsonld"
+
+    ]       
+
+    }
+
+const connectionStrategy={
+    maxRetry: 2,
+    initialDelay: 2000,
+    maxDelay: 10 * 1000
+}
+const requestedParameter= {
+    samplingInterval: 500,
+    discardOldest: true,
+    queueSize: 10
+}
+const serverConnectionConfiguration={
+    endpointMustExist: false,
+    securityPolicy: SecurityPolicy.None,
+    applicationName: "WoT-IL",
+    connectionStrategy: connectionStrategy
+}
+
+
+async function init(){
+
+    if(fiware_node_id == undefined){
+        Logger.failure(`undefined fiware_node_id. Actual value =${fiware_node_id}. Check environment configuration`)
+        throw new Error();
+    }
+    if(fiware_url == undefined){
+        const message=`undefined fiware_url. Actual value =${fiware_url}. Check environment configuration`
+        Logger.failure(message)
+        throw new Error(message);
+    }
+    if(LINE_2_URL == undefined){
+        const message=`undefined LINE_2_URL. Actual value =${LINE_2_URL}. Check environment configuration`
+        Logger.failure(message)
+        throw new Error(message);
+    }
+    if(LINE_5_URL == undefined){
+        const message=`undefined LINE_5_URL. Actual value =${LINE_5_URL}. Check environment configuration`
+        Logger.failure(message)
+        throw new Error(message);
+    }
+    if(TypeNoCur_plc_nodeid_L2 == undefined){
+        const message=`undefined TypeNoCur_plc_nodeid_L2. Actual value =${TypeNoCur_plc_nodeid_L2}. Check environment configuration`
+        Logger.failure(message)
+        throw new Error(message);
+    }
+    if(BlisterEntry_plc_nodeid_L2 == undefined){
+        const message=`undefined BlisterEntry_plc_nodeid_L2. Actual value =${BlisterEntry_plc_nodeid_L2}. Check environment configuration`
+        Logger.failure(message)
+        throw new Error(message);
+    }
+
+    if(TypeNoCur_plc_nodeid_L5 == undefined){
+        const message=`undefined TypeNoCur_plc_nodeid_L5. Actual value =${TypeNoCur_plc_nodeid_L5}. Check environment configuration`
+        Logger.failure(message)
+        throw new Error(message);
+    }
+    if(BlisterEntry_plc_nodeid_L5 == undefined){
+        const message=`undefined BlisterEntry_plc_nodeid_L5. Actual value =${BlisterEntry_plc_nodeid_L5}. Check environment configuration`
+        Logger.failure(message)
+        throw new Error(message);
+    }
+    
+    const entity_id = await getLastRecordOfType("https://uri.fiware.org/ns/data-models%23Alert")
+    if(entity_id > 0){
+        default_index = entity_id
+    }
+
+    //Line 2 setup
+    const l2_client = await connectoToPLC(LINE_2_URL)
+    const TypeNoCur_subscription_L2 = await createSubscription(l2_client,TypeNoCur_plc_nodeid_L2)
+    const BlisterEntry_subscription_L2 = await createSubscription(l2_client,BlisterEntry_plc_nodeid_L2)
+
+    TypeNoCur_subscription_L2.on("changed",  async (dataValue_TypeNoCur: DataValue) => {
+        Logger.debug(`Monitoring TypeNoCur on line 2. Current value = ${dataValue_TypeNoCur.value.value.toString()}`)
+        if(trytypes.TypeA.indexOf(dataValue_TypeNoCur.value.value.toString()) != -1){
+            trayType = 'A'
+        }else if(trytypes.TypeB.indexOf(dataValue_TypeNoCur.value.value.toString()) == -1){
+            trayType = 'B'
+        }else if(trytypes.TypeC.indexOf(dataValue_TypeNoCur.value.value.toString()) == -1){
+            trayType = 'C'
+        }else{
+            Logger.warn(`L2 - try type not defined. Given ${dataValue_TypeNoCur.value.value.toString()}`)
+        }       
+    });
+    
+    BlisterEntry_subscription_L2.on("changed",  async (dataValue_BlisterEntry: DataValue) => {
+        Logger.debug(`Monitoring BlisterEntry on line 2. Current value = ${dataValue_BlisterEntry.value.value.toString()}`)
+        if(dataValue_BlisterEntry.value.value.toString() == "false"){
+            default_index=default_index+1;
+            notification_body.id=`${fiware_node_id}${default_index}`
+            notification_body.description.value=trayType
+            notification_body.alertSource.object='urn:ngsi-ld:Asset:BOS:LS2'
+            postRecord(notification_body)
+           }else{
+            Logger.debug("BlisterEntry at line L2 is not needed")
+        }         
+    });
+    //Line 5 setup
+    const l5_client = await connectoToPLC(LINE_5_URL)
+    const TypeNoCur_subscription_L5 = await createSubscription(l5_client,TypeNoCur_plc_nodeid_L5)
+    const BlisterEntry_subscription_L5 = await createSubscription(l5_client,BlisterEntry_plc_nodeid_L5)
+
+    TypeNoCur_subscription_L5.on("changed",  async (dataValue_TypeNoCur: DataValue) => {
+        Logger.debug(`Monitoring TypeNoCur on line 5. Current value = ${dataValue_TypeNoCur.value.value.toString()}`)
+        if(trytypes.TypeA.indexOf(dataValue_TypeNoCur.value.value.toString()) != -1){
+            trayType = 'A'
+        }else if(trytypes.TypeB.indexOf(dataValue_TypeNoCur.value.value.toString()) == -1){
+            trayType = 'B'
+        }else if(trytypes.TypeC.indexOf(dataValue_TypeNoCur.value.value.toString()) == -1){
+            trayType = 'C'
+        }else{
+            Logger.warn(`L5 - try type not defined. Given ${dataValue_TypeNoCur.value.value.toString()}`)
+        }       
+    });
+    
+    BlisterEntry_subscription_L5.on("changed",  async (dataValue_BlisterEntry: DataValue) => {
+        Logger.debug(`Monitoring BlisterEntry on line 5. Current value = ${dataValue_BlisterEntry.value.value.toString()}`)
+        if(dataValue_BlisterEntry.value.value.toString() == "false"){
+            default_index=default_index+1;
+            notification_body.id=`${fiware_node_id}${default_index}`
+            notification_body.description.value=trayType
+            notification_body.alertSource.object='urn:ngsi-ld:Asset:BOS:LS5'
+            postRecord(notification_body)
+           }else{
+            Logger.debug("BlisterEntry at line L5 is not needed")
+        }         
+    });
+
+}
+
+async function connectoToPLC(url:any){
+    Logger.debug(`Connecting to PLC ${url}...`)
+    const client = OPCUAClient.create(serverConnectionConfiguration);
+    try {
+        await  client.connect(url)
+        return client
+    } catch (error) {
+        Logger.failure(`Cant connect to PLC ${url} --- ${JSON.stringify(error)}`)
+    }
+}
+
+async function getLastRecordOfType(record_type:any){
+    Logger.debug(`finding record of type ${record_type}`)
+    try {
+        var result = await axios.get(`${fiware_url}/ngsi-ld/v1/entities?type=${record_type}`).then((response:any)=>response.data)
+    if(result.length != 0 ){
+        let idStartNumber = result.map((o:any)=>o.id.split('-')
+            .slice(-1)[0])
+            .map((l:string)=>parseInt(l)).sort( (a: number,b: number) =>a - b )
+            .slice(-1)[0]
+
+    Logger.debug(`last notification id was  ${idStartNumber}`)
+      return parseInt(idStartNumber)
+    }else{
+        Logger.debug(`there is no entity matching with ${record_type}`)
+        return 0
+    } 
+    } catch (error) {
+        Logger.failure(`EXCEPTION GIVEN - cant get getLastRecordOfType  ${record_type } - ${JSON.stringify(error)}`)
+        return 0
+    }
+}
+
+async function createSubscription(client:any,node_id:any) {
+    Logger.debug(`creating subscription for ${node_id}...`);
+    const session = await client.createSession();
+    const subscription = await  session.createSubscription2({
+        requestedPublishingInterval: 1000,
+        requestedLifetimeCount: 100,
+        requestedMaxKeepAliveCount: 20,
+        maxNotificationsPerPublish: 10,
+        publishingEnabled: true,
+        priority: 10
+    });
+
+    subscription
+        .on("started", () => console.log("subscription started - subscriptionId=", subscription.subscriptionId))
+        .on("keepalive", () => Logger.debug(`keep alive ${node_id}`))
+        .on("terminated", () => console.log("subscription terminated"));
+    const itemToMonitor={
+        nodeId:node_id,
+        attributeId: AttributeIds.Value
+    }
+    const monitoredItem = await subscription.monitor(
+        itemToMonitor,
+        requestedParameter,
+        TimestampsToReturn.Both);
+return monitoredItem
+}
+
+async function readVariable(client:any,node:any){
+    const session = await client.createSession();
+    const maxAge = 0;
+    const nodeToRead = {
+      nodeId: node,
+    };
+    const dataValue =  await session.read(nodeToRead, maxAge);
+    console.log(" value " , dataValue.toString());
+}
+
+async function browse(client:any){
+   
+    const session = await client.createSession();
+    const browseResult = await session.browse("RootFolder");
+    // const browsePath = makeBrowsePath("RootFolder", "/Objects/Server.ServerStatus.BuildInfo");
+    // const result = await session.translateBrowsePath(browsePath);
+    console.log(JSON.stringify(browseResult));
+    
+    // const productNameNodeId = result.targets[0].targetId;
+    // console.log(" Product Name nodeId = ", productNameNodeId.toString());
+}
+
+function postRecord(body:any){
+    const headers={
+        'Content-Type': 'application/ld+json',
+        }
+    Logger.debug(`body id = ${body.id}`)
+    axios.post(`${fiware_url}/ngsi-ld/v1/entities`,body,{headers:headers}).then((response:any)=>{
+        Logger.debug(JSON.stringify({response:response.status,statusText:response.statusText}))
+    },(error:any)=>{
+        Logger.failure(JSON.stringify(error))
+    }).catch((r:any)=>{
+        Logger.failure(JSON.stringify(r))
+    })
+
+}
+init()
-- 
GitLab