本帖最后由 南岛孤云 于 2021-5-9 13:00 编辑
以前有人做了个树莓派开机的,貌似只能开机。我这个改进了下,可以开,可以关。可以小爱控制。
Win10需要开openssh server,win10自带,开启就可以了。
已加入小爱控制,小爱把它当个插座,app里设备名字改成电脑就好。
需要电脑有局域网固定IP,用来ping电脑状态,可以在网卡或者路由上设置。
App里图标用滑动开关,类型用'开关按键', 就可以正确的表现电脑的开关状态。另外需要wakeonlan 以及 paramiko
- sudo pip3 install wakeonlan
- sudo pip3 install paramiko
复制代码
另外注意下目前Github上blinker的python包有bug,
记得用pull request里那个100%CPU占用的修正。
我的树莓派3B+,这个后台开着应该是基本不占资源。
===================
更新了两句开关机超时的判定,默认都是60秒
设定超时的原因在于开关命令发出后,一般电脑要几十秒后才彻底完成开关动作,程序会通过ping的方式来确定电脑状态
如果出现意外,开关机一直无法完成(开机1分钟ping不到,或者关机1分钟一直能ping到),就要通过超时来停止ping,然后取消开关运行保护。
这样的结构一举三得,
1,避免重复开关机,最起码电脑要实际完成开关动作或者超时以后才能再发出指令,当然小爱是不知道的,你一直让她开她也会去开,但只是去帮你按了开关而已,逻辑都在开关上。
2,正确显示电脑状态,比如你手动开关的电脑,点灯不知道,最坏的情况下,一个心跳以后状态也同步了。
3,因为是纯软件的方法,一个设备就是个进程而已,不需要每个电脑去接线,所以你如果有多台电脑,完全可以一个派控制所有的。
===================
更新下win10下开ssh服务的步骤,以及需要注意的几个点。
开始 - 设置 - 应用 - 可选功能 - 添加功能 - OPENssh服务器 选择安装
然后打开PowerShell
- Start-Service sshd
- # 这一步开启ssh服务的自动启动,或者你也可以到 搜索-服务 里找到openssh ssh server这一条,用鼠标开启自动:
- Set-Service -Name sshd -StartupType 'Automatic'
- # 检查一下防火墙设置.
- Get-NetFirewallRule -Name *ssh*
- # 应该可以看到一条 "OpenSSH-Server-In-TCP",而且已经开启了
- # 如果找不到,执行一下这条添加新的防火墙规则,如果自行更改了端口 注意同时修改我们python代码上面paramiko的参数,具体加在client.connect(port=xxxx)
- New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
复制代码
默认的win10 openssh配置文件在 C:\ProgramData\ssh\sshd_config
如果你打算用公匙私匙方式来登录shh,这个文件的最后两句要用#注释掉,这两句会造成你安装在你管理员帐号下.ssh的密匙不起作用(密匙安装位置在C:\Users\xxxx\.ssh)。
- #Match Group administrators
- #AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
复制代码
配置完成后,最好在派上终端里手动登录一次,第一次登录好像需要输入确定。
==================================
[md]```
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 树莓派利用WOL和OPENSSH实现开关机。 针对WIN10, 电脑需要openssh!
# 直接拿去用需要改5处,1,密匙,2,局域网电脑的固定IP,3,电脑ssh用户名,4,电脑ssh密码 5,电脑的MAC地址
from Blinker import Blinker, BlinkerButton, BlinkerNumber, BlinkerMIOT
from Blinker.BlinkerConfig import *
from Blinker.BlinkerDebug import *
from wakeonlan import send_magic_packet
import paramiko
import time
import subprocess
auth = 'xxxxxxxxxx' # 1,点灯app上获得的密匙
BLINKER_DEBUG.debugAll()
Blinker.mode("BLINKER_WIFI")
Blinker.miotType('BLINKER_MIOT_OUTLET')
Blinker.begin(auth)
staticip = "192.168.1.200" # 2,电脑局域网固定IP,用于检测电脑开关状态以及利用SSH关机,改为你的设置
pcusr = 'xxxxxx' # 3,电脑ssh用户名
pcpw = 'xxxxxx' # 4,电脑ssh密码
pcmac = 'ff.ff.ff.ff.ff.ff' # 5,MAC地址,改成你自己电脑网卡的
button1 = BlinkerButton("btn-pc1") # 数据键,在App里设置一个一样的开关,类型为 '开关按键',图标用滑动开关,其他随意,文本可为空
cmd1 = "timeout 0.1 ping -c 1 " + staticip # 电脑开关检测就是一个局域网内的ping,超时我设置为100ms,貌似太短或太长小爱都容易出错
lockbutton1 = False
oState = ''
def miotPowerState(state):
''' '''
global oState
BLINKER_LOG('need set power state: ', state)
oState = state
BlinkerMIOT.powerState(state)
BlinkerMIOT.print()
# 小爱控制的实际部分放在上报状态之后,因为电脑开机实际时间很长,小爱等久了她会以为没开
if state == 'true':
button1_callback('on')
elif state == 'false':
button1_callback('off')
def miotQuery(queryCode):
''' '''
global oState
# 问小爱电脑开了吗,ping一次获得电脑实际状态
if subprocess.call(cmd1, shell=True)==0:
oState = 'true'
else:
oState = 'false'
BLINKER_LOG('MIOT Query codes: ', queryCode)
if queryCode == BLINKER_CMD_QUERY_ALL_NUMBER :
BLINKER_LOG('MIOT Query All')
BlinkerMIOT.powerState(oState)
BlinkerMIOT.print()
elif queryCode == BLINKER_CMD_QUERY_POWERSTATE_NUMBER :
BLINKER_LOG('MIOT Query Power State')
BlinkerMIOT.powerState(oState)
BlinkerMIOT.print()
else :
BlinkerMIOT.powerState(oState)
BlinkerMIOT.print()
# 关机部分用paramiko的sshclient,不用密码的话可以改用密匙,具体查阅paramiko用法
def shutdownpc():
global staticip
global pcusr
global pcpw
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(staticip, username=pcusr, password=pcpw)
stdin, stdout, stderr = client.exec_command('shutdown -s -f -c "小爱将在10秒内关闭这个电脑" -t 10')
if client is not None:
client.close()
del client, stdin, stdout, stderr
# 开关键,集成了开关功能,状态报告给小爱,开关过程中的运行保护,开关后状态的更新。
def button1_callback(state):
""" """
global lockbutton1
global oState
global pcmac
dtimeout = 60 # 开关机超时默认60秒
if lockbutton1==False:
BLINKER_LOG('get button state: ', state)
if state=='on':
if subprocess.call(cmd1, shell=True)==0:
oState = 'true'
Blinker.print("检测到电脑已开,按钮状态已更新")
button1.text('已开机')
button1.print(state)
else:
Blinker.print("发送开机指令...")
oState = 'true'
lockbutton1 = True
tic = time.perf_counter()
toc = time.perf_counter()
send_magic_packet(pcmac) # 发魔术包开机
while subprocess.call(cmd1, shell=True)!=0 and toc-tic<dtimeout+2:
time.sleep(2)
toc = time.perf_counter()
if toc-tic >= dtimeout:
Blinker.print("开机超时!")
button1.text('已关机')
button1.print('off')
else:
button1.text('已开机')
button1.print(state)
lockbutton1 = False
elif state=='off':
if subprocess.call(cmd1, shell=True)==0:
Blinker.print("发送关机指令...")
oState = 'false'
lockbutton1 = True
tic = time.perf_counter()
toc = time.perf_counter()
shutdownpc() # 关机
while subprocess.call(cmd1, shell=True)==0 and toc-tic<dtimeout+2:
time.sleep(2)
toc = time.perf_counter()
if toc-tic >= dtimeout:
Blinker.print("关机超时!")
button1.text('已开机')
button1.print('on')
else:
button1.text('已关机')
button1.print(state)
lockbutton1 = False
else:
oState = 'false'
Blinker.print("检测到电脑已关闭,按钮状态已更新")
button1.text('已关机')
button1.print(state)
else:
Blinker.print("正在开机或关机中..")
# 心跳加入了电脑状态检测,更新按钮
def heartbeat_callback():
global oState
if subprocess.call(cmd1, shell=True)==0:
oState = 'true'
button1.text('已开机')
button1.print("on")
else:
oState = 'false'
button1.text('已关机')
button1.print("off")
button1.attach(button1_callback)
Blinker.attachHeartbeat(heartbeat_callback)
BlinkerMIOT.attachPowerState(miotPowerState)
BlinkerMIOT.attachQuery(miotQuery)
if __name__ == '__main__':
while True:
Blinker.run()
```[/md]
|