From 7b08fd594d0ba9e4180833a2a4655a9f65ca02dd Mon Sep 17 00:00:00 2001
From: Marin Karamihalev <marin.karamihalev@iopsys.eu>
Date: Fri, 24 Mar 2023 14:42:28 +0100
Subject: [PATCH] fixed reconnection issues, removed reconnect counter

---
 package.json                |   2 +-
 src/configurations/build.ts |  38 +-
 src/specs/usp-msg-1-2.js    | 685 +++++++++++++++++++++++++++++++++++-
 src/specs/usp-record-1-1.js |  44 ++-
 src/types.ts                |  12 +-
 5 files changed, 755 insertions(+), 26 deletions(-)

diff --git a/package.json b/package.json
index 65c3fd3..611d4fc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "usp-js",
-  "version": "0.3.7",
+  "version": "0.3.8",
   "description": "Helper library for easy usp communication using mqtt over tcp or ws.",
   "main": "node/index.js",
   "browser": "web/index.js",
diff --git a/src/configurations/build.ts b/src/configurations/build.ts
index 5605265..d075aa8 100644
--- a/src/configurations/build.ts
+++ b/src/configurations/build.ts
@@ -14,8 +14,15 @@ import {
   Proto,
   BuildConnectionFn,
   USPVersion,
+  ConnectionOptions,
+  MqttOptions,
 } from "../types";
-import { knownUSPVersions, makeCallbackRouter, makeRouter, parseCallbackOptions } from "../util";
+import {
+  knownUSPVersions,
+  makeCallbackRouter,
+  makeRouter,
+  parseCallbackOptions,
+} from "../util";
 
 const defaultPublishEndpoint = "/usp/endpoint";
 const defaultSubscribeEndpoint = "/usp/controller";
@@ -104,6 +111,13 @@ const addOptions = (usp: Partial<USP>, opts: Options): USP => {
   return mainUSP;
 };
 
+const correctOptions = (
+  options: ConnectionOptions
+): ConnectionOptions & MqttOptions => ({
+  ...options,
+  reconnectPeriod: options.closeOnDisconnect ? 0 : 1000,
+});
+
 const buildConnect: BuildConnectionFn =
   ({ connectClient, decodeID, loadProtobuf }) =>
   async (options, events) => {
@@ -113,8 +127,9 @@ const buildConnect: BuildConnectionFn =
     const idEndpoint = options.idEndpoint || defaultIdEndpoint;
 
     const connectTimeout = options.connectTimeout || defaultConnectionTimeout;
+    const correctedOptions = correctOptions(options);
     const client = await timeoutWrapper(
-      () => connectClient(options),
+      () => connectClient(correctedOptions),
       connectTimeout
     );
 
@@ -187,36 +202,25 @@ const buildConnect: BuildConnectionFn =
         }
 
         const cbs = callbackRouter.get(id);
-        const callbackOptions = parseCallbackOptions(parsedMsg)
+        const callbackOptions = parseCallbackOptions(parsedMsg);
         cbs.forEach((cb) => {
-          if (callbackOptions) cb(message || err || "", parsedMsg, callbackOptions)
-          else cb(message || err || "", parsedMsg)
+          if (callbackOptions)
+            cb(message || err || "", parsedMsg, callbackOptions);
+          else cb(message || err || "", parsedMsg);
         });
       }
     });
 
-    let reconnectCount = 0;
-    const isTrackingReconnects =
-      typeof options.reconnectsBeforeClosing === "number";
-
     client.on("error", (err) => {
       callbackRouter.get("error").forEach((cb) => cb(err));
       handleError(JSON.stringify(err, null, 2));
     });
