- 作者:
- 分类:项目&制作->小制作
- 阅读:6565
- 点赞:21
- 难度:
- 版权:CC BY-SA 4.0
- 创建:2019-10-15
- 更新:2024-02-28
原文链接(持续更新):https://neucrack.com/p/190
本文章介绍了如何使用 ESP32 + 自己写代码和部署服务器实现远程控制和查看电脑开关机状态,原理是通过 ESP32 的引脚控制开关机按钮,甚至可以强制关机
另外,你可能觉得自己写代码,并且部署服务器很麻烦,可以看 用 ESP32 + 腾讯云explorer + 腾讯练练小程序30分钟实现远程硬开关机(非WOL方式) 这篇文章,不需要写代码(用我写好的代码),只需要开通免费的腾讯云 explorer 服务,就可以使用微信小程序腾讯练练控制和查看电脑开关机状态了,同理可以用到任何远程开关
原理
控制开关及
机箱的开关及按钮连接到主板的两个引脚: Power+
和 Power-
, 也可以说是Power Out
和Power In
, 平时两个引脚的连接是断开的,当机箱按钮按下短路, Power-
是主板的 开关机检测引脚, 主板检测当这个引脚高电平的时间超过一定时间(t1
)就开关机, 若发现是长按(时间t2
),则强制关机
所以我们只需要用单片机去控制向Power In
输入高电平即可(注意共地)
读取主机开机状态
主板会有一对(PLED+
和PLED-
)甚至更多对引脚来指示开关机状态,一般会被连接到机箱的开关机指示灯, 通过PLED+
的电平就可以知道主机是开机(高电平)还是关机(低电平)了
所以我们只需要用单片机去读取PLED+
的电平即可(注意共地),是高电平就表示是开机状态
系统组成
硬件
ESP32 + 杜邦线 + 插针: ESP32非常便宜性能又高,最关键的是集成的 2.4G
WiFi
硬件和协议栈, 而且支持 Micropython
编程,可以在非常短的时间内完成本设计
电路
通过USB
共地, 也可以接PLED-
到ESP32
的GND
更新:这里原理图画得比较潦草,如zean1987 指出,这里 PLED+ 输出的是 5v 电压,可能会让 3.3v 耐受的 GPIO 被烧,虽然 ESP32 这样接也能用,但是官方文档是没有说 5v 耐受的,所以最好加个电压转换电路,最简单的就是用一个或者两个电阻分压一下,当然实测 ESP32-S 直接接也能耐受。
系统通信网络(序列图)
制作步骤
按照精简电路图搭建硬件电路
下载 Micropython 固件并按照说明更新到开发板
编写
Micropython
程序,使用MQTT
与云端建立长连接,定时向某个主题(topic1
)上传状态,订阅某个主题(topic2
),制定自己的协议,最好对数据进行加密,根据接收到的数据来决定采取什么动作编写服务器程序,订阅发布硬件状态的
MQTT
主题topic1
,这样就可以获得开关机状态了,并且用一个接口来接受我们(用户)发送的开关机命令或者查询命令编写前端应用,比如
Android
应用,然后对接服务器的API
,达到可以控制开关机的目的。当然,最好服务器采用带用户界面的WEB
应用,这样就直接访问网页操作就好了,最好做权限控制,以及加密通信到这里基本就完成了
其它
配合 teamviewer
设置开机自启使用就可以随时随地使用自己的电脑啦~~
代码
木有现成的工程噢嘿嘿嘿
贴个简单的框架代码吧(无法直接使用)
ESP32:
client = MQTTClient(CLIENT_ID, SERVER)
g_power_status = machine.Pin(21, machine.Pin.IN, 0)
g_power_control = machine.Pin(22, machine.Pin.OUT, 0)
def power_status():
global g_power_status
return g_power_status.value()
def power_on():
global g_power_control
g_power_control.value(1)
time.sleep(1.5)
g_power_control.value(0)
def power_off():
global g_power_control
g_power_control.value(1)
time.sleep(1.5)
g_power_control.value(0)
def power_off_force():
global g_power_control
g_power_control.value(1)
time.sleep(6)
g_power_control.value(0)
def sub_cb(topic, msg):
print((topic, msg))
if topic == TOPIC_DOWN:
if msg == b"on":
print("receive power on")
power_on()
elif msg == b"off":
print("receive power off")
power_off()
elif msg == b"off force":
print("receive power off force")
power_off_force()
elif msg == b"status":
print("receive status")
upload = b'{"power":%d}' %(power_status())
print("upload:", upload)
client.publish(TOPIC_UP, upload )
def main():
global client
client.set_callback(sub_cb)
client.connect()
client.subscribe(TOPIC_UP)
client.subscribe(TOPIC_DOWN)
print("Connected to %s, subscribed to %s and %s topic" % (SERVER, TOPIC_UP, TOPIC_DOWN))
try:
while 1:
client.wait_msg()
finally:
client.disconnect()
if __name__ == "__main__":
t = Thread(target=upload_thread)
t.start()
try:
main()
except Exception as e:
machine.reset()
服务器:
以 Flask
为例,同样没有加密过程,大概上是这样的:
app = Flask(__name__)
@app.route('/set')
def set():
cmd = request.args.get("cmd")
if cmd == None:
cmd = "param error cmd"
else:
mqtt_client.publish(TOPIC_DOWN, cmd)
return cmd
@app.route('/get')
def get_status():
global device_status
mqtt_client.publish(TOPIC_DOWN, "status")
return device_status
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe(TOPIC_UP)
print("subscribe topic succss")
global isConnected
isConnected = True
print("connected")
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
print(len(msg.payload))
timeNow = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
print(timeNow+":"+msg.topic+" "+str(msg.payload))
if msg.topic == TOPIC_UP:
global device_status
device_status = timeNow + ": " + msg.payload.decode('utf-8')
def web_task():
app.run(host="0.0.0.0", port=12345)
def mqtt_task():
client = mqtt.Client(
client_id="RPCC_server2",
clean_session=True,
userdata=None,
# protocol=MQTTv311
)
global mqtt_client
mqtt_client = client
client.on_connect = on_connect
client.on_message = on_message
print("connect mqtt")
client.connect("mqtt.com", 1883, 60)
print("connect mqtt end")
client.loop_forever()
if __name__ == "__main__":
t = threading.Thread(target=web_task)
t.setDaemon(True)
t.start()
mqtt_task()
然后打开浏览器输入.../get
就可以得到状态了,.../set?cmd=on
就可以开机了