优化适用于Raspberry Pi 4 B
This commit is contained in:
12
.vscode/settings.json
vendored
Normal file
12
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp.errorSquiggles": "disabled",
|
||||||
|
"files.associations": {
|
||||||
|
"reboot_temperature.h": "c",
|
||||||
|
"stdio.h": "c",
|
||||||
|
"resource.h": "c",
|
||||||
|
"ctype.h": "c",
|
||||||
|
"unistd.h": "c",
|
||||||
|
"syscall.h": "c",
|
||||||
|
"reboot.h": "c"
|
||||||
|
}
|
||||||
|
}
|
22
Makefile
22
Makefile
@@ -1,12 +1,22 @@
|
|||||||
CROSS_COMPILE ?=
|
CROSS_COMPILE ?=
|
||||||
CC := $(CROSS_COMPILE)gcc
|
CC := $(CROSS_COMPILE)gcc
|
||||||
CFLAGS += -Wall -Os -g -L../libini -I../libini -fno-builtin
|
CFLAGS += -Wall -Os -g -I../libini -fno-builtin
|
||||||
LIB += -Wl,-rpath,/root/libini/ ../libini/libini.so
|
# 只链接静态库,不使用系统动态库
|
||||||
|
LDFLAGS += -static -L../libini
|
||||||
|
LIBS += ../libini/libini.a
|
||||||
BIN = boot
|
BIN = boot
|
||||||
|
|
||||||
all: reboot_temperature.o
|
all: libini $(BIN)
|
||||||
$(CC) $(CFLAGS) $^ -o $(BIN) $(LIB)
|
|
||||||
|
libini:
|
||||||
|
$(MAKE) -C ../libini CC=$(CC)
|
||||||
|
|
||||||
|
reboot_temperature.o: reboot_temperature.c reboot_temperature.h
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(BIN): reboot_temperature.o
|
||||||
|
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) $(LIBS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf *.o
|
rm -f *.o $(BIN)
|
||||||
rm $(BIN)
|
$(MAKE) -C ../libini clean
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
# reboot_temperature
|
# reboot_temperature
|
||||||
|
|
||||||
树莓派温度上限时重启或者关机, 第一时间保护硬件, 不处在温度上线过长时间
|
树莓派温度上限时重启或者关机, 第一时间保护硬件, 不处在温度上线过长时间
|
||||||
搭配libesmtp https://git.aixiao.me/aixiao/libesmtp 实现QQ邮件发送告警
|
搭配libesmtp https://git.aixiao.me/aixiao/libesmtp 实现QQ邮件发送告警
|
||||||
|
|
||||||
|
|
||||||
## Help Information
|
## Help Information
|
||||||
|
|
||||||
[global]
|
[global]
|
||||||
thermal_zone = "/sys/class/thermal/thermal_zone0/temp"; // 树莓派温度
|
thermal_zone = "/sys/class/thermal/thermal_zone0/temp"; // 树莓派温度
|
||||||
temperature = 90 // 温度上限
|
temperature = 90 // 温度上限
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
[global]
|
[global]
|
||||||
thermal_zone = "/sys/class/thermal/thermal_zone0/temp";
|
thermal_zone = "/sys/class/thermal/thermal_zone0/temp";
|
||||||
temperature = 70
|
temperature = 81
|
||||||
log_file = "boot.log";
|
log_file = "boot.log";
|
||||||
second = 30
|
second = 10
|
||||||
nice = -20
|
nice = -20
|
||||||
off_power = 0
|
off_power = 1
|
||||||
|
|
||||||
is_alert = 1
|
is_alert = 1
|
||||||
recv_mail = "1605227279@qq.com";
|
recv_mail = "aixiao@aixiao.me";
|
||||||
|
|
@@ -1,163 +1,204 @@
|
|||||||
#include "reboot_temperature.h"
|
#include "reboot_temperature.h"
|
||||||
|
|
||||||
static float get_temperature(char *path)
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/reboot.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char log_file[SIZE];
|
||||||
|
char recv_mail[SIZE];
|
||||||
|
char thermal_zone[SIZE];
|
||||||
|
int temperature;
|
||||||
|
int off_power;
|
||||||
|
int is_alert;
|
||||||
|
int second;
|
||||||
|
int nice;
|
||||||
|
} Config;
|
||||||
|
|
||||||
|
static float get_temperature(const char *path)
|
||||||
{
|
{
|
||||||
char buffer[SIZE];
|
FILE *fp = fopen(path, "r");
|
||||||
FILE *fp = NULL;
|
if (!fp) {
|
||||||
|
perror("fopen (temperature)");
|
||||||
|
return -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
if ((fp = fopen(path, "r")) < 0)
|
char buffer[64] = { 0 };
|
||||||
return -1; /* 文件不存在, 则退出. */
|
if (!fgets(buffer, sizeof(buffer), fp)) {
|
||||||
|
fclose(fp);
|
||||||
while (fgets(buffer, SIZE, fp) != NULL) ;
|
fprintf(stderr, "Failed to read temperature from %s\n", path);
|
||||||
|
return -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return atof(buffer) / (float)1000;
|
|
||||||
|
long raw_temp = strtol(buffer, NULL, 10);
|
||||||
|
if (raw_temp <= 0) {
|
||||||
|
fprintf(stderr, "Invalid temperature value: %ld\n", raw_temp);
|
||||||
|
return -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return raw_temp / 1000.0f; // 转换为摄氏度
|
||||||
}
|
}
|
||||||
|
|
||||||
static int error_log(float l_t, int c_t, char *log_file, char *recv_mail, int _is, int _alert)
|
#include <stdio.h>
|
||||||
{
|
#include <stdlib.h>
|
||||||
time_t tmpcal_ptr = 0;
|
|
||||||
struct tm *tmp_ptr = NULL;
|
|
||||||
FILE *fp = NULL;
|
|
||||||
FILE *fd = NULL;
|
|
||||||
char buffer[SIZE+1024+270];
|
|
||||||
char temperature[SIZE+1024];
|
|
||||||
char hostname[SIZE];
|
|
||||||
|
|
||||||
memset(buffer, 0, SIZE+1024+270);
|
int send_alert_email(const char *recipient, float current_temp, float threshold) {
|
||||||
memset(temperature, 0, SIZE+1024);
|
if (!recipient || recipient[0] == '\0') {
|
||||||
memset(hostname, 0, SIZE);
|
fprintf(stderr, "No recipient email provided\n");
|
||||||
|
return -1;
|
||||||
time(&tmpcal_ptr);
|
|
||||||
tmp_ptr = localtime(&tmpcal_ptr);
|
|
||||||
|
|
||||||
if (gethostname(hostname, SIZE) != 0)
|
|
||||||
{
|
|
||||||
perror("gethostname");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = fopen(log_file, "a+");
|
char command[2048];
|
||||||
if (fd == NULL)
|
snprintf(command, sizeof(command),
|
||||||
|
"gomail -r %s -s \"RaspberryPi Temperature Alert\" "
|
||||||
|
"-t \"CPU Temperature: %.3f°C\nThreshold: %.3f°C\n\"",
|
||||||
|
recipient, current_temp, threshold);
|
||||||
|
|
||||||
|
printf("Executing email command:\n%s\n", command);
|
||||||
|
|
||||||
|
FILE *fp = popen(command, "r");
|
||||||
|
if (!fp) {
|
||||||
|
perror("popen (send_alert_email)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 可选:读取命令输出进行日志记录或调试
|
||||||
|
char buf[256];
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
printf("%s", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = pclose(fp);
|
||||||
|
if (status == -1) {
|
||||||
|
perror("pclose");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||||
|
fprintf(stderr, "gomail exited with code %d\n", WEXITSTATUS(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int log_error(float cpu_temp, int threshold, const Config *config, int alert)
|
||||||
|
{
|
||||||
|
time_t now = time(NULL);
|
||||||
|
struct tm *tm_info = localtime(&now);
|
||||||
|
char hostname[SIZE] = { 0 };
|
||||||
|
gethostname(hostname, SIZE);
|
||||||
|
|
||||||
|
FILE *fd = fopen(config->log_file, "a+");
|
||||||
|
if (!fd)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// 写入日志文件FD
|
fprintf(fd, "[%d-%02d-%02d %02d:%02d:%02d] %s CPU Temperature: %.3f°C, Threshold: %.3f°C\n", 1900 + tm_info->tm_year, tm_info->tm_mon + 1, tm_info->tm_mday, tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec, hostname, cpu_temp, (float)threshold);
|
||||||
fprintf(fd, "[%d.%d.%d %d:%d:%d] %s %s %.3f℃, %s %.3f℃\n", (1900 + tmp_ptr->tm_year), (1 + tmp_ptr->tm_mon), tmp_ptr->tm_mday, tmp_ptr->tm_hour, tmp_ptr->tm_min, tmp_ptr->tm_sec, hostname, "CPU temperature", l_t, "Restartable or shutdown temperature", (float)c_t);
|
|
||||||
|
|
||||||
if (_is == 1)
|
|
||||||
{
|
|
||||||
if (_alert == 1)
|
|
||||||
{
|
|
||||||
// 关机重启时
|
|
||||||
snprintf(temperature, SIZE+1024, "[%d.%d.%d %d:%d:%d] %s %s %.3f℃, %s %.3f℃\n", (1900 + tmp_ptr->tm_year), (1 + tmp_ptr->tm_mon), tmp_ptr->tm_mday, tmp_ptr->tm_hour, tmp_ptr->tm_min, tmp_ptr->tm_sec, hostname, "CPU temperature", l_t, "Restartable or shutdown temperature",
|
|
||||||
(float)c_t);
|
|
||||||
snprintf(buffer, SIZE+1024+270, "gomail -r %s -s \"Raspberrypi Temperature\" -t \"%s\"", recv_mail, temperature);
|
|
||||||
fp = popen(buffer, "r");
|
|
||||||
pclose(fp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 正常温度时
|
|
||||||
if (tmp_ptr->tm_min >= 10 && tmp_ptr->tm_min < 12)
|
|
||||||
{
|
|
||||||
snprintf(temperature, SIZE+1024, "[%d.%d.%d %d:%d:%d] %s %s:%.3f℃\n", (1900 + tmp_ptr->tm_year), (1 + tmp_ptr->tm_mon), tmp_ptr->tm_mday, tmp_ptr->tm_hour, tmp_ptr->tm_min, tmp_ptr->tm_sec, hostname, "CPU temperature", l_t);
|
|
||||||
snprintf(buffer, SIZE+1024+270, "gomail -r %s -s \"Raspberrypi Temperature\" -t \"%s\"", recv_mail, temperature);
|
|
||||||
fp = popen(buffer, "r");
|
|
||||||
while (fgets(buffer, SIZE, fp) != NULL) {
|
|
||||||
fprintf(stdout, "%s", buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
pclose(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
fd = NULL;
|
|
||||||
|
if (config->is_alert && alert) {
|
||||||
|
send_alert_email(config->recv_mail, cpu_temp, (float)threshold);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_executable_path(char *processdir, char *processname, int len)
|
static int get_executable_path(char *processdir, char *processname, int len)
|
||||||
{
|
{
|
||||||
char *filename;
|
|
||||||
|
|
||||||
if (readlink("/proc/self/exe", processdir, len) <= 0)
|
if (readlink("/proc/self/exe", processdir, len) <= 0)
|
||||||
return -1;
|
return -1;
|
||||||
filename = strrchr(processdir, '/');
|
char *filename = strrchr(processdir, '/');
|
||||||
if (filename == NULL)
|
if (!filename)
|
||||||
return -1;
|
return -1;
|
||||||
++filename;
|
strcpy(processname, ++filename);
|
||||||
strcpy(processname, filename);
|
|
||||||
*filename = '\0';
|
*filename = '\0';
|
||||||
|
|
||||||
return (int)(filename - processdir);
|
return (int)(filename - processdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[], char **env)
|
int main()
|
||||||
{
|
{
|
||||||
char buffer[SIZE];
|
Config config;
|
||||||
char log_file[SIZE];
|
memset(&config, 0, sizeof(config));
|
||||||
char *inifile = "conf/config.ini";
|
|
||||||
char path[SIZE] = { 0 };
|
|
||||||
|
|
||||||
char recv_mail[SIZE] = { 0 };
|
char executable_path[SIZE] = { 0 };
|
||||||
char executable_filename[SIZE] = { 0 };
|
char executable_name[SIZE] = { 0 };
|
||||||
(void)get_executable_path(path, executable_filename, sizeof(path));
|
char config_file[SIZE];
|
||||||
inifile = strcat(path, inifile);
|
|
||||||
|
|
||||||
|
strcpy(config_file, "reboot.ini");
|
||||||
|
get_executable_path(executable_path, executable_name, sizeof(executable_path));
|
||||||
|
|
||||||
if (-1 == access(inifile, F_OK)) { // 如果配置不存在
|
if (access(config_file, F_OK) == -1)
|
||||||
inifile="/etc/reboot_temperature.ini";
|
{
|
||||||
|
if (snprintf(config_file, SIZE, "%sconf/reboot.ini", executable_path) >= SIZE) {
|
||||||
|
fprintf(stderr, "Config file path too long\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access(config_file, F_OK) == -1)
|
||||||
|
strcpy(config_file, "/etc/reboot.ini");
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(buffer, 0, SIZE);
|
// Load configuration values
|
||||||
memset(log_file, 0, SIZE);
|
getinikeystring("global", "thermal_zone", config_file, config.thermal_zone);
|
||||||
memset(recv_mail, 0, SIZE);
|
getinikeystring("global", "log_file", config_file, config.log_file);
|
||||||
|
getinikeystring("global", "recv_mail", config_file, config.recv_mail);
|
||||||
|
config.temperature = getinikeyint("global", "temperature", config_file);
|
||||||
|
config.off_power = getinikeyint("global", "off_power", config_file);
|
||||||
|
config.is_alert = getinikeyint("global", "is_alert", config_file);
|
||||||
|
config.second = getinikeyint("global", "second", config_file);
|
||||||
|
config.nice = getinikeyint("global", "nice", config_file);
|
||||||
|
|
||||||
|
/*
|
||||||
|
puts(config.thermal_zone);
|
||||||
|
puts(config.log_file);
|
||||||
|
puts(config.recv_mail);
|
||||||
|
|
||||||
|
printf("%d\n", config.temperature);
|
||||||
|
printf("%d\n", config.off_power);
|
||||||
|
printf("%d\n", config.is_alert);
|
||||||
|
printf("%d\n", config.second);
|
||||||
|
printf("%d\n", config.nice);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
*/
|
||||||
|
|
||||||
if (daemon(1, 1) == -1) {
|
if (daemon(1, 1) == -1) {
|
||||||
perror("daemon");
|
perror("daemon");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 == (nice(getinikeyint("global", "nice", inifile)))) // 进程优先级
|
errno = 0;
|
||||||
|
if (nice(config.nice) == -1 && errno != 0) {
|
||||||
perror("nice");
|
perror("nice");
|
||||||
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
getinikeystring("global", "thermal_zone", inifile, buffer); // 获取thermal_zone路径
|
|
||||||
getinikeystring("global", "log_file", inifile, log_file); // 获取日志文件名
|
|
||||||
getinikeystring("global", "recv_mail", inifile, recv_mail); // 获取接收者邮箱
|
|
||||||
|
|
||||||
if (get_temperature(buffer) >= getinikeyint("global", "temperature", inifile)) // 达到重启或者关机温度
|
|
||||||
{
|
|
||||||
sync();
|
|
||||||
sync();
|
|
||||||
if (getinikeyint("global", "off_power", inifile) == 1)
|
|
||||||
{
|
|
||||||
error_log(get_temperature(buffer), getinikeyint("global", "temperature", inifile), log_file, recv_mail, getinikeyint("global", "is_alert", inifile), 1);
|
|
||||||
return reboot(RB_POWER_OFF); // 关机
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getinikeyint("global", "off_power", inifile) == 0)
|
|
||||||
{
|
|
||||||
error_log(get_temperature(buffer), getinikeyint("global", "temperature", inifile), log_file, recv_mail, getinikeyint("global", "is_alert", inifile), 1);
|
|
||||||
return reboot(RB_AUTOBOOT); // 重启
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else // 未达到重启或者关机温度
|
|
||||||
{
|
|
||||||
error_log(get_temperature(buffer), getinikeyint("global", "temperature", inifile), log_file, recv_mail, getinikeyint("global", "is_alert", inifile), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 等待
|
|
||||||
sleep(getinikeyint("global", "second", inifile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
float current_temp = get_temperature(config.thermal_zone);
|
||||||
|
if (current_temp >= config.temperature) {
|
||||||
|
sync();
|
||||||
|
sync();
|
||||||
|
log_error(current_temp, config.temperature, &config, 1);
|
||||||
|
|
||||||
|
if (config.off_power == 0) {
|
||||||
|
return reboot(RB_POWER_OFF); // 关机
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.off_power == 1) {
|
||||||
|
return reboot(RB_AUTOBOOT); // 重启
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log_error(current_temp, config.temperature, &config, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(config.second);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -4,12 +4,13 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/reboot.h>
|
|
||||||
#include "libini.h"
|
|
||||||
|
|
||||||
|
#include <linux/reboot.h> /* Definition of LINUX_REBOOT_* constants */
|
||||||
|
#include <sys/syscall.h> /* Definition of SYS_* constants */
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "libini.h"
|
||||||
|
|
||||||
#define SIZE 1024
|
#define SIZE 1024
|
||||||
|
|
||||||
|
BIN
reboot_temperature.o
Normal file
BIN
reboot_temperature.o
Normal file
Binary file not shown.
Reference in New Issue
Block a user