{
  "productInfo" : {
    "company" : "HighByte",
    "product" : "IntelligenceHub",
    "version" : "4.4.1",
    "build" : "2026.4.14.7",
    "stage" : "Release"
  },
  "project" : {
    "version" : 13,
    "connections" : [ {
      "name" : "mqtt",
      "uri" : "mqtt://localhost:1889",
      "description" : "This is a Connection to the Intelligence Hub MQTT broker created for the purpose of viewing Pipeline outputs.",
      "tags" : [ "starter_canary", "starter_ip21", "starter_pi_af", "starter_pi_da" ],
      "writes" : {
        "flattenModeledValues" : false
      },
      "writeThrottle" : {
        "enabled" : false,
        "maxBatchSizePerTarget" : 1000,
        "batchDelay" : {
          "duration" : 20,
          "units" : "Milliseconds"
        }
      },
      "subscriptions" : { },
      "storeForward" : {
        "enabled" : false,
        "maxEntries" : 100,
        "waitOnFailureInterval" : {
          "duration" : 1,
          "units" : "Seconds"
        }
      },
      "settings" : {
        "connectionTimeoutSeconds" : 10,
        "keepAliveSeconds" : 60,
        "requestTimeoutMS" : 5000,
        "maxInflight" : 1000,
        "cleanSession" : true,
        "mcpEnabled" : "disabled",
        "ssl" : false,
        "redundantBrokers" : [ ],
        "inputDiscovery" : "",
        "clientId" : "Intelligence_Hub_Reference"
      }
    }, {
      "name" : "pi_da",
      "uri" : "osisoft.afsdk://{{System.Variables.pi_host_reference}}:45299",
      "description" : "This is a Connection to AVEVA PI System.  The purpose of the Connection is to obtain data for starter solution examples and, specifically starter solutions related to PI Data Archive.  HighByte note: this Connection uses a dedicated agent installed on a demo system EC2.",
      "tags" : [ "starter_pi_da" ],
      "writes" : {
        "flattenModeledValues" : false
      },
      "writeThrottle" : {
        "enabled" : false,
        "maxBatchSizePerTarget" : 1000,
        "batchDelay" : {
          "duration" : 20,
          "units" : "Milliseconds"
        }
      },
      "subscriptions" : { },
      "storeForward" : {
        "enabled" : false,
        "maxEntries" : 100,
        "waitOnFailureInterval" : {
          "duration" : 1,
          "units" : "Seconds"
        }
      },
      "settings" : {
        "connectTimeoutSeconds" : 5,
        "requestTimeoutMS" : 120000,
        "compression" : "GZIP",
        "auth" : {
          "type" : "credentials",
          "username" : "osisoft",
          "password" : {
            "type" : "Reference",
            "value" : "pi_password"
          }
        },
        "password" : {
          "type" : "Reference",
          "value" : "pi_token_reference"
        }
      }
    } ],
    "inputs" : [ {
      "name" : "pi_da_input_current_values",
      "connection" : "pi_da",
      "type" : "osisoft.afsdk",
      "qualifier" : {
        "type" : "point",
        "options" : {
          "get" : "currentValue",
          "includeMetaData" : false,
          "includeChildren" : true,
          "useReference" : false,
          "query" : "",
          "index" : false,
          "indexWindow" : "",
          "calcBasis" : "timeWeighted",
          "points" : [ "{{this.flow}}", "{{this.status}}" ]
        }
      },
      "cacheLifetime" : {
        "enabled" : false
      },
      "template" : {
        "type" : "Off"
      },
      "parameters" : {
        "type" : "inline",
        "model" : {
          "name" : "params",
          "tags" : [ ],
          "attributes" : [ {
            "attributeType" : "Internal",
            "name" : "flow",
            "nullable" : false,
            "required" : false,
            "array" : false,
            "defaultValue" : "OSIDemo_Line 1.Inlet Pump.Flow Rate.71d17760-99ae-5bcc-3123-3ca8750adb04",
            "internalType" : "String"
          }, {
            "attributeType" : "Internal",
            "name" : "status",
            "nullable" : false,
            "required" : false,
            "array" : false,
            "defaultValue" : "OSIDemo_Line 1.Inlet Pump.Status.794e1058-b3b2-54ff-0364-8e5b16aaee56",
            "internalType" : "String"
          } ]
        }
      }
    }, {
      "name" : "pi_da_input_metadata_points",
      "connection" : "pi_da",
      "type" : "osisoft.afsdk",
      "qualifier" : {
        "type" : "pointbrowse",
        "options" : {
          "get" : "currentValue",
          "includeMetaData" : true,
          "includeChildren" : true,
          "query" : "OSIDemo_Line*p.Flow* OR OSIDemo_Line*p.Status*",
          "index" : false,
          "indexWindow" : "",
          "additionalMetadataProperties" : [ "changedate" ]
        }
      },
      "cacheLifetime" : {
        "enabled" : false
      },
      "template" : {
        "type" : "Off"
      },
      "parameters" : {
        "type" : "EmptyParameters"
      }
    }, {
      "name" : "pi_da_input_point_list",
      "connection" : "pi_da",
      "type" : "osisoft.afsdk",
      "qualifier" : {
        "type" : "pointbrowse",
        "options" : {
          "get" : "currentValue",
          "includeMetaData" : false,
          "includeChildren" : true,
          "query" : "OSIDemo_Line*p.Flow* OR OSIDemo_Line*p.Status*",
          "index" : false,
          "indexWindow" : ""
        }
      },
      "cacheLifetime" : {
        "enabled" : true,
        "interval" : {
          "duration" : 1,
          "units" : "Days"
        }
      },
      "template" : {
        "type" : "Off"
      },
      "parameters" : {
        "type" : "EmptyParameters"
      }
    }, {
      "name" : "pi_da_input_points_for_current_values",
      "connection" : "pi_da",
      "type" : "osisoft.afsdk",
      "qualifier" : {
        "type" : "pointbrowse",
        "options" : {
          "get" : "currentValue",
          "includeMetaData" : false,
          "includeChildren" : true,
          "query" : "OSIDemo_Line 1*p.Flow* OR OSIDemo_Line 1*p.Status* OR OSIDemo_Line 2*p.Flow* OR OSIDemo_Line 2*p.Status*",
          "index" : false,
          "indexWindow" : "",
          "additionalMetadataProperties" : [ ]
        }
      },
      "cacheLifetime" : {
        "enabled" : true,
        "interval" : {
          "duration" : 1,
          "units" : "Days"
        }
      },
      "template" : {
        "type" : "Off"
      },
      "parameters" : {
        "type" : "EmptyParameters"
      }
    }, {
      "name" : "pi_da_input_points_for_time_span",
      "connection" : "pi_da",
      "type" : "osisoft.afsdk",
      "qualifier" : {
        "type" : "pointbrowse",
        "options" : {
          "get" : "currentValue",
          "includeMetaData" : false,
          "includeChildren" : true,
          "query" : "OSIDemo_Line*p.Flow* OR OSIDemo_Line*p.Status*",
          "index" : false,
          "indexWindow" : "",
          "additionalMetadataProperties" : [ ]
        }
      },
      "cacheLifetime" : {
        "enabled" : true,
        "interval" : {
          "duration" : 1,
          "units" : "Days"
        }
      },
      "template" : {
        "type" : "Off"
      },
      "parameters" : {
        "type" : "EmptyParameters"
      }
    }, {
      "name" : "pi_da_input_points_for_value_changes",
      "connection" : "pi_da",
      "type" : "osisoft.afsdk",
      "qualifier" : {
        "type" : "pointbrowse",
        "options" : {
          "get" : "currentValue",
          "includeMetaData" : false,
          "includeChildren" : true,
          "query" : "OSIDemo_Line*",
          "index" : false,
          "indexWindow" : ""
        }
      },
      "cacheLifetime" : {
        "enabled" : true,
        "interval" : {
          "duration" : 1,
          "units" : "Days"
        }
      },
      "template" : {
        "type" : "Off"
      },
      "parameters" : {
        "type" : "EmptyParameters"
      }
    }, {
      "name" : "pi_da_input_value_changes",
      "connection" : "pi_da",
      "type" : "osisoft.afsdk",
      "qualifier" : {
        "type" : "pointdatapipe",
        "options" : {
          "get" : "currentValue",
          "includeMetaData" : false,
          "includeChildren" : true,
          "useReference" : true,
          "maxPerRead" : 10000,
          "reference" : "{{Connection.pi_da.pi_da_input_points_for_value_changes}}",
          "subscriptionId" : "pi_da_input_value_changes_5_26",
          "query" : "",
          "index" : false,
          "indexWindow" : ""
        }
      },
      "cacheLifetime" : {
        "enabled" : false
      },
      "template" : {
        "type" : "Off"
      },
      "parameters" : {
        "type" : "EmptyParameters"
      }
    }, {
      "name" : "pi_da_input_values_time_span",
      "connection" : "pi_da",
      "type" : "osisoft.afsdk",
      "qualifier" : {
        "type" : "point",
        "options" : {
          "get" : "rawValues",
          "includeMetaData" : true,
          "includeChildren" : true,
          "useReference" : true,
          "boundaryType" : "inside",
          "startTime" : "{{this.startTime}}",
          "endTime" : "{{this.endTime}}",
          "query" : "",
          "index" : false,
          "indexWindow" : "",
          "calcBasis" : "timeWeighted",
          "points" : [ "{{this.tagList}}]]]" ],
          "reference" : "{{Connection.pi_da.pi_da_input_points_for_time_span}}"
        }
      },
      "cacheLifetime" : {
        "enabled" : false
      },
      "template" : {
        "type" : "Off"
      },
      "parameters" : {
        "type" : "inline",
        "model" : {
          "name" : "params",
          "tags" : [ ],
          "attributes" : [ {
            "attributeType" : "Internal",
            "name" : "startTime",
            "nullable" : false,
            "required" : false,
            "array" : false,
            "internalType" : "String"
          }, {
            "attributeType" : "Internal",
            "name" : "endTime",
            "nullable" : false,
            "required" : false,
            "array" : false,
            "internalType" : "String"
          } ]
        }
      }
    } ],
    "outputs" : [ ],
    "modeling" : {
      "models" : [ {
        "name" : "starter_values",
        "description" : "This Model defines a simple narrow schema and supports multiple historian related starter solutions.",
        "groupAs" : "/starter_hist_values",
        "tags" : [ "starter_pi_da" ],
        "attributes" : [ {
          "attributeType" : "Internal",
          "name" : "tagId",
          "nullable" : false,
          "required" : true,
          "array" : false,
          "internalType" : "String"
        }, {
          "attributeType" : "Internal",
          "name" : "valueNumeric",
          "nullable" : true,
          "required" : false,
          "array" : false,
          "internalType" : "Real64"
        }, {
          "attributeType" : "Internal",
          "name" : "valueOther",
          "nullable" : true,
          "required" : false,
          "array" : false,
          "internalType" : "String"
        }, {
          "attributeType" : "Internal",
          "name" : "quality",
          "nullable" : true,
          "required" : false,
          "array" : false,
          "internalType" : "String"
        }, {
          "attributeType" : "Internal",
          "name" : "time",
          "nullable" : false,
          "required" : true,
          "array" : false,
          "internalType" : "DateTime"
        }, {
          "attributeType" : "Internal",
          "name" : "transactionType",
          "nullable" : true,
          "required" : false,
          "array" : false,
          "internalType" : "String"
        } ]
      } ],
      "instances" : [ ]
    },
    "conditions" : [ ],
    "functions" : [ ],
    "tags" : [ {
      "name" : "starter_pi_da"
    } ],
    "pipelines" : [ {
      "name" : "starter_output_pi_da_historical_backfill_values_to_mqtt",
      "description" : "This Pipeline executes many times to index through a time period of historical PI Point value changes.  The Pipeline obtains data from PI Data Archive and models the data before formatting it into an array.  The modeled data would typically be written to a file for a data lake or written directly to a data warehouse table.  The dates for the time period and the index interval time are stored in JavaScript Stages that must be edited.  A date is also stored as a State Variable that must be deleted to reset the Pipeline.",
      "groupAs" : "/starter_hist_historical_backfill",
      "tags" : [ "starter_pi_da" ],
      "inputStages" : [ "get_start_time" ],
      "stages" : [ {
        "name" : "calc_end_time",
        "display" : {
          "position" : {
            "x" : 1140,
            "y" : 0
          }
        },
        "description" : "This JavaScript Stage is used to set the time interval for each index and to calculate the end time for the current execution of the Pipeline.",
        "config" : {
          "type" : ".JavaScriptTransformConfig",
          "transformExpression" : "// intervalSeconds (1 minute)\r\nlet intervalSeconds = 1*60;\r\n\r\n// intervalMilliseconds\r\nlet intervalMilliseconds = intervalSeconds * 1000;\r\n\r\n// set startTime\r\nlet startTime = new Date(event.metadata.startTime);\r\n\r\n// set endTime\r\nlet endTime = new Date();\r\nendTime.setTime(startTime.getTime() + intervalMilliseconds);\r\n\r\n// set endTime as metadata\r\nstage.setMetadata(\"endTime\", endTime.toISOString());\r\n\r\n// set NextRunStartTime pipeline state to endTime of current run.\r\nstate.pipeline.set(\"NextRunStartTime\", endTime.toISOString());\r\n\r\nstage.setValue(event.value);"
        },
        "outputs" : [ "read_pi_values" ]
      }, {
        "name" : "read_pi_values",
        "display" : {
          "position" : {
            "x" : 1590,
            "y" : 0
          }
        },
        "description" : "The Stage reads the value changes from PI Data Archive for the parameterized start and end time and tag list saved as a reference for the PI Connection Input.",
        "config" : {
          "type" : ".ReadConfig",
          "failureOutputs" : [ ],
          "reference" : {
            "type" : "Input",
            "name" : "pi_da_input_values_time_span",
            "path" : "",
            "params" : {
              "startTime" : "{{event.metadata.startTime}}",
              "endTime" : "{{event.metadata.endTime}}"
            },
            "connectionName" : "pi_da"
          }
        },
        "outputs" : [ "breakup_object" ]
      }, {
        "name" : "breakup_array",
        "display" : {
          "position" : {
            "x" : 2490,
            "y" : 0
          }
        },
        "description" : "The Stage breakups up the PI Point array per value change.",
        "config" : {
          "type" : ".BreakupConfig",
          "breakupType" : "array",
          "depth" : 1
        },
        "outputs" : [ "apply_model" ]
      }, {
        "name" : "to_mqtt",
        "display" : {
          "position" : {
            "x" : 3840,
            "y" : 0
          }
        },
        "description" : "In this example value change arrays are being written to the Intelligence Hub MQTT broker for ease of visibility.  ",
        "config" : {
          "type" : ".DynamicWriteConfig",
          "failureOutputs" : [ ],
          "connectionReference" : "{{Connection.mqtt}}",
          "qualifier" : {
            "topic" : "Historical_Backfill_PI_DA",
            "qos" : 0,
            "namedRoot" : false,
            "retained" : false,
            "breakupArrays" : false,
            "filterList" : [ "_model", "_name", "_timestamp" ]
          },
          "qualifierExpression" : "",
          "writeReturn" : "ignore"
        },
        "outputs" : [ ]
      }, {
        "name" : "breakup_object",
        "display" : {
          "position" : {
            "x" : 2040,
            "y" : 0
          }
        },
        "description" : "The Stage breakups up the object payload per PI Point.",
        "config" : {
          "type" : ".BreakupConfig",
          "breakupType" : "object",
          "depth" : 1
        },
        "outputs" : [ "breakup_array" ]
      }, {
        "name" : "apply_model",
        "display" : {
          "position" : {
            "x" : 2940,
            "y" : 0
          }
        },
        "description" : "This stage applies the desired schema to the payload.",
        "config" : {
          "type" : ".ModelConfig",
          "model" : "starter_values",
          "objectName" : "",
          "initExpression" : "",
          "attributes" : [ {
            "name" : "tagId",
            "expression" : {
              "type" : "JavaScript",
              "expression" : "return event.value.metadata.pointID"
            }
          }, {
            "name" : "valueNumeric",
            "expression" : {
              "type" : "JavaScript",
              "expression" : "// checks if event.value.value is not not a number (is a number), not null, not blank and is finite number (not +Infinity, or -Infinity).   If true, cast event.value.value to a number.  If false, set to null.\r\nif (!isNaN(event.value.value) && event.value.value !==null && event.value.value !== \"\" && isFinite(event.value.value))\r\n{\r\n\treturn Number(event.value.value);\r\n}\r\nelse\r\n{\r\n\treturn null;\r\n}\r\n"
            }
          }, {
            "name" : "valueOther",
            "expression" : {
              "type" : "JavaScript",
              "expression" : "// checks if event.value.value is not not a number (is a number), not null, not blank and is finite number (not +Infinity, or -Infinity).   If true, set to null.  If false, return the event.value.value.\r\nif (!isNaN(event.value.value) && event.value.value !==null && event.value.value !== \"\" && isFinite(event.value.value))\r\n{\r\n\treturn null;\r\n}\r\nelse\r\n{\r\n\treturn (event.value.value);\r\n}"
            }
          }, {
            "name" : "quality",
            "expression" : {
              "type" : "JavaScript",
              "expression" : "return event.value.quality;"
            }
          }, {
            "name" : "time",
            "expression" : {
              "type" : "JavaScript",
              "expression" : "return event.value.time;"
            }
          }, {
            "name" : "transactionType",
            "expression" : {
              "type" : "JavaScript",
              "expression" : ""
            },
            "defaultValue" : "backfill"
          } ]
        },
        "outputs" : [ "size_buffer" ]
      }, {
        "name" : "get_start_time",
        "display" : {
          "position" : {
            "x" : 240,
            "y" : 0
          }
        },
        "description" : "This JavaScript Stage is used to set the overall time period and to calculate the start time for the current execution of the Pipeline.",
        "config" : {
          "type" : ".JavaScriptTransformConfig",
          "transformExpression" : "// set initial for start time and end time\r\nlet initialStartTime = new Date('2025-10-13T00:00:00.000Z');\r\nlet pipelineEndTime = new Date('2025-10-13T01:00:00.000Z');\r\nstage.setMetadata(\"PipelineEndTime\", pipelineEndTime);\r\n// read NextRunStartTime as the state value if it exists or initialStartTime if it does not exist.\r\nlet startTime = new Date(state.pipeline.get(\"NextRunStartTime\", initialStartTime));\r\n// set startTime metadata\r\nstage.setMetadata(\"startTime\", startTime.toISOString());\r\nstage.setValue(event.value);"
        },
        "outputs" : [ "check_for_end" ]
      }, {
        "name" : "check_for_end",
        "display" : {
          "position" : {
            "x" : 690,
            "y" : 0
          }
        },
        "description" : "This Switch Stage is used to determine if the Pipeline should continue to index through the overall time period.",
        "config" : {
          "type" : ".SwitchConfig",
          "switchCases" : [ {
            "expression" : "return Boolean(new Date(event.metadata.startTime) >= new Date(event.metadata.PipelineEndTime))",
            "outputs" : [ ],
            "description" : "End Pipeline"
          }, {
            "expression" : "return true",
            "outputs" : [ "calc_end_time" ],
            "description" : "Continue Pipeline"
          } ]
        },
        "outputs" : [ ]
      }, {
        "name" : "size_buffer",
        "display" : {
          "position" : {
            "x" : 3390,
            "y" : 0
          }
        },
        "description" : "The Buffer Stage is used to group many value changes before writing to a file or a data lake or data warehouse.",
        "config" : {
          "type" : ".SizedBufferConfig",
          "windowExpression" : "stage.setBufferKey(null);",
          "windowSize" : 100,
          "timeout" : {
            "duration" : 1,
            "units" : "Minutes"
          }
        },
        "outputs" : [ "to_mqtt" ]
      } ],
      "trackActivity" : false,
      "triggers" : [ {
        "name" : "polled_trigger",
        "display" : {
          "position" : {
            "x" : -450,
            "y" : 0
          }
        },
        "description" : "This Pipeline trigger is set to Continuous mode, so the next Pipeline execution starts as soon as the previous execution ends",
        "config" : {
          "type" : ".TriggerPolled",
          "enabled" : false,
          "interval" : {
            "duration" : 10,
            "units" : "Seconds"
          },
          "mode" : "continuous"
        }
      } ],
      "errorHandler" : {
        "type" : "default"
      }
    } ],
    "namespace" : [ ]
  },
  "network" : {
    "groups" : [ ],
    "hubs" : [ ]
  }
}