-
     client.on("offline", handleOffline);
     client.on("reconnect", () => {
       handleReconnect();
-      if (isTrackingReconnects) reconnectCount++;
     });
     client.on("close", () => {
       handleClose();
-      if (options.closeOnDisconnect === true) client.end();
-      if (
-        isTrackingReconnects &&
-        reconnectCount >= (options.reconnectsBeforeClosing as number)
-      )
-        client.end();
     });
 
     const on: OnFn = (ident, callback) => {
diff --git a/src/specs/usp-msg-1-2.js b/src/specs/usp-msg-1-2.js
index d04a8ca..f289565 100644
--- a/src/specs/usp-msg-1-2.js
+++ b/src/specs/usp-msg-1-2.js
@@ -1 +1,684 @@
-export default{nested:{usp:{nested:{Msg:{fields:{header:{type:"Header",id:1},body:{type:"Body",id:2}}},Header:{fields:{msgId:{type:"string",id:1},msgType:{type:"MsgType",id:2}},nested:{MsgType:{values:{ERROR:0,GET:1,GET_RESP:2,NOTIFY:3,SET:4,SET_RESP:5,OPERATE:6,OPERATE_RESP:7,ADD:8,ADD_RESP:9,DELETE:10,DELETE_RESP:11,GET_SUPPORTED_DM:12,GET_SUPPORTED_DM_RESP:13,GET_INSTANCES:14,GET_INSTANCES_RESP:15,NOTIFY_RESP:16,GET_SUPPORTED_PROTO:17,GET_SUPPORTED_PROTO_RESP:18}}}},Body:{oneofs:{msgBody:{oneof:["request","response","error"]}},fields:{request:{type:"Request",id:1},response:{type:"Response",id:2},error:{type:"Error",id:3}}},Request:{oneofs:{reqType:{oneof:["get","getSupportedDm","getInstances","set","add","delete","operate","notify","getSupportedProtocol"]}},fields:{get:{type:"Get",id:1},getSupportedDm:{type:"GetSupportedDM",id:2},getInstances:{type:"GetInstances",id:3},set:{type:"Set",id:4},add:{type:"Add",id:5},delete:{type:"Delete",id:6},operate:{type:"Operate",id:7},notify:{type:"Notify",id:8},getSupportedProtocol:{type:"GetSupportedProtocol",id:9}}},Response:{oneofs:{respType:{oneof:["getResp","getSupportedDmResp","getInstancesResp","setResp","addResp","deleteResp","operateResp","notifyResp","getSupportedProtocolResp"]}},fields:{getResp:{type:"GetResp",id:1},getSupportedDmResp:{type:"GetSupportedDMResp",id:2},getInstancesResp:{type:"GetInstancesResp",id:3},setResp:{type:"SetResp",id:4},addResp:{type:"AddResp",id:5},deleteResp:{type:"DeleteResp",id:6},operateResp:{type:"OperateResp",id:7},notifyResp:{type:"NotifyResp",id:8},getSupportedProtocolResp:{type:"GetSupportedProtocolResp",id:9}}},Error:{fields:{errCode:{type:"fixed32",id:1},errMsg:{type:"string",id:2},paramErrs:{rule:"repeated",type:"ParamError",id:3}},nested:{ParamError:{fields:{paramPath:{type:"string",id:1},errCode:{type:"fixed32",id:2},errMsg:{type:"string",id:3}}}}},Get:{fields:{paramPaths:{rule:"repeated",type:"string",id:1},maxDepth:{type:"fixed32",id:2}}},GetResp:{fields:{reqPathResults:{rule:"repeated",type:"RequestedPathResult",id:1}},nested:{RequestedPathResult:{fields:{requestedPath:{type:"string",id:1},errCode:{type:"fixed32",id:2},errMsg:{type:"string",id:3},resolvedPathResults:{rule:"repeated",type:"ResolvedPathResult",id:4}}},ResolvedPathResult:{fields:{resolvedPath:{type:"string",id:1},resultParams:{keyType:"string",type:"string",id:2}}}}},GetSupportedDM:{fields:{objPaths:{rule:"repeated",type:"string",id:1},firstLevelOnly:{type:"bool",id:2},returnCommands:{type:"bool",id:3},returnEvents:{type:"bool",id:4},returnParams:{type:"bool",id:5}}},GetSupportedDMResp:{fields:{reqObjResults:{rule:"repeated",type:"RequestedObjectResult",id:1}},nested:{RequestedObjectResult:{fields:{reqObjPath:{type:"string",id:1},errCode:{type:"fixed32",id:2},errMsg:{type:"string",id:3},dataModelInstUri:{type:"string",id:4},supportedObjs:{rule:"repeated",type:"SupportedObjectResult",id:5}}},SupportedObjectResult:{fields:{supportedObjPath:{type:"string",id:1},access:{type:"ObjAccessType",id:2},isMultiInstance:{type:"bool",id:3},supportedCommands:{rule:"repeated",type:"SupportedCommandResult",id:4},supportedEvents:{rule:"repeated",type:"SupportedEventResult",id:5},supportedParams:{rule:"repeated",type:"SupportedParamResult",id:6},divergentPaths:{rule:"repeated",type:"string",id:7}}},SupportedParamResult:{fields:{paramName:{type:"string",id:1},access:{type:"ParamAccessType",id:2},valueType:{type:"ParamValueType",id:3},valueChange:{type:"ValueChangeType",id:4}}},SupportedCommandResult:{fields:{commandName:{type:"string",id:1},inputArgNames:{rule:"repeated",type:"string",id:2},outputArgNames:{rule:"repeated",type:"string",id:3},commandType:{type:"CmdType",id:4}}},SupportedEventResult:{fields:{eventName:{type:"string",id:1},argNames:{rule:"repeated",type:"string",id:2}}},ParamAccessType:{values:{PARAM_READ_ONLY:0,PARAM_READ_WRITE:1,PARAM_WRITE_ONLY:2}},ObjAccessType:{values:{OBJ_READ_ONLY:0,OBJ_ADD_DELETE:1,OBJ_ADD_ONLY:2,OBJ_DELETE_ONLY:3}},ParamValueType:{values:{PARAM_UNKNOWN:0,PARAM_BASE_64:1,PARAM_BOOLEAN:2,PARAM_DATE_TIME:3,PARAM_DECIMAL:4,PARAM_HEX_BINARY:5,PARAM_INT:6,PARAM_LONG:7,PARAM_STRING:8,PARAM_UNSIGNED_INT:9,PARAM_UNSIGNED_LONG:10}},ValueChangeType:{values:{VALUE_CHANGE_UNKNOWN:0,VALUE_CHANGE_ALLOWED:1,VALUE_CHANGE_WILL_IGNORE:2}},CmdType:{values:{CMD_UNKNOWN:0,CMD_SYNC:1,CMD_ASYNC:2}}}},GetInstances:{fields:{objPaths:{rule:"repeated",type:"string",id:1},firstLevelOnly:{type:"bool",id:2}}},GetInstancesResp:{fields:{reqPathResults:{rule:"repeated",type:"RequestedPathResult",id:1}},nested:{RequestedPathResult:{fields:{requestedPath:{type:"string",id:1},errCode:{type:"fixed32",id:2},errMsg:{type:"string",id:3},currInsts:{rule:"repeated",type:"CurrInstance",id:4}}},CurrInstance:{fields:{instantiatedObjPath:{type:"string",id:1},uniqueKeys:{keyType:"string",type:"string",id:2}}}}},GetSupportedProtocol:{fields:{controllerSupportedProtocolVersions:{type:"string",id:1}}},GetSupportedProtocolResp:{fields:{agentSupportedProtocolVersions:{type:"string",id:1}}},Add:{fields:{allowPartial:{type:"bool",id:1},createObjs:{rule:"repeated",type:"CreateObject",id:2}},nested:{CreateObject:{fields:{objPath:{type:"string",id:1},paramSettings:{rule:"repeated",type:"CreateParamSetting",id:2}}},CreateParamSetting:{fields:{param:{type:"string",id:1},value:{type:"string",id:2},required:{type:"bool",id:3}}}}},AddResp:{fields:{createdObjResults:{rule:"repeated",type:"CreatedObjectResult",id:1}},nested:{CreatedObjectResult:{fields:{requestedPath:{type:"string",id:1},operStatus:{type:"OperationStatus",id:2}},nested:{OperationStatus:{oneofs:{operStatus:{oneof:["operFailure","operSuccess"]}},fields:{operFailure:{type:"OperationFailure",id:1},operSuccess:{type:"OperationSuccess",id:2}},nested:{OperationFailure:{fields:{errCode:{type:"fixed32",id:1},errMsg:{type:"string",id:2}}},OperationSuccess:{fields:{instantiatedPath:{type:"string",id:1},paramErrs:{rule:"repeated",type:"ParameterError",id:2},uniqueKeys:{keyType:"string",type:"string",id:3}}}}}}},ParameterError:{fields:{param:{type:"string",id:1},errCode:{type:"fixed32",id:2},errMsg:{type:"string",id:3}}}}},Delete:{fields:{allowPartial:{type:"bool",id:1},objPaths:{rule:"repeated",type:"string",id:2}}},DeleteResp:{fields:{deletedObjResults:{rule:"repeated",type:"DeletedObjectResult",id:1}},nested:{DeletedObjectResult:{fields:{requestedPath:{type:"string",id:1},operStatus:{type:"OperationStatus",id:2}},nested:{OperationStatus:{oneofs:{operStatus:{oneof:["operFailure","operSuccess"]}},fields:{operFailure:{type:"OperationFailure",id:1},operSuccess:{type:"OperationSuccess",id:2}},nested:{OperationFailure:{fields:{errCode:{type:"fixed32",id:1},errMsg:{type:"string",id:2}}},OperationSuccess:{fields:{affectedPaths:{rule:"repeated",type:"string",id:1},unaffectedPathErrs:{rule:"repeated",type:"UnaffectedPathError",id:2}}}}}}},UnaffectedPathError:{fields:{unaffectedPath:{type:"string",id:1},errCode:{type:"fixed32",id:2},errMsg:{type:"string",id:3}}}}},Set:{fields:{allowPartial:{type:"bool",id:1},updateObjs:{rule:"repeated",type:"UpdateObject",id:2}},nested:{UpdateObject:{fields:{objPath:{type:"string",id:1},paramSettings:{rule:"repeated",type:"UpdateParamSetting",id:2}}},UpdateParamSetting:{fields:{param:{type:"string",id:1},value:{type:"string",id:2},required:{type:"bool",id:3}}}}},SetResp:{fields:{updatedObjResults:{rule:"repeated",type:"UpdatedObjectResult",id:1}},nested:{UpdatedObjectResult:{fields:{requestedPath:{type:"string",id:1},operStatus:{type:"OperationStatus",id:2}},nested:{OperationStatus:{oneofs:{operStatus:{oneof:["operFailure","operSuccess"]}},fields:{operFailure:{type:"OperationFailure",id:1},operSuccess:{type:"OperationSuccess",id:2}},nested:{OperationFailure:{fields:{errCode:{type:"fixed32",id:1},errMsg:{type:"string",id:2},updatedInstFailures:{rule:"repeated",type:"UpdatedInstanceFailure",id:3}}},OperationSuccess:{fields:{updatedInstResults:{rule:"repeated",type:"UpdatedInstanceResult",id:1}}}}}}},UpdatedInstanceFailure:{fields:{affectedPath:{type:"string",id:1},paramErrs:{rule:"repeated",type:"ParameterError",id:2}}},UpdatedInstanceResult:{fields:{affectedPath:{type:"string",id:1},paramErrs:{rule:"repeated",type:"ParameterError",id:2},updatedParams:{keyType:"string",type:"string",id:3}}},ParameterError:{fields:{param:{type:"string",id:1},errCode:{type:"fixed32",id:2},errMsg:{type:"string",id:3}}}}},Operate:{fields:{command:{type:"string",id:1},commandKey:{type:"string",id:2},sendResp:{type:"bool",id:3},inputArgs:{keyType:"string",type:"string",id:4}}},OperateResp:{fields:{operationResults:{rule:"repeated",type:"OperationResult",id:1}},nested:{OperationResult:{oneofs:{operationResp:{oneof:["reqObjPath","reqOutputArgs","cmdFailure"]}},fields:{executedCommand:{type:"string",id:1},reqObjPath:{type:"string",id:2},reqOutputArgs:{type:"OutputArgs",id:3},cmdFailure:{type:"CommandFailure",id:4}},nested:{OutputArgs:{fields:{outputArgs:{keyType:"string",type:"string",id:1}}},CommandFailure:{fields:{errCode:{type:"fixed32",id:1},errMsg:{type:"string",id:2}}}}}}},Notify:{oneofs:{notification:{oneof:["event","valueChange","objCreation","objDeletion","operComplete","onBoardReq"]}},fields:{subscriptionId:{type:"string",id:1},sendResp:{type:"bool",id:2},event:{type:"Event",id:3},valueChange:{type:"ValueChange",id:4},objCreation:{type:"ObjectCreation",id:5},objDeletion:{type:"ObjectDeletion",id:6},operComplete:{type:"OperationComplete",id:7},onBoardReq:{type:"OnBoardRequest",id:8}},nested:{Event:{fields:{objPath:{type:"string",id:1},eventName:{type:"string",id:2},params:{keyType:"string",type:"string",id:3}}},ValueChange:{fields:{paramPath:{type:"string",id:1},paramValue:{type:"string",id:2}}},ObjectCreation:{fields:{objPath:{type:"string",id:1},uniqueKeys:{keyType:"string",type:"string",id:2}}},ObjectDeletion:{fields:{objPath:{type:"string",id:1}}},OperationComplete:{oneofs:{operationResp:{oneof:["reqOutputArgs","cmdFailure"]}},fields:{objPath:{type:"string",id:1},commandName:{type:"string",id:2},commandKey:{type:"string",id:3},reqOutputArgs:{type:"OutputArgs",id:4},cmdFailure:{type:"CommandFailure",id:5}},nested:{OutputArgs:{fields:{outputArgs:{keyType:"string",type:"string",id:1}}},CommandFailure:{fields:{errCode:{type:"fixed32",id:1},errMsg:{type:"string",id:2}}}}},OnBoardRequest:{fields:{oui:{type:"string",id:1},productClass:{type:"string",id:2},serialNumber:{type:"string",id:3},agentSupportedProtocolVersions:{type:"string",id:4}}}}},NotifyResp:{fields:{subscriptionId:{type:"string",id:1}}}}}}};
\ No newline at end of file
+export default {
+  nested: {
+    usp: {
+      nested: {
+        Msg: {
+          fields: {
+            header: { type: "Header", id: 1 },
+            body: { type: "Body", id: 2 },
+          },
+        },
+        Header: {
+          fields: {
+            msgId: { type: "string", id: 1 },
+            msgType: { type: "MsgType", id: 2 },
+          },
+          nested: {
+            MsgType: {
+              values: {
+                ERROR: 0,
+                GET: 1,
+                GET_RESP: 2,
+                NOTIFY: 3,
+                SET: 4,
+                SET_RESP: 5,
+                OPERATE: 6,
+                OPERATE_RESP: 7,
+                ADD: 8,
+                ADD_RESP: 9,
+                DELETE: 10,
+                DELETE_RESP: 11,
+                GET_SUPPORTED_DM: 12,
+                GET_SUPPORTED_DM_RESP: 13,
+                GET_INSTANCES: 14,
+                GET_INSTANCES_RESP: 15,
+                NOTIFY_RESP: 16,
+                GET_SUPPORTED_PROTO: 17,
+                GET_SUPPORTED_PROTO_RESP: 18,
+              },
+            },
+          },
+        },
+        Body: {
+          oneofs: { msgBody: { oneof: ["request", "response", "error"] } },
+          fields: {
+            request: { type: "Request", id: 1 },
+            response: { type: "Response", id: 2 },
+            error: { type: "Error", id: 3 },
+          },
+        },
+        Request: {
+          oneofs: {
+            reqType: {
+              oneof: [
+                "get",
+                "getSupportedDm",
+                "getInstances",
+                "set",
+                "add",
+                "delete",
+                "operate",
+                "notify",
+                "getSupportedProtocol",
+              ],
+            },
+          },
+          fields: {
+            get: { type: "Get", id: 1 },
+            getSupportedDm: { type: "GetSupportedDM", id: 2 },
+            getInstances: { type: "GetInstances", id: 3 },
+            set: { type: "Set", id: 4 },
+            add: { type: "Add", id: 5 },
+            delete: { type: "Delete", id: 6 },
+            operate: { type: "Operate", id: 7 },
+            notify: { type: "Notify", id: 8 },
+            getSupportedProtocol: { type: "GetSupportedProtocol", id: 9 },
+          },
+        },
+        Response: {
+          oneofs: {
+            respType: {
+              oneof: [
+                "getResp",
+                "getSupportedDmResp",
+                "getInstancesResp",
+                "setResp",
+                "addResp",
+                "deleteResp",
+                "operateResp",
+                "notifyResp",
+                "getSupportedProtocolResp",
+              ],
+            },
+          },
+          fields: {
+            getResp: { type: "GetResp", id: 1 },
+            getSupportedDmResp: { type: "GetSupportedDMResp", id: 2 },
+            getInstancesResp: { type: "GetInstancesResp", id: 3 },
+            setResp: { type: "SetResp", id: 4 },
+            addResp: { type: "AddResp", id: 5 },
+            deleteResp: { type: "DeleteResp", id: 6 },
+            operateResp: { type: "OperateResp", id: 7 },
+            notifyResp: { type: "NotifyResp", id: 8 },
+            getSupportedProtocolResp: {
+              type: "GetSupportedProtocolResp",
+              id: 9,
+            },
+          },
+        },
+        Error: {
+          fields: {
+            errCode: { type: "fixed32", id: 1 },
+            errMsg: { type: "string", id: 2 },
+            paramErrs: { rule: "repeated", type: "ParamError", id: 3 },
+          },
+          nested: {
+            ParamError: {
+              fields: {
+                paramPath: { type: "string", id: 1 },
+                errCode: { type: "fixed32", id: 2 },
+                errMsg: { type: "string", id: 3 },
+              },
+            },
+          },
+        },
+        Get: {
+          fields: {
+            paramPaths: { rule: "repeated", type: "string", id: 1 },
+            maxDepth: { type: "fixed32", id: 2 },
+          },
+        },
+        GetResp: {
+          fields: {
+            reqPathResults: {
+              rule: "repeated",
+              type: "RequestedPathResult",
+              id: 1,
+            },
+          },
+          nested: {
+            RequestedPathResult: {
+              fields: {
+                requestedPath: { type: "string", id: 1 },
+                errCode: { type: "fixed32", id: 2 },
+                errMsg: { type: "string", id: 3 },
+                resolvedPathResults: {
+                  rule: "repeated",
+                  type: "ResolvedPathResult",
+                  id: 4,
+                },
+              },
+            },
+            ResolvedPathResult: {
+              fields: {
+                resolvedPath: { type: "string", id: 1 },
+                resultParams: { keyType: "string", type: "string", id: 2 },
+              },
+            },
+          },
+        },
+        GetSupportedDM: {
+          fields: {
+            objPaths: { rule: "repeated", type: "string", id: 1 },
+            firstLevelOnly: { type: "bool", id: 2 },
+            returnCommands: { type: "bool", id: 3 },
+            returnEvents: { type: "bool", id: 4 },
+            returnParams: { type: "bool", id: 5 },
+          },
+        },
+        GetSupportedDMResp: {
+          fields: {
+            reqObjResults: {
+              rule: "repeated",
+              type: "RequestedObjectResult",
+              id: 1,
+            },
+          },
+          nested: {
+            RequestedObjectResult: {
+              fields: {
+                reqObjPath: { type: "string", id: 1 },
+                errCode: { type: "fixed32", id: 2 },
+                errMsg: { type: "string", id: 3 },
+                dataModelInstUri: { type: "string", id: 4 },
+                supportedObjs: {
+                  rule: "repeated",
+                  type: "SupportedObjectResult",
+                  id: 5,
+                },
+              },
+            },
+            SupportedObjectResult: {
+              fields: {
+                supportedObjPath: { type: "string", id: 1 },
+                access: { type: "ObjAccessType", id: 2 },
+                isMultiInstance: { type: "bool", id: 3 },
+                supportedCommands: {
+                  rule: "repeated",
+                  type: "SupportedCommandResult",
+                  id: 4,
+                },
+                supportedEvents: {
+                  rule: "repeated",
+                  type: "SupportedEventResult",
+                  id: 5,
+                },
+                supportedParams: {
+                  rule: "repeated",
+                  type: "SupportedParamResult",
+                  id: 6,
+                },
+                divergentPaths: { rule: "repeated", type: "string", id: 7 },
+              },
+            },
+            SupportedParamResult: {
+              fields: {
+                paramName: { type: "string", id: 1 },
+                access: { type: "ParamAccessType", id: 2 },
+                valueType: { type: "ParamValueType", id: 3 },
+                valueChange: { type: "ValueChangeType", id: 4 },
+              },
+            },
+            SupportedCommandResult: {
+              fields: {
+                commandName: { type: "string", id: 1 },
+                inputArgNames: { rule: "repeated", type: "string", id: 2 },
+                outputArgNames: { rule: "repeated", type: "string", id: 3 },
+                commandType: { type: "CmdType", id: 4 },
+              },
+            },
+            SupportedEventResult: {
+              fields: {
+                eventName: { type: "string", id: 1 },
+                argNames: { rule: "repeated", type: "string", id: 2 },
+              },
+            },
+            ParamAccessType: {
+              values: {
+                PARAM_READ_ONLY: 0,
+                PARAM_READ_WRITE: 1,
+                PARAM_WRITE_ONLY: 2,
+              },
+            },
+            ObjAccessType: {
+              values: {
+                OBJ_READ_ONLY: 0,
+                OBJ_ADD_DELETE: 1,
+                OBJ_ADD_ONLY: 2,
+                OBJ_DELETE_ONLY: 3,
+              },
+            },
+            ParamValueType: {
+              values: {
+                PARAM_UNKNOWN: 0,
+                PARAM_BASE_64: 1,
+                PARAM_BOOLEAN: 2,
+                PARAM_DATE_TIME: 3,
+                PARAM_DECIMAL: 4,
+                PARAM_HEX_BINARY: 5,
+                PARAM_INT: 6,
+                PARAM_LONG: 7,
+                PARAM_STRING: 8,
+                PARAM_UNSIGNED_INT: 9,
+                PARAM_UNSIGNED_LONG: 10,
+              },
+            },
+            ValueChangeType: {
+              values: {
+                VALUE_CHANGE_UNKNOWN: 0,
+                VALUE_CHANGE_ALLOWED: 1,
+                VALUE_CHANGE_WILL_IGNORE: 2,
+              },
+            },
+            CmdType: { values: { CMD_UNKNOWN: 0, CMD_SYNC: 1, CMD_ASYNC: 2 } },
+          },
+        },
+        GetInstances: {
+          fields: {
+            objPaths: { rule: "repeated", type: "string", id: 1 },
+            firstLevelOnly: { type: "bool", id: 2 },
+          },
+        },
+        GetInstancesResp: {
+          fields: {
+            reqPathResults: {
+              rule: "repeated",
+              type: "RequestedPathResult",
+              id: 1,
+            },
+          },
+          nested: {
+            RequestedPathResult: {
+              fields: {
+                requestedPath: { type: "string", id: 1 },
+                errCode: { type: "fixed32", id: 2 },
+                errMsg: { type: "string", id: 3 },
+                currInsts: { rule: "repeated", type: "CurrInstance", id: 4 },
+              },
+            },
+            CurrInstance: {
+              fields: {
+                instantiatedObjPath: { type: "string", id: 1 },
+                uniqueKeys: { keyType: "string", type: "string", id: 2 },
+              },
+            },
+          },
+        },
+        GetSupportedProtocol: {
+          fields: {
+            controllerSupportedProtocolVersions: { type: "string", id: 1 },
+          },
+        },
+        GetSupportedProtocolResp: {
+          fields: { agentSupportedProtocolVersions: { type: "string", id: 1 } },
+        },
+        Add: {
+          fields: {
+            allowPartial: { type: "bool", id: 1 },
+            createObjs: { rule: "repeated", type: "CreateObject", id: 2 },
+          },
+          nested: {
+            CreateObject: {
+              fields: {
+                objPath: { type: "string", id: 1 },
+                paramSettings: {
+                  rule: "repeated",
+                  type: "CreateParamSetting",
+                  id: 2,
+                },
+              },
+            },
+            CreateParamSetting: {
+              fields: {
+                param: { type: "string", id: 1 },
+                value: { type: "string", id: 2 },
+                required: { type: "bool", id: 3 },
+              },
+            },
+          },
+        },
+        AddResp: {
+          fields: {
+            createdObjResults: {
+              rule: "repeated",
+              type: "CreatedObjectResult",
+              id: 1,
+            },
+          },
+          nested: {
+            CreatedObjectResult: {
+              fields: {
+                requestedPath: { type: "string", id: 1 },
+                operStatus: { type: "OperationStatus", id: 2 },
+              },
+              nested: {
+                OperationStatus: {
+                  oneofs: {
+                    operStatus: { oneof: ["operFailure", "operSuccess"] },
+                  },
+                  fields: {
+                    operFailure: { type: "OperationFailure", id: 1 },
+                    operSuccess: { type: "OperationSuccess", id: 2 },
+                  },
+                  nested: {
+                    OperationFailure: {
+                      fields: {
+                        errCode: { type: "fixed32", id: 1 },
+                        errMsg: { type: "string", id: 2 },
+                      },
+                    },
+                    OperationSuccess: {
+                      fields: {
+                        instantiatedPath: { type: "string", id: 1 },
+                        paramErrs: {
+                          rule: "repeated",
+                          type: "ParameterError",
+                          id: 2,
+                        },
+                        uniqueKeys: {
+                          keyType: "string",
+                          type: "string",
+                          id: 3,
+                        },
+                      },
+                    },
+                  },
+                },
+              },
+            },
+            ParameterError: {
+              fields: {
+                param: { type: "string", id: 1 },
+                errCode: { type: "fixed32", id: 2 },
+                errMsg: { type: "string", id: 3 },
+              },
+            },
+          },
+        },
+        Delete: {
+          fields: {
+            allowPartial: { type: "bool", id: 1 },
+            objPaths: { rule: "repeated", type: "string", id: 2 },
+          },
+        },
+        DeleteResp: {
+          fields: {
+            deletedObjResults: {
+              rule: "repeated",
+              type: "DeletedObjectResult",
+              id: 1,
+            },
+          },
+          nested: {
+            DeletedObjectResult: {
+              fields: {
+                requestedPath: { type: "string", id: 1 },
+                operStatus: { type: "OperationStatus", id: 2 },
+              },
+              nested: {
+                OperationStatus: {
+                  oneofs: {
+                    operStatus: { oneof: ["operFailure", "operSuccess"] },
+                  },
+                  fields: {
+                    operFailure: { type: "OperationFailure", id: 1 },
+                    operSuccess: { type: "OperationSuccess", id: 2 },
+                  },
+                  nested: {
+                    OperationFailure: {
+                      fields: {
+                        errCode: { type: "fixed32", id: 1 },
+                        errMsg: { type: "string", id: 2 },
+                      },
+                    },
+                    OperationSuccess: {
+                      fields: {
+                        affectedPaths: {
+                          rule: "repeated",
+                          type: "string",
+                          id: 1,
+                        },
+                        unaffectedPathErrs: {
+                          rule: "repeated",
+                          type: "UnaffectedPathError",
+                          id: 2,
+                        },
+                      },
+                    },
+                  },
+                },
+              },
+            },
+            UnaffectedPathError: {
+              fields: {
+                unaffectedPath: { type: "string", id: 1 },
+                errCode: { type: "fixed32", id: 2 },
+                errMsg: { type: "string", id: 3 },
+              },
+            },
+          },
+        },
+        Set: {
+          fields: {
+            allowPartial: { type: "bool", id: 1 },
+            updateObjs: { rule: "repeated", type: "UpdateObject", id: 2 },
+          },
+          nested: {
+            UpdateObject: {
+              fields: {
+                objPath: { type: "string", id: 1 },
+                paramSettings: {
+                  rule: "repeated",
+                  type: "UpdateParamSetting",
+                  id: 2,
+                },
+              },
+            },
+            UpdateParamSetting: {
+              fields: {
+                param: { type: "string", id: 1 },
+                value: { type: "string", id: 2 },
+                required: { type: "bool", id: 3 },
+              },
+            },
+          },
+        },
+        SetResp: {
+          fields: {
+            updatedObjResults: {
+              rule: "repeated",
+              type: "UpdatedObjectResult",
+              id: 1,
+            },
+          },
+          nested: {
+            UpdatedObjectResult: {
+              fields: {
+                requestedPath: { type: "string", id: 1 },
+                operStatus: { type: "OperationStatus", id: 2 },
+              },
+              nested: {
+                OperationStatus: {
+                  oneofs: {
+                    operStatus: { oneof: ["operFailure", "operSuccess"] },
+                  },
+                  fields: {
+                    operFailure: { type: "OperationFailure", id: 1 },
+                    operSuccess: { type: "OperationSuccess", id: 2 },
+                  },
+                  nested: {
+                    OperationFailure: {
+                      fields: {
+                        errCode: { type: "fixed32", id: 1 },
+                        errMsg: { type: "string", id: 2 },
+                        updatedInstFailures: {
+                          rule: "repeated",
+                          type: "UpdatedInstanceFailure",
+                          id: 3,
+                        },
+                      },
+                    },
+                    OperationSuccess: {
+                      fields: {
+                        updatedInstResults: {
+                          rule: "repeated",
+                          type: "UpdatedInstanceResult",
+                          id: 1,
+                        },
+                      },
+                    },
+                  },
+                },
+              },
+            },
+            UpdatedInstanceFailure: {
+              fields: {
+                affectedPath: { type: "string", id: 1 },
+                paramErrs: { rule: "repeated", type: "ParameterError", id: 2 },
+              },
+            },
+            UpdatedInstanceResult: {
+              fields: {
+                affectedPath: { type: "string", id: 1 },
+                paramErrs: { rule: "repeated", type: "ParameterError", id: 2 },
+                updatedParams: { keyType: "string", type: "string", id: 3 },
+              },
+            },
+            ParameterError: {
+              fields: {
+                param: { type: "string", id: 1 },
+                errCode: { type: "fixed32", id: 2 },
+                errMsg: { type: "string", id: 3 },
+              },
+            },
+          },
+        },
+        Operate: {
+          fields: {
+            command: { type: "string", id: 1 },
+            commandKey: { type: "string", id: 2 },
+            sendResp: { type: "bool", id: 3 },
+            inputArgs: { keyType: "string", type: "string", id: 4 },
+          },
+        },
+        OperateResp: {
+          fields: {
+            operationResults: {
+              rule: "repeated",
+              type: "OperationResult",
+              id: 1,
+            },
+          },
+          nested: {
+            OperationResult: {
+              oneofs: {
+                operationResp: {
+                  oneof: ["reqObjPath", "reqOutputArgs", "cmdFailure"],
+                },
+              },
+              fields: {
+                executedCommand: { type: "string", id: 1 },
+                reqObjPath: { type: "string", id: 2 },
+                reqOutputArgs: { type: "OutputArgs", id: 3 },
+                cmdFailure: { type: "CommandFailure", id: 4 },
+              },
+              nested: {
+                OutputArgs: {
+                  fields: {
+                    outputArgs: { keyType: "string", type: "string", id: 1 },
+                  },
+                },
+                CommandFailure: {
+                  fields: {
+                    errCode: { type: "fixed32", id: 1 },
+                    errMsg: { type: "string", id: 2 },
+                  },
+                },
+              },
+            },
+          },
+        },
+        Notify: {
+          oneofs: {
+            notification: {
+              oneof: [
+                "event",
+                "valueChange",
+                "objCreation",
+                "objDeletion",
+                "operComplete",
+                "onBoardReq",
+              ],
+            },
+          },
+          fields: {
+            subscriptionId: { type: "string", id: 1 },
+            sendResp: { type: "bool", id: 2 },
+            event: { type: "Event", id: 3 },
+            valueChange: { type: "ValueChange", id: 4 },
+            objCreation: { type: "ObjectCreation", id: 5 },
+            objDeletion: { type: "ObjectDeletion", id: 6 },
+            operComplete: { type: "OperationComplete", id: 7 },
+            onBoardReq: { type: "OnBoardRequest", id: 8 },
+          },
+          nested: {
+            Event: {
+              fields: {
+                objPath: { type: "string", id: 1 },
+                eventName: { type: "string", id: 2 },
+                params: { keyType: "string", type: "string", id: 3 },
+              },
+            },
+            ValueChange: {
+              fields: {
+                paramPath: { type: "string", id: 1 },
+                paramValue: { type: "string", id: 2 },
+              },
+            },
+            ObjectCreation: {
+              fields: {
+                objPath: { type: "string", id: 1 },
+                uniqueKeys: { keyType: "string", type: "string", id: 2 },
+              },
+            },
+            ObjectDeletion: { fields: { objPath: { type: "string", id: 1 } } },
+            OperationComplete: {
+              oneofs: {
+                operationResp: { oneof: ["reqOutputArgs", "cmdFailure"] },
+              },
+              fields: {
+                objPath: { type: "string", id: 1 },
+                commandName: { type: "string", id: 2 },
+                commandKey: { type: "string", id: 3 },
+                reqOutputArgs: { type: "OutputArgs", id: 4 },
+                cmdFailure: { type: "CommandFailure", id: 5 },
+              },
+              nested: {
+                OutputArgs: {
+                  fields: {
+                    outputArgs: { keyType: "string", type: "string", id: 1 },
+                  },
+                },
+                CommandFailure: {
+                  fields: {
+                    errCode: { type: "fixed32", id: 1 },
+                    errMsg: { type: "string", id: 2 },
+                  },
+                },
+              },
+            },
+            OnBoardRequest: {
+              fields: {
+                oui: { type: "string", id: 1 },
+                productClass: { type: "string", id: 2 },
+                serialNumber: { type: "string", id: 3 },
+                agentSupportedProtocolVersions: { type: "string", id: 4 },
+              },
+            },
+          },
+        },
+        NotifyResp: { fields: { subscriptionId: { type: "string", id: 1 } } },
+      },
+    },
+  },
+};
diff --git a/src/specs/usp-record-1-1.js b/src/specs/usp-record-1-1.js
index dff964f..d511a4b 100644
--- a/src/specs/usp-record-1-1.js
+++ b/src/specs/usp-record-1-1.js
@@ -1 +1,43 @@
-export default{nested:{usp_record:{nested:{Record:{oneofs:{recordType:{oneof:["noSessionContext","sessionContext"]}},fields:{version:{type:"string",id:1},toId:{type:"string",id:2},fromId:{type:"string",id:3},payloadSecurity:{type:"PayloadSecurity",id:4},macSignature:{type:"bytes",id:5},senderCert:{type:"bytes",id:6},noSessionContext:{type:"NoSessionContextRecord",id:7},sessionContext:{type:"SessionContextRecord",id:8}},nested:{PayloadSecurity:{values:{PLAINTEXT:0,TLS12:1}}}},NoSessionContextRecord:{fields:{payload:{type:"bytes",id:2}}},SessionContextRecord:{fields:{sessionId:{type:"uint64",id:1},sequenceId:{type:"uint64",id:2},expectedId:{type:"uint64",id:3},retransmitId:{type:"uint64",id:4},payloadSarState:{type:"PayloadSARState",id:5},payloadrecSarState:{type:"PayloadSARState",id:6},payload:{rule:"repeated",type:"bytes",id:7}},nested:{PayloadSARState:{values:{NONE:0,BEGIN:1,INPROCESS:2,COMPLETE:3}}}}}}}};
\ No newline at end of file
+export default {
+  nested: {
+    usp_record: {
+      nested: {
+        Record: {
+          oneofs: {
+            recordType: { oneof: ["noSessionContext", "sessionContext"] },
+          },
+          fields: {
+            version: { type: "string", id: 1 },
+            toId: { type: "string", id: 2 },
+            fromId: { type: "string", id: 3 },
+            payloadSecurity: { type: "PayloadSecurity", id: 4 },
+            macSignature: { type: "bytes", id: 5 },
+            senderCert: { type: "bytes", id: 6 },
+            noSessionContext: { type: "NoSessionContextRecord", id: 7 },
+            sessionContext: { type: "SessionContextRecord", id: 8 },
+          },
+          nested: { PayloadSecurity: { values: { PLAINTEXT: 0, TLS12: 1 } } },
+        },
+        NoSessionContextRecord: {
+          fields: { payload: { type: "bytes", id: 2 } },
+        },
+        SessionContextRecord: {
+          fields: {
+            sessionId: { type: "uint64", id: 1 },
+            sequenceId: { type: "uint64", id: 2 },
+            expectedId: { type: "uint64", id: 3 },
+            retransmitId: { type: "uint64", id: 4 },
+            payloadSarState: { type: "PayloadSARState", id: 5 },
+            payloadrecSarState: { type: "PayloadSARState", id: 6 },
+            payload: { rule: "repeated", type: "bytes", id: 7 },
+          },
+          nested: {
+            PayloadSARState: {
+              values: { NONE: 0, BEGIN: 1, INPROCESS: 2, COMPLETE: 3 },
+            },
+          },
+        },
+      },
+    },
+  },
+};
diff --git a/src/types.ts b/src/types.ts
index cdad800..884e99a 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -691,10 +691,6 @@ export interface OtherConnectionOptions {
    * Close connection if disconnected
    */
   closeOnDisconnect?: boolean;
-  /**
-   * Number of times to attempt reconnecting before closing connection
-   */
-  reconnectsBeforeClosing?: number;
   /**
    * Timeout in milliseconds for connection
    */
@@ -705,6 +701,10 @@ export interface OtherConnectionOptions {
   useLatestUSPVersion?: boolean;
 }
 
+export type MqttOptions = {
+  reconnectPeriod?: number;
+};
+
 export type ConnectionOptions = URLConnectionOptions | HostConnectionOptions;
 
 export type Response = string | Record<string, any>;
@@ -735,8 +735,8 @@ export type EncodeArgs = {
 export type OnIdent = string | RegExp;
 
 export type CallbackOptions = {
-  sendResp: boolean
-}
+  sendResp: boolean;
+};
 
 export type OnCallback = (
   msg: Response,
-- 
GitLab