emoncmsr
: R interface to the emonCMS APIThis package provides the tools to create, delete, and manage inputs and feeds in the open source energy, temperature and environmental monitoring sytem from OpenEnergyMonitor.
emonCMS has two flavors, a self-hosted version and a hosted solution at emoncms.org. The two APIs are similar but differ in a number of areas. This package only supports the self-hosted flavor, though there are several unsupported functions for the hosted version.
This package takes a slightly opinionated view towards the API, returning
normalized values from many of the API calls. The native API has several non-
standard and inconsistent responses to both success and failure. emoncmsr
provides an interface consistent with data analysis and a tidy pipeline.
devtools::install_github("davidski/emoncmsr")
emoncmsr requires two environment variables to locate the emoncms host and the
proper API key for authentication. These can be set globally (e.g. via
.bashrc
, the Windows control panel, or other OS-specific mechanism) or you
can place them in your ~.Renviron
file for a portable solution.
Environment variables used:
Simulating a beverage sensor that monitors the level of coffee, tea, and water available. First, we'll list the inputs currently configured.
library(emoncmsr) suppressPackageStartupMessages(library(tidyverse)) # use the tidyverse # Inputs list_inputs()
Now we'll create some simulated data, post it to emonCMS as inputs using a
node identifier of emoncmsr
, read back the value of the coffee level we just
posted, store the ID of this new coffee input for future use, and set a useful
description for the new input. Whew! Let's get to it!
# create some beverage data dat <- list(coffee = 42, tea = 6, water = 42) post_data_to_input(dat) list_inputs() %>% filter(nodeid == "emoncmsr", name == "coffee") # store the id of the new input inputid <- list_inputs() %>% filter(nodeid == "emoncmsr", name == "coffee") %>% pull(id) inputid # set a friendly description for our new input set_input_field(inputid, "description", "cups of coffee remaining in pot") list_inputs() %>% filter(id == inputid)
That wasn't so bad!
While we're now accepting levels of coffee, tea, and water in emonCMS, those values aren't being stored or processed in any way. We'd like to monitor the levels of coffee over time. We need to create a feed, then configure the coffee input to send its data to that feed.
# Create a feed for the coffee level feed_response <- create_feed("coffeelevel", "emoncmsr") feed_response # Show that the feed exists list_feeds() %>% filter(id == feed_response$feedid) # Hook up the coffee monitor to the feed set_input_process(inputid, paste(1, feed_response$feedid, sep = ":")) get_input_processes(inputid)
Now that we have our feed set up, let's send some updated beverage level sensor data. We'll first send a single timepoint set of values, then demonstrate using the bulk data interface to several days of simulated data in a single call.
After sending the readings we'll read the feed metadata to demonstrate that data has flowed from the input to the feed.
# Post a single set of readings to all three new inputs dat <- list(coffee = 86, tea = 100, water = 4) post_data_to_input(dat) # show the values we just posted appeared in the inputs list_inputs() %>% filter(nodeid == "emoncmsr") # We can also use the bulk data input format for sending a dataframe # worth of data, all at different offsets to an optional timestamp interval <- get_feed_metadata(feed_response$feedid)$interval end_time <- lubridate::now() %>% as.integer() end_time <- end_time - (end_time %% interval) start_time <- (lubridate::now() - lubridate::ddays(3)) %>% as.integer() start_time <- start_time - (start_time %% interval) times <- seq(start_time, end_time, by = interval) dat <- tibble(offset = times, nodeid = "emoncmsr") dat <- bind_cols(dat, tibble(value = map(times, ~list("coffee" = sample(1:10, size=1))))) post_bulk_data_to_input(dat, reference_time = 0) # this large a bulk post can take a moment to process, sleep for a few seconds Sys.sleep(5) # we can also post with a specific reference time, though we don't demonstrate # that here... # reference_time <- lubridate::as_datetime("2017-03-27 01:30:00") %>% as.integer() # post_bulk_data_to_input(dat, reference_time) # show the feed's info get_feed_metadata(feed_response$feedid)
Beverage monitoring systems are GO! Let's pull a set of data from our feed and plot that data over time, adding a smoothed curve for grins.
dat <- get_feed_data(feed_response$feedid) gg <- ggplot(dat, aes(x = date, y = value)) + geom_line() + geom_smooth(method = 'loess') + labs(title = "Coffee Levels", subtitle = "Seven day historical with smoothed overlay", caption = "Demonstration plot for emoncmsr", y = "Watts", x = NULL) + scale_y_continuous(labels = scales::pretty_breaks()) + theme_minimal() gg
Finally, clean up the test inputs and feeds we created.
list_feeds() %>% filter(tag == "emoncmsr") %>% pull(id) %>% map(~ delete_feed(.x)) list_inputs() %>% filter(nodeid == "emoncmsr") %>% pull(id) %>% map(~ delete_input(.x))
library(emoncmsr) library(testthat) date() test_dir("tests/")
This project is governed by a Code of Conduct. By participating in this project you agree to abide by these terms.
The MIT License applies.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.