-
Notifications
You must be signed in to change notification settings - Fork 1
/
README.Rmd
184 lines (140 loc) 路 6.26 KB
/
README.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
---
output:
github_document
---
## `emoncmsr`: R interface to the [emonCMS](https://github.com/emoncms/emoncms) API
<!-- badges: start -->
[![R build status](https://github.com/davidski/emoncmsr/workflows/R-CMD-check/badge.svg)](https://github.com/davidski/emoncmsr/actions)
[![Coverage Status](https://img.shields.io/codecov/c/github/davidski/emoncmsr/master.svg)](https://codecov.io/github/davidski/emoncmsr?branch=master)
<!-- badges: end -->
This package provides the tools to create, delete, and manage inputs and feeds
in the open source energy, temperature and environmental monitoring sytem from
[OpenEnergyMonitor](https://openenergymonitor.org/).
emonCMS has two flavors, a self-hosted version and a hosted solution at
[emoncms.org](https://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.
## Installation
```{r eval=FALSE}
devtools::install_github("davidski/emoncmsr")
```
## Usage
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:
* EMONCMS_URI - Full URL (w/final slash) to API endpoint
* EMONCMS_API_KEY - API key value (read or write) to API
## Applications
Simulating a beverage sensor that monitors the level of coffee, tea, and
water available. First, we'll list the inputs currently configured.
```{r listing_inputs}
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!
```{r posting_to_inputs}
# 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.
```{r creating_the_coffee_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.
```{r demonstrate_input_to_feed_posting}
# 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](https://en.wikipedia.org/wiki/Thunderbirds_Are_Go)!
Let's pull a set of data from our feed and plot that data over time, adding
a smoothed curve for grins.
```{r plotting_feed_data}
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.
```{r clean_up}
list_feeds() %>% filter(tag == "emoncmsr") %>% pull(id) %>%
map(~ delete_feed(.x))
list_inputs() %>% filter(nodeid == "emoncmsr") %>% pull(id) %>%
map(~ delete_input(.x))
```
## Test results
```{r}
library(emoncmsr)
library(testthat)
date()
test_dir("tests/")
```
# Contributing
This project is governed by a [Code of Conduct](./CODE_OF_CONDUCT.md). By
participating in this project you agree to abide by these terms.
# License
The [MIT License](LICENSE) applies.