选中内容(绿色)时除了会搜索文章名,还会搜索文章内容
点击结果中的文章名进入文章界面后可以按Ctrl+F在页面内搜索
  • 版权:CC BY-SA 4.0
  • 创建:2019-10-15
  • 更新:2024-02-28
远程开关及功能, 而且是直接控制主机开关机键, 而不是使用 `Wake On LAN(WOL)` 的功能, 这样的好处是有绝对的控制权,就算电脑死机,也可以触发长按强制关机的命令,而且也不会出现`WOL`的有时候无法唤醒的问题; 缺点就是需要改硬件(其实就是改一下主板上的针脚插接线路而已,很简单)


本文章介绍了如何使用 ESP32 + 自己写代码和部署服务器实现远程控制和查看电脑开关机状态,原理是通过 ESP32 的引脚控制开关机按钮,甚至可以强制关机

另外,你可能觉得自己写代码,并且部署服务器很麻烦,可以看 用 ESP32 + 腾讯云explorer + 腾讯练练小程序30分钟实现远程硬开关机(非WOL方式) 这篇文章,不需要写代码(用我写好的代码),只需要开通免费的腾讯云 explorer 服务,就可以使用微信小程序腾讯练练控制和查看电脑开关机状态了,同理可以用到任何远程开关

原理

控制开关及

机箱的开关及按钮连接到主板的两个引脚: Power+Power-, 也可以说是Power OutPower In, 平时两个引脚的连接是断开的,当机箱按钮按下短路, Power-是主板的 开关机检测引脚, 主板检测当这个引脚高电平的时间超过一定时间(t1)就开关机, 若发现是长按(时间t2),则强制关机

所以我们只需要用单片机去控制向Power In输入高电平即可(注意共地)

读取主机开机状态

主板会有一对(PLED+PLED-)甚至更多对引脚来指示开关机状态,一般会被连接到机箱的开关机指示灯, 通过PLED+的电平就可以知道主机是开机(高电平)还是关机(低电平)了

所以我们只需要用单片机去读取PLED+的电平即可(注意共地),是高电平就表示是开机状态

系统组成

硬件

ESP32 + 杜邦线 + 插针: ESP32非常便宜性能又高,最关键的是集成的 2.4G WiFi 硬件和协议栈, 而且支持 Micropython编程,可以在非常短的时间内完成本设计

电路

ESP32_开机控制电路

通过USB共地, 也可以接PLED-ESP32GND

更新:这里原理图画得比较潦草,如zean1987 指出,这里 PLED+ 输出的是 5v 电压,可能会让 3.3v 耐受的 GPIO 被烧,虽然 ESP32 这样接也能用,但是官方文档是没有说 5v 耐受的,所以最好加个电压转换电路,最简单的就是用一个或者两个电阻分压一下,当然实测 ESP32-S 直接接也能耐受。

系统通信网络(序列图)

Created with Raphaël 2.1.2硬件硬件MQTT服务器MQTT服务器网页服务器网页服务器用户浏览器用户浏览器订阅订阅登录、请求控制或者获取状态信息推送请求(消息)转发消息收到消息,判断消息并处理、响应推送状态信息转发消息收到状态,响应给用户响应控制结果以及状态信息

制作步骤

  • 按照精简电路图搭建硬件电路

  • 下载 Micropython 固件并按照说明更新到开发板

  • 编写Micropython程序,使用MQTT与云端建立长连接,定时向某个主题(topic1)上传状态,订阅某个主题(topic2),制定自己的协议,最好对数据进行加密,根据接收到的数据来决定采取什么动作

  • 编写服务器程序,订阅发布硬件状态的MQTT主题topic1,这样就可以获得开关机状态了,并且用一个接口来接受我们(用户)发送的开关机命令或者查询命令

  • 编写前端应用,比如Android应用,然后对接服务器的API,达到可以控制开关机的目的。当然,最好服务器采用带用户界面的WEB应用,这样就直接访问网页操作就好了,最好做权限控制,以及加密通信

  • 到这里基本就完成了

其它

配合 teamviewer 设置开机自启使用就可以随时随地使用自己的电脑啦~~

代码

木有现成的工程噢嘿嘿嘿

贴个简单的框架代码吧(无法直接使用)

