laundry_status/laundry_status.R

319 lines
14 KiB
R
Raw Normal View History

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)
2024-01-28 22:00:25 -06:00
longterm_run_time <- ymd_hms("2024-01-01:00:00:00", tz = "America/Chicago")
2023-11-21 14:06:51 -06:00
power_threshold_on <- 10
2024-05-13 16:38:02 -05:00
power_threshold_wash_door <- 5
2023-11-21 14:06:51 -06:00
power_threshold_dry_door <- 1.5
2023-11-06 16:18:30 -06:00
# ---- set variables
2024-01-28 14:12:56 -06:00
entities <- data.frame(name = c("washing machine", "dryer"), entity_id = c("washing_machine_power", "dryer_power"), name_es = c("lavadora", "secadora"))
2023-11-06 16:18:30 -06:00
2023-11-22 11:25:35 -06:00
colors <- data.frame(value = c("off", "on"), color = c("#bcbcbc", "#008080"))
2023-11-21 11:24:27 -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)
}
2024-01-28 14:12:56 -06:00
calculateTimeAgo_es <- 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("hace", round(timeDiff / dhours(24)), "dias")
} else if (timeDiff >= hours(1)) {
result <- paste("hace", round(timeDiff / dhours(1)), "horas")
} else if (timeDiff >= minutes(1)) {
result <- paste("hace", round(timeDiff / dminutes(1)), "minutos")
} else {
result <- "Ahora"
}
return(result)
}
# ---- update_data function
2023-11-06 17:27:49 -06:00
update_data <- function(){
2024-01-28 14:12:56 -06:00
Sys.setlocale("LC_TIME", "en_US.UTF-8")
2023-11-06 17:27:49 -06:00
2023-11-07 14:18:26 -06:00
run_time <- Sys.time()
start_time <- floor_date(run_time - ddays(7), unit = "days")
values <- home_assistant$query(paste0('from(bucket: "home_assistant") |> range(start: ',
start_time,
') |> 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)) %>%
2023-11-28 07:51:21 -06:00
mutate(door = ifelse(value < door_threshold, "open", "closed")) %>%
filter(time >= start_time)
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
}
2024-01-28 14:12:56 -06:00
current_status <- bind_rows(current_status)
2024-01-28 22:00:25 -06:00
current_status_update <<- ifelse((current_status$washing_machine_power == "on")|(current_status$dryer_power) == "on", TRUE, FALSE)
2024-01-28 14:12:56 -06:00
## add spanish translations
current_status <- current_status %>%
mutate(dryer_power_es = ifelse(dryer_power == "on", "encendida", "apagada"),
washing_machine_power_es = ifelse(washing_machine_power == "on", "encendida", "apagada"))
2023-11-06 17:27:49 -06:00
2024-01-28 14:12:56 -06:00
status_door <- status_door %>%
mutate(dryer_power_es = ifelse(dryer_power == "open", "abierto", "cerado"),
washing_machine_power_es = ifelse(washing_machine_power == "open", "abierto", "cerado"))
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 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
2024-01-28 14:12:56 -06:00
Sys.setlocale("LC_TIME", "es_NI.UTF-8")
# ---- make plots (es)
plot_1day_es <- ggplot(data = values %>% filter(time >= max(values$end_time) - hours(24)) %>%
mutate(status = ifelse(status == "on", "encendida", "apagada"))) +
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,
fill = status)) +
scale_y_discrete(breaks = entities$entity_id, labels = entities$name_es) +
2024-01-28 14:43:00 -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 = '%H:%M', date_minor_breaks = "1 hours") +
2024-01-28 14:12:56 -06:00
scale_fill_manual(values = colors$color) +
theme(axis.text.x = element_text(angle = 30, vjust = 0.5)) +
labs(title = "Hace 24 horas",
x = NULL,
y = NULL,
fill = NULL)
plot_1week_days_es <- ggplot(data = values %>%
2024-01-28 14:50:59 -06:00
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_es, levels = c("lavadora", "secadora"))) %>%
mutate(status = ifelse(status == "on", "encendida", "apagada"))) +
2024-01-28 14:12:56 -06:00
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 ~ .) +
2024-01-28 14:43:00 -06:00
scale_y_datetime(date_breaks = "4 hours", date_labels = '%H:%M', minor_breaks = "2 hours", expand = expansion(mult = 0)) +
2024-01-28 14:12:56 -06:00
scale_x_datetime(date_breaks = "1 day", date_labels = '%A', minor_breaks = NULL) +
scale_fill_manual(values = colors$color) +
theme(axis.text.x = element_text(angle = 30, vjust = 0.5)) +
labs(title = "La semana pasada",
2024-01-28 14:43:00 -06:00
x = "Día",
2024-01-28 14:12:56 -06:00
y = "Tiempo",
fill = NULL)
render("laundry_status_es.Rmd",
output_dir = "html",
output_file = "es.html")
2023-11-06 17:27:49 -06:00
}
2023-11-06 16:18:30 -06:00
2024-01-17 13:55:13 -06:00
update_longterm_data <- function(){
2024-01-28 14:12:56 -06:00
Sys.setlocale("LC_TIME", "en_US.UTF-8")
2024-01-17 13:55:13 -06:00
run_time <- Sys.time()
2024-01-28 22:00:25 -06:00
longterm_run_time <<- run_time
2024-01-17 13:55:13 -06:00
start_time <- floor_date(run_time - ddays(365), unit = "days")
values <- home_assistant$query(paste0('from(bucket: "home_assistant") |> range(start: ',
start_time,
') |> 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")'),
POSIXctCol = NULL)
values <- bind_rows(values)
values <- values %>%
rename(value = "_value",
time = "_time")
values <- values %>%
mutate(
time = as.POSIXct(time, tz = "America/Chicago"),
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")) %>%
filter(time >= start_time)
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)
values["weekday"] <- wday(values$time, label = TRUE)
values["hourofday"] <- floor_date(ymd_hms(paste("2023_01_01",strftime(values$time, format="%H:%M:%S"))), unit = "hours")
long_term <- values %>%
filter(status =="on") %>%
group_by(weekday, hourofday, entity_id, status) %>%
summarise(count = n())
# ---- make plots
2024-01-23 15:44:23 -06:00
plot_all_week_days <- ggplot(data = long_term %>%
left_join(. , entities, by = join_by(entity_id)) %>%
mutate(name = factor(name, levels = c("washing machine", "dryer")))) +
2024-01-17 13:55:13 -06:00
geom_tile(aes(x = weekday,
y = hourofday,
alpha = count,
fill = status)) +
2024-01-23 15:44:23 -06:00
facet_grid(name ~ .) +
2024-01-17 13:55:13 -06:00
scale_y_datetime(date_breaks = "4 hours", date_labels = '%I:%M %p', minor_breaks = "2 hours", expand = expansion(mult = 0)) +
scale_x_discrete() +
2024-01-23 15:44:23 -06:00
scale_fill_manual(values = colors$color[2], guide = NULL) +
2024-01-17 13:55:13 -06:00
theme(axis.text.x = element_text(angle = 30, vjust = 0.5)) +
2024-01-23 15:44:23 -06:00
labs(title = "Long term trends",
subtitle = paste0("data from ",strftime(min(values$time), format = "%B %d, %Y"), " to ", strftime(run_time, format = "%B %d, %Y")),
2024-01-17 13:55:13 -06:00
x = "Weekday",
y = "Time of Day",
2024-01-23 15:44:23 -06:00
alpha = "Frequency")
2024-01-17 13:55:13 -06:00
# ---- generate html
render("laundry_longterm_data.Rmd",
output_dir = "html",
output_file = "longterm_data.html")
2024-01-28 14:12:56 -06:00
# ---- spanish translation
Sys.setlocale("LC_TIME", "es_NI.UTF-8")
values["weekday"] <- wday(values$time, label = TRUE)
values["hourofday"] <- floor_date(ymd_hms(paste("2023_01_01",strftime(values$time, format="%H:%M:%S"))), unit = "hours")
long_term <- values %>%
filter(status =="on") %>%
group_by(weekday, hourofday, entity_id, status) %>%
summarise(count = n())
# ---- make plots
plot_all_week_days_es <- ggplot(data = long_term %>%
left_join(. , entities, by = join_by(entity_id)) %>%
mutate(name = factor(name_es, levels = c("lavadora", "secadora")))) +
geom_tile(aes(x = weekday,
y = hourofday,
alpha = count,
fill = status)) +
facet_grid(name ~ .) +
2024-01-28 14:43:00 -06:00
scale_y_datetime(date_breaks = "4 hours", date_labels = '%H:%M', minor_breaks = "2 hours", expand = expansion(mult = 0)) +
2024-01-28 14:12:56 -06:00
scale_x_discrete() +
scale_fill_manual(values = colors$color[2], guide = NULL) +
theme(axis.text.x = element_text(angle = 30, vjust = 0.5)) +
labs(title = "Tendencias a largo plazo",
2024-01-28 14:50:59 -06:00
subtitle = paste0("datos desde el ",strftime(min(values$time), format = "%d de %B de %Y"), " hasta el ", strftime(run_time, format = "%d de %B de %Y")),
2024-01-28 14:12:56 -06:00
x = "Día de la semana",
y = "Tiempo",
alpha = "Frecuencia")
render("laundry_longterm_data_es.Rmd",
output_dir = "html",
output_file = "longterm_data_es.html")
2024-01-17 13:55:13 -06:00
}
2023-11-20 12:29:41 -06:00
continue <- TRUE
while(continue){
message(Sys.time())
2023-11-06 17:27:49 -06:00
update_data()
2024-01-28 22:00:25 -06:00
if (as.double(difftime(Sys.time(), longterm_run_time, units = "hours", tz = "America/Chicago")) > 24) {
2024-01-17 13:55:13 -06:00
update_longterm_data()
}
2024-01-28 22:00:25 -06:00
if (current_status_update == TRUE) {
message("sleeping for 1 minute")
Sys.sleep(60*1)
} else {
message("sleeping for 5 minutes")
Sys.sleep(60*5)
}
2024-01-17 13:55:13 -06:00
}