Flipper Zero Python CLI 包装器

本次发布将包装器与当前 Flipper Zero CLI 保持一致(已在真实硬件上验证,固件版本 unlshd-089e):
info 模块:flipper.info.device_info() / power_info() / power_debug_info()(现代 info device / info power 命令)。power info → info power:flipper.power.info() 继续工作,现在内部读取 info power。新增 flipper.power.otg_on()/otg_off()。date:使用 flipper.date.datetime();解析已针对当前输出格式进行了修复。KB 和 KiB,read() 现在返回完整的多行文件内容,exFAT 和空标签卡能正确解析(修复 #21)。NECext、Kaseikyo、RCA、Pioneer 等自动受支持(修复 #15)。新增 flipper.ir.protocols()。debug → sysctl debug,subghz tx/rx 增加了必需的 device 参数,bt hci_info 保持不变。scan、dump、emulate、field、apdu、raw、mfu),并带有每个 UID 的 Mifare Classic 密钥缓存辅助函数(import_nfc_keys、write_key_cache)。ps(→ top)、music_player、nfc detect。$ pip install pyflipper
unlshd-089e)from pyflipper import PyFlipper
# 本地串行端口
flipper = PyFlipper(com="/dev/ttyACM0")
# 或者
# 远程 serial2websocket 服务器
flipper = PyFlipper(ws="ws://192.168.1.5:1337")
# TCP
flipper = PyFlipper(tcp='192.168.89.222:22170')
# 信息(在当前固件下,内部读取 `info power`)
info = flipper.power.info()
# 关机
flipper.power.off()
# 重启
flipper.power.reboot()
# 重启至 DFU 模式
flipper.power.reboot2dfu()
# 切换 GPIO 排针上的 5V OTG 引脚
flipper.power.otg_on()
flipper.power.otg_off()
# 从 .fuf 文件安装更新
flipper.update.install(fuf_file="/ext/update.fuf")
# 将 Flipper 备份为 .tar 文件
flipper.update.backup(dest_tar_file="/ext/backup.tar")
# 从备份的 .tar 文件恢复 Flipper
flipper.update.restore(bak_tar_file="/ext/backup.tar")
# 列出已安装的应用程序
apps = flipper.loader.list()
# 打开应用程序
flipper.loader.open(app_name="Clock")
# 获取 Flipper 日期(datetime 对象)
date = flipper.date.datetime()
# 获取 Flipper 时间戳
timestamp = flipper.date.timestamp()
# 获取设备信息字典(当前固件下的 `info device`,点分隔的键)
device_info = flipper.info.device_info()
# 获取电源信息字典(当前固件下的 `info power`)
power_info = flipper.info.power_info()
# 扩展电源/电量调试信息
power_debug = flipper.info.power_debug_info()
# 旧版 `device_info` 命令(下划线分隔的键,仍受支持)
legacy_info = flipper.device_info.info()
# 获取堆信息字典
heap = flipper.free.info()
# 获取 free_blocks 字符串
free_blocks = flipper.free.blocks()
# 获取蓝牙信息
bt_info = flipper.bt.info()
固件兼容性。 本库现在面向当前 Flipper Zero CLI(固件 1.x,已在 Unleashed
unlshd-089e上验证)。一些旧版命令已从官方固件中移除,因此不再可用:ps(已被交互式top取代)、music_player和nfc detect(NFC 现为交互式子 shell)。power info移至info power,debug移至sysctl debug,storage现在报告的大小单位为KiB——以上所有更改均由包装器透明处理。
# 获取存储文件系统信息
ext_info = flipper.storage.info(fs="/ext")
# 获取 /ext 目录的字典
ext_list = flipper.storage.list(path="/ext")
# 获取 /ext 目录的树状字典
ext_tree = flipper.storage.tree(path="/ext")
# 获取文件信息
file_info = flipper.storage.stat(file="/ext/foo/bar.txt")
# 创建目录
flipper.storage.mkdir(new_dir="/ext/foo")
# 读取文件
plain_text = flipper.storage.read(file="/ext/foo/bar.txt")
# 删除文件
flipper.storage.remove(file="/ext/foo/bar.txt")
# 复制文件
flipper.storage.copy(src="/ext/foo/source.txt", dest="/ext/bar/destination.txt")
# 重命名文件
flipper.storage.rename(file="/ext/foo/bar.txt", new_file="/ext/foo/rab.txt")
# 文件 MD5 哈希
md5_hash = flipper.storage.md5(file="/ext/foo/bar.txt")
# 一次性写入文件
file = "/ext/bar.txt"
text = """There are many variations of passages of Lorem Ipsum available,
but the majority have suffered alteration in some form, by injected humour,
or randomised words which don't look even slightly believable.
If you are going to use a passage of Lorem Ipsum,
you need to be sure there isn't anything embarrassing hidden in the middle of text.
"""
flipper.storage.write.file(path=file, text=text)
# 使用监听器写入文件
file = "/ext/foo.txt"
text_one = """There are many variations of passages of Lorem Ipsum available,
but the majority have suffered alteration in some form, by injected humour,
or randomised words which don't look even slightly believable.
If you are going to use a passage of Lorem Ipsum,
you need to be sure there isn't anything embarrassing hidden in the middle of text.
"""
flipper.storage.write.start(file)
time.sleep(2)
flipper.storage.write.send(text_one)
text_two = """All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as
necessary, making this the first true generator on the Internet.
It uses a dictionary of over 200 Latin words, combined with a handful of
model sentence structures, to generate Lorem Ipsum which looks reasonable.
The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.
"""
flipper.storage.write.send(text_two)
time.sleep(3)
# 别忘了停止
flipper.storage.write.stop()
# 设置通用 LED(r,b,g,bl)
flipper.led.set(led='r', value=255)
# 关闭蓝色 LED
flipper.led.blue(value=0)
# 设置绿色 LED 亮度值
flipper.led.green(value=175)
# 开启背光
flipper.led.backlight_on()
# 关闭背光
flipper.led.backlight_off()
# 关闭 LED
flipper.led.off()
# 设置震动为 True 或 False
flipper.vibro.set(True)
# 开启震动
flipper.vibro.on()
# 关闭震动
flipper.vibro.off()
# 设置 GPIO 模式:0 - 输入,1 - 输出
flipper.gpio.mode(pin_name=PIN_NAME, value=1)
# 设置 GPIO 引脚值:0 - 关闭,1 - 开启
flipper.gpio.set(pin_name=PIN_NAME, value=1)
# 读取 GPIO 引脚值
flipper.gpio.read(pin_name=PIN_NAME)
⚠️ 已从官方固件中移除。
music_playerCLI 命令已从原厂固件中删除(该应用现在是一个单独的.fap)。这些调用在保留该命令的定制固件(例如包含了该命令的 Unleashed / RogueMaster 版本)上仍然有效;在原厂固件上会返回“command not found”的响应。
# 以 RTTTL 格式播放歌曲
rttl_song = "Littleroot Town - Pokemon:d=4,o=5,b=100:8c5,8f5,8g5,4a5,8p,8g5,8a5,8g5,8a5,8a#5,8p,4c6,8d6,8a5,8g5,8a5,8c#6,4d6,4e6,4d6,8a5,8g5,8f5,8e5,8f5,8a5,4d6,8d5,8e5,2f5,8c6,8a#5,8a#5,8a5,2f5,8d6,8a5,8a5,8g5,2f5,8p,8f5,8d5,8f5,8e5,4e5,8f5,8g5"
# 循环播放
flipper.music_player.play(rtttl_code=rttl_song)
# 停止循环
flipper.music_player.stop()
# 播放 20 秒
flipper.music_player.play(rtttl_code=rttl_song, duration=20)
# 发出哔声
flipper.music_player.beep()
# 发出哔声持续 5 秒
flipper.music_player.beep(duration=5)
在当前固件上,NFC 是一个交互式子 shell(scanner、dump、emulate、field、apdu、raw、mfu)。此包装器进入子 shell,运行一个命令然后退出,因此每个方法都是普通的阻塞调用。detect() 作为 scan() 的别名保留。
# 检测标签类型 -> {'protocols': ['Mifare Classic'], 'raw': '...'} 或 None
tag = flipper.nfc.scan(timeout=5)
# 打开 NFC 场持续几秒钟
flipper.nfc.field(timeout=3)
# 发送 APDU(ISO14443-4 / ISO15693-3);若省略则协议自动检测
resp = flipper.nfc.apdu(["00A4 04 00", "A0 00"], protocol="14_4a")
# 发送原始字节并附加 CRC
flipper.nfc.raw("93 20", protocol="14a", crc=True)
# Mifare Ultralight 辅助函数
info = flipper.nfc.mfu_info()
block4 = flipper.nfc.mfu_read_block(4)
flipper.nfc.mfu_write_block(4, "00 01 02 03")
# 模拟已保存的 .nfc 文件
flipper.nfc.emulate(file="/ext/nfc/mycard.nfc", timeout=10)
CLI 的 dump 不运行字典攻击:它从每个 UID 的缓存中读取密钥,缓存位于 /ext/nfc/.cache/<UID>.keys(GUI 成功读取后写入的文件)。如果该缓存缺失,dump 会返回 "failed to read"。你可以从现有的 Flipper .nfc 转储文件中(重新)创建它——密钥从每个扇区尾部获取:
# 将原生 .nfc 转储文件中的密钥加载到每个 UID 的密钥缓存中
uid, cache_path = flipper.nfc.import_nfc_keys("/path/to/card.nfc")
# 现在 CLI dump 可以读取该卡(协议标记:mfc, mfu, 14_4a, ...)
flipper.nfc.dump(protocol="mfc", file="/ext/nfc/card_dump.nfc")
# 同步,默认超时 5 秒
# 读取 RFID
rfid = flipper.rfid.read()
# 模拟 RFID
emulated = flipper.rfid.emulate(key_type="EM4100", key_data="5500824806")
# 写入 RFID
written = flipper.rfid.write(key_type="EM4100", key_data="5500824806")
# 发送十六进制密钥 N 次(默认 count=10,device=0 -> CC1101_INT,1 -> CC1101_EXT)
flipper.subghz.tx(hex_key="DEADBEEF", frequency=433920000, count=5, device=0)
# 接收(默认 frequency=433920000,device=0,raw=False,timeout=5 秒)
received = flipper.subghz.rx(frequency=433920000, device=0, raw=True, timeout=10)
# 重放已记录的传输
flipper.subghz.tx_from_file("/ext/subghz/foo.sub")
# 解码原始的 .sub 文件
decoded = flipper.subghz.decode_raw(sub_file="/ext/subghz/foo.sub")
# 列出已连接固件支持的协议(从 `ir` help 实时读取)
protocols = flipper.ir.protocols()
# 发送十六进制地址和十六进制命令,选择协议
flipper.ir.tx(protocol="Samsung32", hex_address="C000FFEE", hex_command="DEADBEEF")
# NECext 现在受支持(协议列表从固件读取,而非硬编码)
flipper.ir.tx(protocol="NECext", hex_address="EF00", hex_command="FD02")
# 原始发送采样
flipper.ir.tx_raw(frequency=38000, duty_cycle=0.33, samples=[1337, 8888, 3000, 5555])
# 同步,默认超时 5 秒
# 接收
r = flipper.ir.rx(timeout=10)
# 读取(默认超时 5 秒)
ikey = flipper.ikey.read()
# 写入(默认超时 5 秒)
flipper.ikey.write(key_type="Dallas", key_data="DEADBEEFCOOOFFEE")
# 模拟(默认超时 5 秒)
flipper.ikey.emulate(key_type="Dallas", key_data="DEADBEEFCOOOFFEE")
# 附加事件日志器(默认超时 10 秒)
logs = flipper.log.attach()
# 激活调试模式(在当前固件上执行 `sysctl debug 1`)
flipper.debug.on()
# 停用调试模式
flipper.debug.off()
# 搜索
response = flipper.onewire.search()
# 获取
response = flipper.i2c.get()
# 输入转储
dump = flipper.input.dump()
# 发送输入
flipper.input.send("up", "press")
测试套件分为两部分:
test_serial_wrapper.py、test_commands.py)可在任何地方运行——它们针对模拟串行端口(tests/fake_serial.py)驱动库,该端口重现了 Flipper CLI 帧结构,因此无需设备。这些测试在 CI 中运行。test_hardware.py)与真实的 Flipper 通信,并在未连接设备时自动跳过。设置 FLIPPER_COM=/dev/ttyACM0 来指定特定端口。# 全部测试(硬件测试在未连接 Flipper 时自动跳过)
python -m unittest discover -s tests -p "test_*.py" -v
# 仅运行无需硬件的测试
python -m unittest tests.test_serial_wrapper tests.test_commands -v
欢迎以任何方式贡献
ZEC: zs13zdde4mu5rj5yjm2kt6al5yxz2qjjjgxau9zaxs6np9ldxj65cepfyw55qvfp9v8cvd725f7tz7
ETH: 0xef3cF1Eb85382EdEEE10A2df2b348866a35C6A54
BTC: 15umRZXBzgUacwLVgpLPoa2gv7MyoTrKat