<file_sep>% Generated by roxygen2 (4.1.1): do not edit by hand
% Please edit documentation in R/flowerpower.R
\name{get_samples.flowerpower}
\alias{get_samples.flowerpower}
\title{Get data samples.}
\usage{
\method{get_samples}{flowerpower}(obj, location)
}
\arguments{
\item{obj}{a flowerpower object}

\item{location}{a location identifier}
}
\description{
Get data samples.
}

<file_sep>
#' @importFrom httr GET content http_status stop_for_status add_headers
#' @importFrom lubridate ymd_hms as.period now days
NULL
<file_sep>## flowerpower — access Parrot's Flower Power Sensor from R

[![Travis-CI Build Status](https://travis-ci.org/vsbuffalo/flowerpower.png?branch=master)](https://travis-ci.org/vsbuffalo/flowerpower)


![timeseries plot of temperature data from FlowerPower unit](https://raw.githubusercontent.com/vsbuffalo/flowerpower/master/inst/extdata/example.png)

An R package to access data from Parrot's awesome
[Flower Power sensor](http://www.parrot.com/usa/products/flower-power/). This is
still in **alpha**.

FlowerPower's API is a bit strange and requires *a lot* of authentication keys,
including your username and password to the FlowerPower site (not the dev
portal). Here is an example:

    > fp <- flowerpower(user, pass, id, secret)
    > get_locations(fp) # get location IDs
    > s <- get_samples(fp, location='1W2zIGfgEF14220_YOURLOCATIONKEY')
	> head(s)
           capture_ts par_umole_m2s air_temperature_celsius vwc_percent
    1 2015-03-10 21:49:00     12.607764                30.45476    17.04505
    2 2015-03-10 22:04:00     11.928668                29.37226    16.63505
    3 2015-03-10 22:19:00      8.715568                28.45192    16.44611
    4 2015-03-10 22:34:00     11.429752                28.15554    15.81059
    5 2015-03-10 22:49:00      7.567640                28.86598    16.66856
    6 2015-03-10 23:04:00      7.066480                28.31073    16.91436

    > p <- ggplot(s) + geom_line(aes(x=capture_ts, y=air_temperature_celsius))
    > p <- p + xlab("time") + ylab("temperature (C)")
    > p

There's also a `get_fertilizer()` function to access these data.

### Design

An R6 class stores state and lower-level methods for getting data from the
server, and higher-level S3 methods call these methods and reshape
results. Users interact with these higher-level functions, but I leave the
object methods public for developers that want to do their own hacking.

### Todo

- Refresh auth token.




<file_sep>% Generated by roxygen2 (4.1.1): do not edit by hand
% Please edit documentation in R/flowerpower.R
\name{get_fertilizer.flowerpower}
\alias{get_fertilizer.flowerpower}
\title{Get fertilizer samples.}
\usage{
\method{get_fertilizer}{flowerpower}(obj, location)
}
\arguments{
\item{obj}{a flowerpower object}

\item{location}{a location identifier}
}
\description{
Get fertilizer samples.
}

<file_sep>% Generated by roxygen2 (4.1.1): do not edit by hand
% Please edit documentation in R/flowerpower.R
\name{get_locations.flowerpower}
\alias{get_locations.flowerpower}
\title{Get all sensor locations}
\usage{
\method{get_locations}{flowerpower}(obj, location = NULL)
}
\arguments{
\item{obj}{a flowerpower object}

\item{location}{a location identifier}
}
\description{
Get all sensor locations
}

<file_sep>% Generated by roxygen2 (4.1.1): do not edit by hand
% Please edit documentation in R/flowerpower.R
\name{get_samples}
\alias{get_samples}
\title{Get data samples.}
\usage{
get_samples(obj, location)
}
\arguments{
\item{obj}{a flowerpower object}

\item{location}{a location identifier}
}
\description{
Get data samples.
}

<file_sep>% Generated by roxygen2 (4.1.1): do not edit by hand
% Please edit documentation in R/flowerpower.R
\name{get_locations}
\alias{get_locations}
\title{Get all sensor locations}
\usage{
get_locations(obj, location = NULL)
}
\arguments{
\item{obj}{a flowerpower object}

\item{location}{a location identifier}
}
\description{
Get all sensor locations
}

<file_sep># flowerpower.R
##' @importFrom R6 R6Class

# suppress warnings; TODO: not optimal
options(lubridate.verbose = FALSE)

FPDEBUG <- FALSE

stop_for_status <- function(x) {
  # a switch to catch HTTP errors when in debug mode
  if (FPDEBUG)
    if (!httr::successful(x)) {
      print(x)
      browser()
    }
  httr::stop_for_status(x)
}

# URL stuff
FPAPI_ROOT <- "https://apiflowerpower.parrot.com/"
fpurl <- function(path) paste0(FPAPI_ROOT, path)
FPAPI_GETLOCS <- fpurl("sensor_data/v3/sync")
FPAPI_GETSAMPS <- fpurl("sensor_data/v2/sample/location/")
FPAPI_AUTH <- fpurl("user/v1/authenticate")

# Internal function to create data ranges (since max date span is 10 days)
date_ranges <- function(from, to=now(), interval=days(9)) {
  n <- ceiling(as.period(to - from)/interval)
  out <- vector('list', n)
  last <- from
  for (i in seq_len(n)) {
    out[[i]] <- c(last, last + interval)
    last <- last + interval
  }
  out
}

unfold_list <- function(x, el) {
  # take a list of elements, extract and bind an inner list of list of rows
  # #yodawg #ihatenestedlists
  out <- do.call(rbind, lapply(x, function(u) {
                          as.data.frame(do.call(rbind, u[[el]]))
                        }))
  out
}

# All internal methods are in R6, API funs in S3
flowerpower_factory <- R6::R6Class(
  "flowerpower",
   public=list(
     keys=NULL,
     auth_header=NULL,
     token=NULL,
     locations=list(),
     last_sync=NULL,
     auth=function() {
       auth_query <- c(list(grant_type='password'), self$keys)
       r <- GET(FPAPI_AUTH, query=auth_query)
       stop_for_status(r)
       self$token <<- content(r)$access_token
       authkey <- sprintf("Bearer %s", self$token)
       self$auth_header <<- add_headers(Authorization=authkey)
       self
     },
     initialize=function(user, pass, client_id, client_secret) {
       self$keys <<- list(username=user,
                            password=<PASSWORD>,
                            client_id=client_id,
                            client_secret=client_secret)
       self$auth()
    },
     is_auth=function() {
       return(!is.null(self$token))
     },
     sync=function() {
       # server sync request; for location other data
       r <- GET(FPAPI_GETLOCS, self$auth_header)
       stop_for_status(r)
       cont <- content(r)
       self$last_sync <<- cont
       cont
     },
     get_data=function(location, from=NULL, to=NULL) {
       # NOTE: returns list of each time range (lower-level fun)
       if (!is.null(from) || !is.null(to)) stop("not implemented")
       # plant assigned date is earliest date
       assigned_data <- ymd_hms(get_locations(self, location)$plant_assigned_date)
       rngs <- date_ranges(assigned_data, interval=days(10))
       out_lst <- lapply(rngs, function(rng) {
         rng <- as.character(rng)
         qry <- list(from_datetime_utc=rng[1], to_datetime_utc=rng[2])
         locurl <- paste0(FPAPI_GETSAMPS, location)
         r <- GET(locurl, query=qry, self$auth_header)
         stop_for_status(r)
         cnt <- content(r)
         cnt
       })
       # now, merge all list elements (across date ranges)
      samples <- unfold_list(out_lst, 'samples')
      fertilizer <- unfold_list(out_lst, 'fertilizer')
      merged <- out_lst
      merged$samples <- samples
      merged$fertilizer <- fertilizer
      merged
     },
     check_sync=function() {
       if (is.null(self$last_sync))
         self$sync()
     }
    ))

#' Create new API connection to Parrot's FlowerPower sensor
#'
#' @param user username
#' @param pass <PASSWORD>
#' @param client_id client identifier
#' @param client_secret client secret key
#' @export
flowerpower <- function(user, pass, client_id, client_secret) {
  flowerpower_factory$new(user, pass, client_id, client_secret)
}

#' Get all sensor locations
#'
#' @param obj a flowerpower object
#' @param location a location identifier
#'
#' @export
get_locations <- function(obj, location=NULL) {
  UseMethod("get_locations")
}

#' Get all sensor locations
#'
#' @param obj a flowerpower object
#' @param location a location identifier
#'
#' @export
get_locations.flowerpower <- function(obj, location=NULL) {
  obj$check_sync()
  ignore_cols <- c("images", "display_order", "avatar_url",
                   "ignore_fertilizer_alert",
                   "ignore_light_alert",
                   "ignore_moisture_alert",
                   "ignore_temperature_alert")
  tmp <- do.call(rbind, lapply(obj$last_sync$locations, function(x) {
    data.frame(x[setdiff(names(x), ignore_cols)], stringsAsFactors=FALSE)
  }))
  if (!is.null(location))
    return(tmp[tmp$location_identifier == location, ])
  tmp$plant_assigned_data <- ymd_hms(tmp$plant_assigned_date)
  tmp
}

#' Get data samples.
#'
#' @param obj a flowerpower object
#' @param location a location identifier
#'
#' @export
get_samples <- function(obj, location) {
  UseMethod("get_samples")
}

#' Get data samples.
#'
#' @param obj a flowerpower object
#' @param location a location identifier
#'
#' @export
get_samples.flowerpower <- function(obj, location) {
  obj$check_sync()
  dt <- obj$get_data(location)
  out <- dt$samples
  out$capture_ts <- ymd_hms(out$capture_ts)
  out
}


#' Get fertilizer samples.
#'
#' @param obj a flowerpower object
#' @param location a location identifier
#'
#' @export
get_fertilizer <- function(obj, location) {
  UseMethod("get_fertilizer")
}

#' Get fertilizer samples.
#'
#' @param obj a flowerpower object
#' @param location a location identifier
#'
#' @export
get_fertilizer.flowerpower <- function(obj, location) {
  obj$check_sync()
  dt <- obj$get_data(location)
  out <- dt$fertilizer 
  out$watering_cycle_end_date_time_utc <- ymd_hms(out$watering_cycle_end_date_time_utc)
  out$watering_cycle_start_date_time_utc <- ymd_hms(out$watering_cycle_start_date_time_utc)
  out
}
<file_sep>% Generated by roxygen2 (4.1.1): do not edit by hand
% Please edit documentation in R/flowerpower.R
\name{get_fertilizer}
\alias{get_fertilizer}
\title{Get fertilizer samples.}
\usage{
get_fertilizer(obj, location)
}
\arguments{
\item{obj}{a flowerpower object}

\item{location}{a location identifier}
}
\description{
Get fertilizer samples.
}

<file_sep>% Generated by roxygen2 (4.1.1): do not edit by hand
% Please edit documentation in R/flowerpower.R
\name{flowerpower}
\alias{flowerpower}
\title{Create new API connection to Parrot's FlowerPower sensor}
\usage{
flowerpower(user, pass, client_id, client_secret)
}
\arguments{
\item{user}{username}

\item{pass}{<PASSWORD>}

\item{client_id}{client identifier}

\item{client_secret}{client secret key}
}
\description{
Create new API connection to Parrot's FlowerPower sensor
}

