2023-11-20 10:07:46 -06:00
|
|
|
#setup ----
|
|
|
|
library(tidyverse)
|
|
|
|
library(influxdbclient)
|
|
|
|
library(rmarkdown)
|
2023-11-06 16:18:30 -06:00
|
|
|
|
2023-11-06 22:22:50 -06:00
|
|
|
if(Sys.info()[4] == "pseudotsuga") {
|
2023-11-06 22:16:25 -06:00
|
|
|
setwd("~/Documents/dataProjects/laundry_status")
|
|
|
|
} else {
|
|
|
|
setwd("/laundry_status")
|
|
|
|
}
|
2023-11-06 21:59:14 -06:00
|
|
|
Sys.setenv(TZ='America/Chicago')
|
2023-11-06 16:18:30 -06:00
|
|
|
# parameters needed to make connection to Database
|
2023-11-06 17:08:05 -06:00
|
|
|
token <- substr(read_file("data/api_key"), 1, 88)
|
2023-11-06 16:18:30 -06:00
|
|
|
org = "home_assistant"
|
|
|
|
bucket = "home_assistant"
|
|
|
|
## make connection to the influxDB bucket
|
|
|
|
home_assistant <- InfluxDBClient$new(url = "https://influxdb.dendroalsia.net",
|
|
|
|
token = token,
|
|
|
|
org = org)
|
2023-11-06 17:42:51 -06:00
|
|
|
update_interval <- 5
|
2023-11-07 09:29:01 -06:00
|
|
|
cronjob_interval <- 60
|
2023-11-21 14:06:51 -06:00
|
|
|
power_threshold_on <- 10
|
|
|
|
power_threshold_wash_door <- 4
|
|
|
|
power_threshold_dry_door <- 1.5
|
|
|
|
|
2023-11-06 16:18:30 -06:00
|
|
|
# ---- set variables
|
2023-11-20 10:05:57 -06:00
|
|
|
entities <- data.frame(name = c("washing machine", "dryer"), entity_id = c("washing_machine_power", "dryer_power"))
|
2023-11-06 16:18:30 -06:00
|
|
|
|
2023-11-21 11:24:27 -06:00
|
|
|
colors <- data.frame(value = c("off", "on"), color = c("#bcbcbc", "#b45f06"))
|
|
|
|
|
2023-11-21 08:25:42 -06:00
|
|
|
# Define a function to calculate the time difference
|
|
|
|
calculateTimeAgo <- function(eventTime) {
|
|
|
|
current <- Sys.time() # Get the current time
|
|
|
|
timeDiff <- as.duration(current - eventTime) # Calculate the time difference
|
|
|
|
|
|
|
|
# Convert the time difference to appropriate units and format the result
|
|
|
|
if (timeDiff >= hours(24)) {
|
|
|
|
result <- paste(round(timeDiff / dhours(24)), "days ago")
|
|
|
|
} else if (timeDiff >= hours(1)) {
|
|
|
|
result <- paste(round(timeDiff / dhours(1)), "hours ago")
|
|
|
|
} else if (timeDiff >= minutes(1)) {
|
|
|
|
result <- paste(round(timeDiff / dminutes(1)), "minutes ago")
|
|
|
|
} else {
|
|
|
|
result <- "Just now"
|
|
|
|
}
|
|
|
|
|
|
|
|
return(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
# ---- update_data function
|
2023-11-06 17:27:49 -06:00
|
|
|
update_data <- function(){
|
|
|
|
|
2023-11-07 14:18:26 -06:00
|
|
|
run_time <- Sys.time()
|
2023-11-20 10:05:57 -06:00
|
|
|
values <- home_assistant$query('from(bucket: "home_assistant") |> range(start: -7d) |> filter(fn: (r) => r["entity_id"] == "washing_machine_power" or r["entity_id"] == "dryer_power") |> filter(fn: (r) => r["_field"] == "value") |> filter(fn: (r) => r["_measurement"] == "W")',
|
2023-11-06 18:15:11 -06:00
|
|
|
POSIXctCol = NULL)
|
2023-11-06 17:27:49 -06:00
|
|
|
values <- bind_rows(values)
|
|
|
|
values <- values %>%
|
2023-11-06 18:15:11 -06:00
|
|
|
rename(value = "_value",
|
|
|
|
time = "_time")
|
2023-11-06 17:27:49 -06:00
|
|
|
values <- values %>%
|
2023-11-06 18:15:11 -06:00
|
|
|
mutate(
|
|
|
|
time = as.POSIXct(time, tz = "America/Chicago"),
|
2023-11-21 14:06:51 -06:00
|
|
|
status = ifelse(value > power_threshold_on, "on", "off")) %>%
|
|
|
|
mutate(door_threshold = ifelse(entity_id == "washing_machine_power", power_threshold_wash_door, power_threshold_dry_door)) %>%
|
|
|
|
mutate(door = ifelse(value < door_threshold, "open", "closed"))
|
2023-11-06 17:27:49 -06:00
|
|
|
|
2023-11-07 14:18:26 -06:00
|
|
|
values_by_entity <- as.list(NULL)
|
|
|
|
for(entity in entities$entity_id) {
|
|
|
|
values_by_entity[[entity]] <- values %>%
|
|
|
|
filter(entity_id %in% entity) %>%
|
|
|
|
mutate(end_time = c(time[-1], run_time))
|
|
|
|
}
|
|
|
|
values <- bind_rows(values_by_entity)
|
|
|
|
|
2023-11-21 14:06:51 -06:00
|
|
|
last_change <- values %>%
|
|
|
|
group_by(entity_id, status) %>%
|
|
|
|
slice_max(n = 1, order_by = time) %>%
|
|
|
|
pivot_wider(id_cols = domain, names_from = c(entity_id, status), values_from = time)
|
|
|
|
|
|
|
|
status_door <- values %>%
|
|
|
|
group_by(entity_id) %>%
|
|
|
|
slice_max(n = 1, order_by = time) %>%
|
|
|
|
select(entity_id, door) %>%
|
|
|
|
pivot_wider(names_from = entity_id, values_from = door)
|
2023-11-06 22:16:25 -06:00
|
|
|
|
2023-11-06 17:27:49 -06:00
|
|
|
current_status <- as.list(NULL)
|
|
|
|
for (entity in entities$entity_id){
|
2023-11-21 14:06:51 -06:00
|
|
|
current_status[[entity]] <- ifelse(values %>% filter(entity_id %in% entity) %>% tail(1) %>% pull(value) > power_threshold_on, "on", "off")
|
2023-11-06 17:27:49 -06:00
|
|
|
}
|
|
|
|
|
2023-11-21 11:07:47 -06:00
|
|
|
# ---- make plots
|
2023-11-21 08:39:10 -06:00
|
|
|
plot_1day <- ggplot(data = values %>% filter(time >= max(values$end_time) - hours(24))) +
|
2023-11-07 14:18:26 -06:00
|
|
|
geom_tile(aes(x = time + seconds(round(as.numeric(difftime(end_time, time, unit = "secs")))/2),
|
|
|
|
y = entity_id,
|
|
|
|
width = seconds(round(as.numeric(difftime(end_time, time, unit = "secs")))),
|
|
|
|
height = 0.5,
|
2023-11-06 17:27:49 -06:00
|
|
|
fill = status)) +
|
2023-11-07 14:18:26 -06:00
|
|
|
scale_y_discrete(breaks = entities$entity_id, labels = entities$name) +
|
2023-11-21 08:39:10 -06:00
|
|
|
scale_x_datetime(breaks = seq(round_date(max(values$end_time), "4 hours") - hours(24), round_date(max(values$end_time), "4 hours"), by = "4 hours"), date_labels = '%I:%M %p', date_minor_breaks = "1 hours") +
|
2023-11-21 11:24:27 -06:00
|
|
|
scale_fill_manual(values = colors$color) +
|
2023-11-06 17:27:49 -06:00
|
|
|
theme(axis.text.x = element_text(angle = 30, vjust = 0.5)) +
|
2023-11-21 08:39:10 -06:00
|
|
|
labs(title = "Last 24 hours",
|
2023-11-07 14:25:45 -06:00
|
|
|
x = NULL,
|
|
|
|
y = NULL,
|
|
|
|
fill = NULL)
|
2023-11-06 17:27:49 -06:00
|
|
|
|
2023-11-21 08:39:10 -06:00
|
|
|
plot_1week <- ggplot(data = values) +
|
2023-11-07 14:18:26 -06:00
|
|
|
geom_tile(aes(x = time + seconds(round(as.numeric(difftime(end_time, time, unit = "secs")))/2),
|
|
|
|
y = entity_id,
|
|
|
|
width = seconds(round(as.numeric(difftime(end_time, time, unit = "secs")))),
|
|
|
|
height = 0.5,
|
2023-11-06 17:27:49 -06:00
|
|
|
fill = status)) +
|
2023-11-07 14:18:26 -06:00
|
|
|
scale_y_discrete(breaks = entities$entity_id, labels = entities$name) +
|
2023-11-21 08:39:10 -06:00
|
|
|
scale_x_datetime(date_breaks = "1 day", date_labels = '%A', date_minor_breaks = "4 hours") +
|
2023-11-21 11:24:27 -06:00
|
|
|
scale_fill_manual(values = colors$color) +
|
2023-11-06 17:27:49 -06:00
|
|
|
theme(axis.text.x = element_text(angle = 30, vjust = 0.5)) +
|
2023-11-21 08:39:10 -06:00
|
|
|
labs(title = "The past week",
|
2023-11-07 14:25:45 -06:00
|
|
|
x = NULL,
|
|
|
|
y = NULL,
|
|
|
|
fill = NULL)
|
2023-11-06 17:27:49 -06:00
|
|
|
|
2023-11-21 11:07:47 -06:00
|
|
|
plot_1week_days <- ggplot(data = values %>%
|
|
|
|
filter(as.Date(time, tz = "America/Chicago") == as.Date(end_time, tz = "America/Chicago")) %>%
|
|
|
|
mutate(date = as.Date(time, tz = "America/Chicago")) %>%
|
|
|
|
left_join(. , entities, by = join_by(entity_id)) %>%
|
|
|
|
mutate(name = factor(name, levels = c("washing machine", "dryer")))) +
|
|
|
|
geom_rect(aes(xmin = date - hours(8),
|
|
|
|
xmax = date + hours(8),
|
|
|
|
ymin = ymd_hms(paste("2023-01-01", strftime(time, format = "%H:%M:%S"))),
|
|
|
|
ymax = ymd_hms(paste("2023-01-01", strftime(end_time, format = "%H:%M:%S"))),
|
|
|
|
fill = status)) +
|
|
|
|
facet_grid(name ~ .) +
|
|
|
|
scale_y_datetime(date_breaks = "4 hours", date_labels = '%I:%M %p', minor_breaks = "2 hours", expand = expansion(mult = 0)) +
|
|
|
|
scale_x_datetime(date_breaks = "1 day", date_labels = '%A', minor_breaks = NULL) +
|
2023-11-21 11:24:27 -06:00
|
|
|
scale_fill_manual(values = colors$color) +
|
2023-11-21 11:07:47 -06:00
|
|
|
theme(axis.text.x = element_text(angle = 30, vjust = 0.5)) +
|
|
|
|
labs(title = "The past week",
|
|
|
|
x = "Day",
|
|
|
|
y = "Time of Day",
|
|
|
|
fill = NULL)
|
|
|
|
|
|
|
|
# ---- generate html
|
2023-11-07 09:44:54 -06:00
|
|
|
render("laundry_status.Rmd",
|
|
|
|
output_dir = "html",
|
|
|
|
output_file = "index.html")
|
2023-11-20 10:07:46 -06:00
|
|
|
|
2023-11-06 17:27:49 -06:00
|
|
|
}
|
2023-11-06 16:18:30 -06:00
|
|
|
|
2023-11-20 12:29:41 -06:00
|
|
|
# for(i in 1:(cronjob_interval/update_interval)){
|
|
|
|
# message(Sys.time())
|
|
|
|
# update_data()
|
|
|
|
# Sys.sleep(60*update_interval)
|
|
|
|
# }
|
|
|
|
|
|
|
|
continue <- TRUE
|
|
|
|
while(continue){
|
2023-11-07 09:29:01 -06:00
|
|
|
message(Sys.time())
|
2023-11-06 17:27:49 -06:00
|
|
|
update_data()
|
2023-11-06 17:42:51 -06:00
|
|
|
Sys.sleep(60*update_interval)
|
2023-11-06 17:27:49 -06:00
|
|
|
}
|