我们使用433MHz无线开关来控制PC

您好Geektimes Habr。

在我的家中,在家中积累了数个433 MHz的无线交换机,无论它们是否可用于任何任务,例如控制计算机或将“智能家居”集成到系统中,都变得很有趣。

这些开关因其低成本和稳定的操作而十分方便,它们看起来像这样:



它是如何工作的,以及可以用它们做什么(轻骑兵保持安静:),细节在削减。

理论


我必须立即说出这种开关的工作原理,尽管我猜是这样。 因此,您将需要进行一些逆向工程。

首先,必须接收信号,为此,我们使用众所周知的RTL-SDR接收器,通常被无线电爱好者称为“哨子”。 该设备的价格仅为10美元,可让您接收大约50至1250 MHz的无线电信号,这对我们来说是我们需要的。 该主题很旧,但是如果有人没有阅读, 请阅读

我们进行分析的第一步-我们仔细查看开关。 我们发现在案件的背面写着“中国制造”(谁会想到的?),更重要的是,显示了433 MHz的频率。 现在您可以连接SDR接收器,启动SDR#并确保确实传输了数据。



频谱上信号的对称性表明存在AM调制。 顺便说一下,在右侧可以看到较弱的“外来”信号-它们也可以被接收和解码,将分别进行详细讨论。 但是,回到信号。 我们以通常的WAV格式记录它,然后按遥控器上的按钮-例如,我按了通道“ 1”上的ON和OFF按钮。

在任何音频编辑器中打开声音文件,然后使用另一个专业分析工具Paint来比较信号。 我们将来自不同按钮的2个信号放在另一个之上,以查看差异:



可以很容易地看到,我们具有通常的位序列,其中的区别只是一位,对应于ON或OFF按钮。 按下按钮时,开关会以每秒20次的速度简单地循环播放此序列。 便宜又容易,即使一个序列在传输过程中失真,其他序列也会被接受。

顺便说一下,由此可以得出一个重要的结论-这种开关的信号(我们所说的是廉价的型号)按“原样”传输,无需任何身份验证,保护或加密。 此类开关或带有此类开关的无线插座不应用于某些重要功能,例如,打开强大的加热器,甚至不能用于打开前门或车库。 甚至与黑客无关(某人以无线方式入侵我家的机会,我估计跌落到我的ISS家的机会要少),但邻居可以不小心购买相同的交换机,并且密码可能匹配(但是,在交换机上有4个通道可供选择)。 以我的使用经验,断路器每年确实开动2-3次,实际上是收到了来自同一型号的障碍物或遥远的信号。

当然,这不适用于更复杂的系统,例如Lora或Philips Hue,加密就可以了。

但是,回到我们的任务。 您可以自己编写此类信号的解码器,但幸运的是,这已经摆在我们面前的“ rtl_433”项目中。 该程序最初是为Linux创建的,Windows版本可以下载 Linux版本可以从GitHub下载。

我们从命令行启动程序:“ rtl_433.exe -F json”



我们得到了数据,剩下的就是编写程序进行处理了。

树莓派


首先值得考虑的是Raspberry Pi。 要在Raspbian上安装rtl_433 ,请解压缩归档文件并执行以下命令。

sudo apt-get install libtool libusb-1.0.0-dev librtlsdr-dev rtl-sdr build-essential autoconf cmake pkg-config cd rtl_433/ autoreconf --install ./configure make make install 

第二步是编写一个程序,它将接收此数据,并根据它执行必要的操作。 Python代码非常简单:

 from __future__ import print_function import os, sys, io import json import subprocess print("RTLSDR listening started") transmitter_name = "Waveman Switch Transmitter" transmitter_channel = 1 proc = subprocess.Popen(["rtl_433 -F json"], stdout=subprocess.PIPE, shell=True) while True: try: line = proc.stdout.readline().encode('ascii','ignore') proc.poll() data = json.loads(line) print(data) m,st,ch,btn= data['model'],data['state'],data['channel'],data['button'] if m==transmitter_name and ch==transmitter_channel and btn==1 and st=='on': print("ON") elif m==transmitter_name and ch==transmitter_channel and btn==1 and st=='off': print("OFF") except KeyboardInterrupt: break except: pass print("RTLSDR listening done") 

要运行代码,您需要将其保存在文件中(例如rtl_listen.py)并运行命令“ python rtl_listen.py”。

如您所见,该程序使用subprocess.Popen启动该过程并从中读取数据。 这样一切就变得简单了,代码也很易读,并且进行更改也就不难了。 在此示例中,当按下“ 1”按钮时,显示消息打印(“ ON”),而您可以执行其他操作,例如,激活GPIO引脚,打开继电器,将数据发送到服务器等。在使用它之前,您需要同时进行更改将使用的控制台的型号名称中的“名称”端。

顺便说一下,与Raspberry Pi相比,RTL-SDR接收器本身看起来像这样:



窗户


不幸的是,在Windows 10下,上述代码无法正常工作。 但是正如在github上的搜索所建议的那样,可以从单独的流中异步读取数据。 为什么会这样呢,太懒了,找不到答案,我只把工作代码放在破坏者的下面。