ESP32:

  • MQTT库使用这里的或这个
  • 两个线程, 一个定时上传状态数据,另一个接受MQTT消息并处理
  • 这里的示例消息内容没有加密,在接收到指令后做动作即可
  • 出现错误捕获重启就好了~
  1. client = MQTTClient(CLIENT_ID, SERVER)
  2. g_power_status = machine.Pin(21, machine.Pin.IN, 0)
  3. g_power_control = machine.Pin(22, machine.Pin.OUT, 0)
  4. def power_status():
  5. global g_power_status
  6. return g_power_status.value()
  7. def power_on():
  8. global g_power_control
  9. g_power_control.value(1)
  10. time.sleep(1.5)
  11. g_power_control.value(0)
  12. def power_off():
  13. global g_power_control
  14. g_power_control.value(1)
  15. time.sleep(1.5)
  16. g_power_control.value(0)
  17. def power_off_force():
  18. global g_power_control
  19. g_power_control.value(1)
  20. time.sleep(6)
  21. g_power_control.value(0)
  22. def sub_cb(topic, msg):
  23. print((topic, msg))
  24. if topic == TOPIC_DOWN:
  25. if msg == b"on":
  26. print("receive power on")
  27. power_on()
  28. elif msg == b"off":
  29. print("receive power off")
  30. power_off()
  31. elif msg == b"off force":
  32. print("receive power off force")
  33. power_off_force()
  34. elif msg == b"status":
  35. print("receive status")
  36. upload = b'{"power":%d}' %(power_status())
  37. print("upload:", upload)
  38. client.publish(TOPIC_UP, upload )
  39. def main():
  40. global client
  41. client.set_callback(sub_cb)
  42. client.connect()
  43. client.subscribe(TOPIC_UP)
  44. client.subscribe(TOPIC_DOWN)
  45. print("Connected to %s, subscribed to %s and %s topic" % (SERVER, TOPIC_UP, TOPIC_DOWN))
  46. try:
  47. while 1:
  48. client.wait_msg()
  49. finally:
  50. client.disconnect()
  51. if __name__ == "__main__":
  52. t = Thread(target=upload_thread)
  53. t.start()
  54. try:
  55. main()
  56. except Exception as e:
  57. machine.reset()

服务器:

Flask 为例,同样没有加密过程,大概上是这样的:

  1. app = Flask(__name__)
  2. @app.route('/set')
  3. def set():
  4. cmd = request.args.get("cmd")
  5. if cmd == None:
  6. cmd = "param error cmd"
  7. else:
  8. mqtt_client.publish(TOPIC_DOWN, cmd)
  9. return cmd
  10. @app.route('/get')
  11. def get_status():
  12. global device_status
  13. mqtt_client.publish(TOPIC_DOWN, "status")
  14. return device_status
  15. def on_connect(client, userdata, flags, rc):
  16. print("Connected with result code "+str(rc))
  17. client.subscribe(TOPIC_UP)
  18. print("subscribe topic succss")
  19. global isConnected
  20. isConnected = True
  21. print("connected")
  22. # The callback for when a PUBLISH message is received from the server.
  23. def on_message(client, userdata, msg):
  24. print(len(msg.payload))
  25. timeNow = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
  26. print(timeNow+":"+msg.topic+" "+str(msg.payload))
  27. if msg.topic == TOPIC_UP:
  28. global device_status
  29. device_status = timeNow + ": " + msg.payload.decode('utf-8')
  30. def web_task():
  31. app.run(host="0.0.0.0", port=12345)
  32. def mqtt_task():
  33. client = mqtt.Client(
  34. client_id="RPCC_server2",
  35. clean_session=True,
  36. userdata=None,
  37. # protocol=MQTTv311
  38. )
  39. global mqtt_client
  40. mqtt_client = client
  41. client.on_connect = on_connect
  42. client.on_message = on_message
  43. print("connect mqtt")
  44. client.connect("mqtt.com", 1883, 60)
  45. print("connect mqtt end")
  46. client.loop_forever()
  47. if __name__ == "__main__":
  48. t = threading.Thread(target=web_task)
  49. t.setDaemon(True)
  50. t.start()
  51. mqtt_task()

然后打开浏览器输入.../get就可以得到状态了,.../set?cmd=on就可以开机了

文章有误?有想法想讨论?查看或者发起勘误/讨论 主题
(发起评论需要先登录 github)

/wallpaper/wallhaven-rdyewm.jpg