文章目录
  1. 1. 准备零件
  2. 2. 电路图
  3. 3. NodeMCU 端的实现细节
  4. 4. 服务端
    1. 4.1. 控制界面

之前一直想拿 nodemcu 做个远程控制电脑开关的东西,当时配件没买齐,实现到一半就扔在那边放了好久,用着小米路由器的远程唤醒功能。不过使用网卡的远程唤醒在停电后就无法再通过远程唤醒了,而且死机后也没办法强制关机。
前两天搬到新家后,因为小米路由器留给老家了,所以又把 nodemcu 拿起来做这个远程开关机的东西。

准备零件

  1. nodemcu 1个
  2. s9013 NPN三极管1个
  3. 杜邦线若干
  4. 1k 色环电阻1个

电路图

连接 D1S9013 三极管的基极,中间串一个 1k 电阻,然后将主板的 Power SW 的正极接到集电极上,发射极接到 NodeMCU 的 GND上,组成一个三极管开关,使 GPIO1 的高电平可以打开主板的电源开关。

原来的机箱开关接到 D2 上,并将另一边接到 3.3V 上,以便实现高电平触发。

NodeMCU 端的实现细节

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
print('Setting up WIFI...')
wifi.setmode(wifi.STATION)
wifi.sta.config('ssid', 'password')
wifi.sta.autoconnect(1)

print('Waiting for IP ...')
tmr.alarm(1, 1000, tmr.ALARM_AUTO, function()
if wifi.sta.getip() ~= nil then
print('IP is ' .. wifi.sta.getip())
tmr.stop(1)
mqttStart() -- 当 IP 获取到时连接 MQTT Server
end
end)

POWER_SWITCH_PIN = 1 -- 控制电脑的电源开关输出
POWER_BUTTON_PIN = 2 -- 电源按钮输入

function mqttStart()
m = mqtt.Client("nas_switch", 120, "iot user", "iot password")

-- 成功连接 MQTT Server 时设置 lwt ,订阅相关的 topic
m:on('connect', function(client)
print("mqtt connected" )
-- 设置 lwt ,让设备掉线时自动通知服务器
m:lwt('iot/nas/server', '{"op":"offline"}', 2)
-- 订阅 topic
m:subscribe('iot/nas/eq', 0)
-- 保持心跳,防止长时间不通信断开
keepliveStatus(m)
end)

-- 处理接收到服务器的消息
m:on("message", function(client, topic, data)
print(topic .. ":" )
if data ~= nil then
local action = cjson.decode(data)
-- 实现开机关机功能
if action.op == 'power' then
gpio.write(POWER_SWITCH_PIN, gpio.HIGH)
-- 先停止按钮的计时器,机箱的开关检查使用了 tmr 3 这个计时器
tmr.stop(3)
-- 按一下开关,模拟平时的开机按钮动作,400ms 就可以让我的 nas 开机
tmr.create():alarm(400, tmr.ALARM_SINGLE, function()
gpio.write(POWER_SWITCH_PIN, gpio.LOW)
tmr.start(3)
end)
elseif action.op == 'power15' then
gpio.write(POWER_SWITCH_PIN, gpio.HIGH)
tmr.stop(3)
-- 模拟长按电源按钮15秒,实现强制关机
tmr.create():alarm(15000, tmr.ALARM_SINGLE, function()
gpio.write(POWER_SWITCH_PIN, gpio.LOW)
tmr.start(3)
end)
end
print(data)
end
end)

m:on('offline', function(client)
print("mqtt disconnect")
end)

-- 连接服务器,自动重连,服务器地址可以使用共公的,也可以自己用 mosquitto 架一个
m:connect('iot.eclipse.com', 1883, 0, 1)
end

-- 上传当前的开机状态 60s
function keepliveStatus(m)
-- 先上传一次,然后每60秒上传一次
upStatus(m)
tmr.alarm(1, 60000, tmr.ALARM_AUTO, function()
upStatus(m)
end)
end

-- 上传当前电脑的开机状态
function upStatus(m)
-- TODO: 由于用万用表测量了主板的 `Power LED` 后发现开机后电压是 3.3V 和 8.3V ,关机时是 3.3v 和 3.3v。无法使用 gpio 直接读取,后来想到使用 5v 继电器模块正好,但手头上没有,这个功能就暂时不实现了。
m:publish("iot/nas/server", '{"op":"status","data":"close"}', 1, 0)
end

-- 设置实体按钮
function setupButton(pin)
-- 重置按钮状态
local function resetButton()
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.LOW)
gpio.mode(pin, gpio.INPUT)
end
resetButton()
tmr.alarm(3, 10, tmr.ALARM_AUTO, function()
local level = gpio.read(pin)
if level == gpio.HIGH then
gpio.write(POWER_SWITCH_PIN, gpio.HIGH)
else
gpio.write(POWER_SWITCH_PIN, gpio.LOW)
end
resetButton()
end)
end

setupButton(POWER_BUTTON_PIN)

暂时没有实现实时显示当前的开机状态,手头上缺少继电器模块,下次有别的东西要做的时候再去批量买一点回来,继电器可以使用下面的这种 5V 的,正好可以将电脑的开机 LED 灯状态转换成 GPIO 能获取的信号。

服务端

服务端我用了 golang 开发,配合 github.com/eclipse/paho.mqtt.golang 这个客户端与设备通信。控制界面用了 websocket 实现实时显示当前开机状态,不过由于缺少配件,功能残废。

控制界面

文章目录
  1. 1. 准备零件
  2. 2. 电路图
  3. 3. NodeMCU 端的实现细节
  4. 4. 服务端
    1. 4.1. 控制界面