前言
我有一台nas,不过nas的硬盘风扇电源不知道接哪里最合适,因为接主板上,需要手动去控制转速。而接硬盘背板时,这样会一直满负荷运行,导致太吵了。
所以这里产生了一个想法,用arduino去控制风扇,再在nas里面去添加一个脚本,实时根据温度去发送应该的转速,然后使用pwm去控制风扇转速。
nas python脚本
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
# coding=utf-8
import os
import socket
from time import sleep
def get_temp():
temp = os.popen("ls -1 /dev/sd? | xargs -n1 smartctl -A | grep Celsius").read()
item_temp = temp.split('\n')
max_temp = 0
for item in item_temp:
if not item:
continue
split = item.split(' ')
index = split.index("(Min/Max")
item_temp = split[index - 1]
max_temp = max(int(item_temp), max_temp)
return max_temp
def convert(temp):
if temp > 44:
return 1000
elif temp < 35:
return 0
else:
return (temp - 35) * 100
sk = socket.socket() # 创建socket对象
sk.bind(("0.0.0.0", 9001)) # 绑定IP和端口
sk.listen() # 开启监听
print("start listen")
while 1: # 让服务端和客户端循环通信
conn, address = sk.accept() # 等待客户端连接 阻塞
print("accept client")
try:
while 1:
temp = get_temp()
send_msg = str(convert(temp))+'\n' # 要发送的消息
conn.send(send_msg.encode("utf-8")) # 发送消息给客户端
print("send temp success, current temp: " + str(temp) + "fan speed: " + send_msg)
sleep(1)
except OSError:
print("send to client error")
conn.close()
首先使用ls -1 /dev/sd? | xargs -n1 smartctl -A | grep Celsius
去获取当前所有硬盘的状态。根据获取到的值去进行拆分,获取到温度最大值。这里原计划是发送到公共的广播,但是esp8266的udp代码部分出现问题,所以改成还是用tcp实现了。这个可以添加为unraid的脚本,然后在array建立时直接运行。
arduino
这里使用的是esp8266,价格便宜,用在这里也算是大材小用了。
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
#include <ESP8266WiFi.h> // 本程序使用ESP8266WiFi库
const char* ssid = "xxxx-xxxx"; // 需要连接到的WiFi名
const char* password = "xxxxxxxx"; // 连接的WiFi密码
int gpio = 16; // D0
void setup() {
Serial.begin(115200); // 初始化串口通讯波特率为115200
analogWriteFreq(25000); // 频率设置为25kHz
analogWriteRange(1000); // 范围设置为1000
analogWrite(gpio, 1000);
WiFi.mode(WIFI_STA); // 设置Wifi工作模式为STA,默认为AP+STA模式
WiFi.begin(ssid, password); // 通过wifi名和密码连接到Wifi
Serial.print("\r\nConnecting to "); // 串口监视器输出网络连接信息
Serial.print(ssid); Serial.println(" ..."); // 显示NodeMCU正在尝试WiFi连接
int i = 0; // 检查WiFi是否连接成功
while (WiFi.status() != WL_CONNECTED) // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。
{ // 如果WiFi连接成功则返回值为WL_CONNECTED
delay(1000); // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值
Serial.print("waiting for ");
Serial.print(i++); Serial.println("s...");
}
Serial.println(""); // WiFi连接成功后
Serial.println("WiFi connected!"); // NodeMCU将通过串口监视器输出"连接成功"信息。
Serial.print("IP address: "); // 同时还将输出NodeMCU的IP地址。这一功能是通过调用
Serial.println(WiFi.localIP()); // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。
}
const char* host = "192.168.10.235";
const uint16_t port = 9001;
void loop() {
/* 新建一个WiFiClient类对象,作为TCP客户端对象 */
WiFiClient tcpclient;
/* 建立TCP连接 */
Serial.print("connecting to "); Serial.print(host); Serial.print(':'); Serial.println(port);
if (!tcpclient.connect(host, port)) {
Serial.println("connection failed"); // 如果连接失败,则打印连接失败信息,并返回
delay(3000);
return;
}
while (true)
{
String str = tcpclient.readStringUntil('\n');
if (str.length()==0)
{
// 读取失败时风扇满载运行
analogWrite(gpio, 1000);
break;
}
int value = str.toInt();
analogWrite(gpio, value);
Serial.println(str);
}
}
这里实现很简单,主要参考实例程序改写,首先是链接WiFi,然后接收服务端发送来的消息,然后根据传递过来的数字设置转速。