源代码
 from __future__ import print_function import os, sys import subprocess import time import threading import Queue import json class AsynchronousFileReader(threading.Thread): # Helper class to implement asynchronous reading def __init__(self, fd, queue): assert isinstance(queue, Queue.Queue) assert callable(fd.readline) threading.Thread.__init__(self) self._fd = fd self._queue = queue def run(self): # The body of the tread: read lines and put them on the queue. for line in iter(self._fd.readline, ''): self._queue.put(line) def eof(self): # Check whether there is no more content to expect return not self.is_alive() and self._queue.empty() def replace(string): while ' ' in string: string = string.replace(' ', ' ') return string def read_rtl_data(): process = subprocess.Popen(["rtl_433.exe", "-F", "json"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Launch the asynchronous readers of stdout and stderr. stdout_queue = Queue.Queue() stdout_reader = AsynchronousFileReader(process.stdout, stdout_queue) stdout_reader.start() stderr_queue = Queue.Queue() stderr_reader = AsynchronousFileReader(process.stderr, stderr_queue) stderr_reader.start() transmitter_name = "Waveman Switch Transmitter" transmitter_channel = 1 # Check the queues if we received some output while not stdout_reader.eof() or not stderr_reader.eof(): # Show what we received from standard output. while not stdout_queue.empty(): line = stdout_queue.get() print("Line1:", repr(line)) data = json.loads(line) # print("Data:", repr(line)) m,st,ch,btn= data['model'],data['state'],data['channel'],data['button'] if m==transmitter_name and ch==transmitter_channel and btn==1 and st=='on': print("ON") elif m==transmitter_name and ch==transmitter_channel and btn==1 and st=='off': print("OFF") # Show what we received from standard error. while not stderr_queue.empty(): line = replace(stderr_queue.get()) print("Line2:", line) # Sleep a bit before asking the readers again. time.sleep(0.1) stdout_reader.join() stderr_reader.join() # Close subprocess' file descriptors. process.stdout.close() process.stderr.close() if __name__ == '__main__': print("RTLSDR listening started") read_rtl_data() print("RTLSDR listening done") 


使用此代码,我们可以在处理程序中使用任何操作,其逻辑与Raspberry Pi上的代码相同。

示例 :假设我们有一台专用于家庭影院的计算机,并且我们想通过按遥控器上的按钮将其关闭。 将代码“ print(“ OFF”)”替换为

  os.system('shutdown -s') sys.exit(0) 

之后,计算机将通过按相应的按钮关闭。 当然,除了“ shutdown -s”之外,您还可以使用任何其他Windows命令,您只需要考虑在按下遥控器按钮的同时重复发送命令即可,以避免重复,您需要改进代码。

结论


如您所见,一切都非常简单,并且有进行实验的空间。 最后,对于那些在这里读书的人来说,这是一笔不小的奖金。 在433 MHz下,rtl_433可以解码大量不同的设备,您可以将程序运行几个小时,然后看看有什么“赶上”了。 在扰流板下,记录了这样的日志的示例,该日志先前已记录:

记录
2018-01-10 21:15:17 : Prologue sensor : 5 : 15
Channel: 1
Battery: OK
Button: 0
Temperature: 6.00 C
Humidity: 11 %

2018-01-10 21:15:28 : inFactory sensor
ID: 71
Temperature: 6.67 °C
Humidity: 99 %

2018-01-10 21:16:07 : Toyota : TPMS : 61511475 : 60e5006b : CRC

2018-01-10 21:20:33 : Prologue sensor : 5 : 15
Channel: 1
Battery: OK
Button: 0
Temperature: 6.00 C
Humidity: 11 %
: Waveman Switch Transmitter
id: A
channel: 2
button: 1
state: on
: Waveman Switch Transmitter
id: A
channel: 2
button: 1
state: on
: Waveman Switch Transmitter
id: A
channel: 2
button: 1
state: on

2018-01-10 21:21:21 : Akhan 100F14 remote keyless entry
ID (20bit): 0x41
Data (4bit): 0x4 (Mute)
: Waveman Switch Transmitter
id: A
channel: 2
button: 1
state: off

2018-01-10 21:32:31 : Ford : TPMS : 00268b1f : a34a0e : CHECKSUM
2018-01-10 21:32:32 : Ford : TPMS : 00268a5c : 9c440e : CHECKSUM
2018-01-10 21:32:37 : Ford : TPMS : 016dbfce : 99430e : CHECKSUM
2018-01-10 21:32:39 : Ford : TPMS : 002671a0 : 9c4a0e : CHECKSUM


有一些有趣的数据,例如邻居汽车的胎压(TPMS,胎压监测系统)或其他人的传感器的外部温度+6。 例如,如果邻居意外地拥有与该协议兼容的气象站,则可以显示外部温度。

所有成功的实验。

免责声明 :显然,使用SDR和数字处理读取OOK调制信号本质上是对麻雀的射击。 也许在速卖通上有1-2美元的现成接收机,它们可以完成相同的工作,而且成本更低,功耗更低。 如果有人知道这样的模型,请在注释中写。

Source: https://habr.com/ru/post/zh-CN414285/


All Articles