赞
踩
背景:之前使用HACS/网页版实现了电脑网络唤醒,但不能关机,不支持小爱
问题:不能语音关机,不支持小爱
环境:支持WOL的主板电脑,python 3.X环境(我这里用了群晖)
解法:1.使用小爱添加第三方设备
2.第三方平台提供API,
3.找台服务器运行Python脚本虚拟一个开关设备,定义开关触发bash脚本
流程、架构理清了,开始执行:
1.准备python3.X的环境,确保pip3 命令可用,群晖没有PIP3可以装,但是后面很多库、依赖安装出错,最终放弃,我直接使用docker python环境
已经搞好的(包含依赖环境)上传到了:https://hub.docker.com/r/realwang/blinker-wol
2.在python环境中安装Blinker依赖环境,参考官方教程
3.手机端操作
- 1.下载个点灯科技APP,注册账户
-
- 2. 添加设备-->独立设备-->WIFI接入-->阿里云-->复制key
-
- 3. 右上角编辑-->添加按钮-->修改键名为"btn-pc1"类型勾选开关按键
-
- 4. 右拉添加个调试组件,锁定退出
4.编写python脚本,确保服务器81端口闲置
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
-
- # 本代码引用arduino论坛 南岛孤云
- # 直接拿去用需要改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()
5.运行脚本,如果报错,缺什么补什么
6.电脑安装openssh,ssh测试一下到win10
6.跑起来手机上的设备会显示在线,手动操作开机后用小爱测试下
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。