diff --git a/DESCRIPTION b/DESCRIPTION index 3d9ff1b..b9faae4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -11,5 +11,7 @@ LazyData: true Depends: R6, httr, rjson +Imports: + data.table RoxygenNote: 6.0.1 diff --git a/NAMESPACE b/NAMESPACE index 40ea8e2..243fe43 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1 +1,7 @@ +importFrom(data.table,rbindlist) +importFrom(data.table,set) +importFrom(data.table,setattr) +importFrom(data.table,setcolorder) +importFrom(data.table,setnames) +importFrom(R6, R6Class) exportPattern("^[[:alpha:]]+") diff --git a/R/dataApi.r b/R/dataApi.r index 96d88d0..b02a422 100644 --- a/R/dataApi.r +++ b/R/dataApi.r @@ -33,49 +33,19 @@ dataApi <- R6Class("dataApi", return(as.vector(webIds)) }, convertToDataFrame = function(items) { - itemsLength <- length(items) - value <- array(1:itemsLength) - timestamp <- array(1:itemsLength) - unitsAbbreviation <- array(1:itemsLength) - good <- array(1:itemsLength) - questionable <- array(1:itemsLength) - substituted <- array(1:itemsLength) - for (i in 1:itemsLength) { - if (is.null(items[[i]]$Value) == FALSE) - { - if (is.numeric(items[[i]]$Value) == TRUE) - { - value[i] <- items[[i]]$Value - } - else - { - value[i] <- items[[i]]$Value$Name - } - } - if (is.null(items[[i]]$Timestamp) == FALSE) - { - timestamp[i] <- items[[i]]$Timestamp - } - if (is.null(items[[i]]$UnitsAbbreviation) == FALSE) - { - unitsAbbreviation[i] <- items[[i]]$UnitsAbbreviation - } - if (is.null(items[[i]]$Good) == FALSE) - { - good[i] <- items[[i]]$Good - } - if (is.null(items[[i]]$Questionable) == FALSE) - { - questionable[i] <- items[[i]]$Questionable - } - if (is.null(items[[i]]$Substituted) == FALSE) - { - substituted[i] <- items[[i]]$Substituted + # check if value is tagged + for (i in seq_along(items)) { + if (!is.numeric(items[[i]]$Value) && is.list(items[[i]]$Value)) { + items[[i]]$Value <- items[[i]]$Value$Name } } - - resDataFrame <- data.frame(value, timestamp, unitsAbbreviation, good, questionable, substituted) + resDataFrame <- data.table::rbindlist(items, fill = TRUE)[, lapply(.SD, unlist, use.names = FALSE)] + data.table::setnames(resDataFrame, + c("timestamp", "value", "unitsAbbreviation", "good", "questionable", "substituted", "annotated") + ) + data.table::set(resDataFrame, NULL, "annotated", NULL) + data.table::setcolorder(resDataFrame, "value") return(resDataFrame) }, calculateItemsIndex = function(webId, items, originalIndex){ @@ -90,72 +60,21 @@ dataApi <- R6Class("dataApi", return(originalIndex) }, convertMultipleStreamsToDataFrame = function(items, gatherInOneDataFrame, webIds, paths = NULL) { - streamsLength <- length(items) + resDataFrame <- lapply(items, function (item) self$convertToDataFrame(item$Items)) + data.table::setattr(resDataFrame, "names", paths) if (gatherInOneDataFrame == TRUE) { - itemsLength <- length(items[[1]]$Items) - order <- 1:itemsLength - resDataFrame <- data.frame(order) - for (i in 1:streamsLength) { - k = self$calculateItemsIndex (webIds[i], items, i); - value <- array(1:itemsLength) - timestamp <- array(1:itemsLength) - unitsAbbreviation <- array(1:itemsLength) - good <- array(1:itemsLength) - questionable <- array(1:itemsLength) - substituted <- array(1:itemsLength) - for (j in 1:itemsLength) { - if (is.null(items[[k]]$Items[[j]]$Value) == FALSE) - { - if (is.numeric(items[[k]]$Items[[j]]$Value) == TRUE) - { - value[j] <- items[[k]]$Items[[j]]$Value - } - else - { - value[j] <- items[[k]]$Items[[j]]$Value$Name - } - } - if (is.null(items[[k]]$Items[[j]]$Timestamp) == FALSE) - { - timestamp[j] <- items[[k]]$Items[[j]]$Timestamp - } - if (is.null(items[[k]]$Items[[j]]$UnitsAbbreviation) == FALSE) - { - unitsAbbreviation[j] <- items[[k]]$Items[[j]]$UnitsAbbreviation - } - if (is.null(items[[k]]$Items[[k]]$Good) == FALSE) - { - good[j] <- items[[k]]$Items[[k]]$Good - } - if (is.null(items[[k]]$Items[[j]]$Questionable) == FALSE) - { - questionable[j] <- items[[k]]$Items[[j]]$Questionable - } - if (is.null(items[[k]]$Items[[j]]$Substituted) == FALSE) - { - substituted[j] <- items[[k]]$Items[[j]]$Substituted - } - } - if (i == 1) { - resDataFrame <- data.frame(timestamp) - } + timestamp <- resDataFrame[[1]][, .SD, .SDcols = "timestamp"] - resDataFrame[[paste0("value", i)]] = as.vector(value) - resDataFrame[[paste0("unitsAbbreviation", i)]] = as.vector(unitsAbbreviation) - resDataFrame[[paste0("good", i)]] = as.vector(good) - resDataFrame[[paste0("questionable", i)]] = as.vector(questionable) - resDataFrame[[paste0("substituted", i)]] = as.vector(substituted) - } - } - else { - resDataFrame <- list() - for (i in 1:streamsLength) { - key <- paste0(paths[i]) - df <- self$convertToDataFrame(items[[i]]$Items) - resDataFrame[[key]] = df + for (i in seq_along(resDataFrame)) { + data.table::setnames(resDataFrame[[i]], NULL, "timestamp", NULL) + data.table::setnames(resDataFrame[[i]], paste0(names(resDataFrame[[1]]), "i")) } + + resDataFrame <- Reduce(cbind, c(list(timestamp), resDataFrame)) + } + return(resDataFrame) }, diff --git a/R/piwebapi.r b/R/piwebapi.r index fb5b370..f1c987f 100644 --- a/R/piwebapi.r +++ b/R/piwebapi.r @@ -1,7 +1,12 @@ -library(R6) -library(httr) -library(rjson) +.onLoad <- function(libname, pkgname) { + require("httr") + require("rjson") +} +.onAttach <- function(libname, pkgname) { + require("httr") + require("rjson") +} piwebapi <- R6Class("piwebapi", private = list(), diff --git a/README.md b/README.md index 36467b9..17bc12b 100644 --- a/README.md +++ b/README.md @@ -3,26 +3,32 @@ PI Web API client R package (2018) ## Introduction -This is an R package that integrates the PI System with R through PI Web API. With this package, you can retrieve PI data without having to generate the URL for each request. This version was developed on top of the PI Web API 2018 swagger specification. +This is an R package that integrates the PI System with R through PI Web API. +With this package, you can retrieve PI data without having to generate the URL +for each request. This version was developed on top of the PI Web API 2018 +swagger specification. ## Requirements. - - PI Web API 2018 installed within your domain using Kerberos or Basic Authentication. If you are using an older version, some methods might not work. + - PI Web API 2018 installed within your domain using Kerberos or Basic + Authentication. If you are using an older version, some methods might not + work. - R 3.4.3+ ## Installation -This R package is not available on CRAN. You should download it directly from this GitHub repository by using the devtools R package. If you don't have it installed, please use the command below: +This R package is not available on CRAN. You should download it directly from +this GitHub repository by using the `remotes` R package. If you don't have it +installed, please use the command below: ```r -install.packages("devtools") +install.packages("remotes") ``` -Then, load the library and install the PI Web API R package with the install_github method: +Then, load the library and install the PI Web API R package with the `install_github` method: ```r -library(devtools) -install_github("osimloeff/PI-Web-API-Client-R") +remotes::install_github("hongyuanjia/piwebapi") ``` If the installation is successful, the command below will load the package: @@ -42,17 +48,20 @@ remove.packages("piwebapi") All the methods and classes from this R package are described on its documentation, which can be opened by typing on the R console: ```r -help(package="piwebapi") +help(package="piwebapi") ``` ## Notes - - Is is highly recommended to turn debug mode on in case you are using PI Web API 2017 R2+ in order to receive more detailed exception errors. This can be achieved by creating or editing the DebugMode attribute's value to TRUE from the System Configuration element. + - Is is highly recommended to turn debug mode on in case you are using PI Web + API 2017 R2+ in order to receive more detailed exception errors. This can be + achieved by creating or editing the DebugMode attribute's value to TRUE from + the System Configuration element. - The X-Requested-With header is added to work with CSRF defences. ## Examples -Please refer to the following examples to understand how to use this library: +Please refer to the following examples to understand how to use this library: ### Create an intance of the piwebapi top level object. @@ -77,9 +86,9 @@ debug <- TRUE piWebApiService <- piwebapi$new("https://webserver/piwebapi", useKerberos, username, password, validateSSL, debug) ``` -If you want to use basic authentication instead of Kerberos, set useKerberos to FALSE. -If you are having issues with your SSL certificate and you want to ignore this error, set validateSSL to FALSE. -If you want to receive a log about each HTTP request, set debug to TRUE. +* If you want to use basic authentication instead of Kerberos, set useKerberos to FALSE. +* If you are having issues with your SSL certificate and you want to ignore this error, set validateSSL to FALSE. +* If you want to receive a log about each HTTP request, set debug to TRUE. ### Retrieve data from the main PI Web API endpoint @@ -247,6 +256,7 @@ response17 <- piWebApiService$streamSet$retrieveStreamSetUpdates(markers); ## Licensing + Copyright 2018 OSIsoft, LLC. Licensed under the Apache License, Version 2.0 (the "License"); @@ -260,5 +270,5 @@ Copyright 2018 OSIsoft, LLC. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - + Please see the file named [LICENSE.md](LICENSE.md).