September 21, 2022

Визуализируем данные мониторинга температуры процессора Rapsberry PI Zero W

Прошлый пост был посвящен автоматическому скачиванию и подготовке данных о погоде в регионах России для создания интерактивной плиточной карты РФ. Для автоматического обновления данных используется скрипт на языке R, который выполняется по расписанию (ежедневно каждые три часа) на моем маленьком домашнем устройстве — Raspberry PI Zero W.

Маленький домашний помощник, работающий в режиме 24/7

Исходные данные: cpu_temp.log

В этот раз мы будем визуализировать данные поминутного изменения температуры процессора Raspberry PI, которые сохраняются в специальным лог-файле c помощью bash-скрипта:

#!/bin/bash
date +"%d.%m.%Y %T" | tr '\n' '\t' >> /home/pi/cpu_temp.log ; vcgencmd measure_temp| tr -d "temp=" | tr -d "'C" >> /home/pi/cpu_temp.log

Для запуска bash-скрипта по расписанию через cron была добавлена запись (каждую минуту):

*/1 * * * * ~/cpu_temp.sh

В результате выполнения скрипта данные о температуре процессора сохраняются в лог:

Эти данные мы и будем визуализировать с помощью R (cpu_temp.R), лого для вставки на график: https://disk.yandex.ru/d/dP16Vwq9sH6RNQ

library(tidyverse)
library(readr)
library(geomtextpath)
library(glue)
library(here)
# Загружаем логотип Raspberry Pi
# лого: https://disk.yandex.ru/d/dP16Vwq9sH6RNQ
png <- magick::image_read("raspberrypi-logo.png")
img <- grid::rasterGrob(png, interpolate = TRUE)
# Загружаем данные (лог температуры)
cpu_temp <- read_delim(
    "cpu_temp.log",
    delim = "\t",
    col_names = c("datetime", "cpu_temp"),
    trim_ws = TRUE) %>%
  mutate(datetime = lubridate::as_datetime(datetime,
                                           "%d.%m.%Y %H:%M:%S",
                                           tz = "Asia/Yekaterinburg"))
# Временной интервал для графика -- последние 3 часа из лога
last_datetime <- cpu_temp$datetime[length(cpu_temp$datetime)]
first_datetime <- last_datetime - lubridate::hours(3)
# Описательные для графика (мин, макс, среднее)
maxTempCPU <- max(cpu_temp$cpu_temp[between(cpu_temp$datetime,
                                            first_datetime, last_datetime)])
minTempCPU <- min(cpu_temp$cpu_temp[between(cpu_temp$datetime,
                                            first_datetime, last_datetime)])
meanTempCPU_period <-
  round(mean(cpu_temp$cpu_temp[between(cpu_temp$datetime,
                                       first_datetime, last_datetime)]), 1)
# для вставки лого
# mt <- ceiling(max(cpu_temp$cpu_temp[between(cpu_temp$datetime,
                                            # first_datetime, last_datetime)]))
mt <- ceiling(max(cpu_temp$cpu_temp))
mt_min <- floor(min(cpu_temp$cpu_temp))
x_max <- last_datetime + lubridate::minutes(25)
x_min <- last_datetime + lubridate::minutes(10)

cpu_temp %>%
  filter(between(datetime, first_datetime, last_datetime)) %>%
  ggplot(aes(datetime, cpu_temp)) +
  annotation_custom(
    img,
    ymin = mt ,
    ymax = mt + 8.25,
    xmin = x_min,
    xmax = x_max
  ) +
  geom_texthline(
    yintercept = mean(cpu_temp$cpu_temp),
    size = 3.75,
    linetype = "dashed",
    linewidth = 0.25,
    label = glue("Среднее за всё время: <b>{round(mean(cpu_temp$cpu_temp),1)}</b>°C"),
    hjust = 0.985,
    vjust = -0.2,
    color = "gray70",
    rich = TRUE
  ) +
  geom_texthline(
    yintercept = meanTempCPU_period,
    size = 3.75,
    linewidth = 0.25,
    label = glue("Среднее за 3 часа: <b>{meanTempCPU_period}</b>°C"),
    hjust = 0.985,
    vjust = -0.2,
    color = "gray70",
    rich = TRUE
  ) +
  geom_step(color = "gray10") +
  scale_y_continuous(
    breaks = seq(mt_min, mt + 1, 2),
    limits = c(mt_min, mt + 1),
    labels = c(as.character(seq(mt_min, mt - 1, 2)),
               glue::glue("{mt + 1}°C"))
  ) +
  scale_x_datetime(
    "Время",
    date_breaks = "30 min",
    date_labels = "%H:%M",
    expand = c(0.15, 0)
  ) +
  labs(
    title = "Температура процессора Raspberry Pi Zero W",
    subtitle = glue(
      "Поминутное изменение температуры за последние 3 часа\n",
      "{format(first_datetime, format = '%d %b %H:%M')} - {format(last_datetime, format = '%H:%M')}",
      " | Мин {minTempCPU}°C | Среднее {meanTempCPU_period}°C | Макс {maxTempCPU}°C"
    ),
    x = "Время",
    y = ""
  ) +
  coord_cartesian(clip = "off") +
  theme(text = element_text(family = "Open Sans"),
        panel.background = element_blank(),
        axis.title.x = element_text(size = 14),
        plot.margin = margin(25, 30, 10, 12),
        plot.title.position = "plot",
        plot.subtitle = element_text(size = 12, color = "gray60"),
        title = element_text(size = 16),
        axis.text.y = element_text(size = 12),
        axis.text.x = element_text(size = 12)
  )
ggsave(
  glue("img/cpu_temp_{format(last_datetime, '%d_%m_%Y_%H_%M')}.png"),
  dpi = 300,
  scale = 1.5
)

Для запуска скрипта каждые три часа создадим задачу в cron:

0 */3 * * * Rscript /home/pi/cpu_temp/cpu_temp_pi.R

Полученный график будем отправлять себе в телеграм через телеграм-бота, созданного специально для отправки личных уведомлений простой командой в конце нашего скрипта:

bot$sendPhoto(chat_id,
              photo = glue("~/cpu_temp/img/cpu_temp_{format(last_datetime, '%d_%m_%Y_%H_%M')}.png")
)

Мой телеграм-канал: https://t.me/weekly_charts