DIY 兼容 FindMy 网络的定位标签/设备(长期记录)
“NinjiaTag”并非拼写错误,而是我们对物联网产品价值的重新定义:它不仅是敏捷的防丢工具(Ninja),更是对下一代分布式物联网(IOT)技术的憧憬,为分布式蓝牙标签(Tag)的新一代解决方案。名称中的 ‘jia’ 也寓意 ‘协作之家’,期待与你共同构建!
服务器端运行 FindMy 网络后台抓取位置数据并存入数据库,无需部署 Mac 电脑或虚拟机,也不需要拥有 iPhone 与其上面的查找 app 即可查看回溯任意时间段内您 DIY 的定位标签/设备的位置、轨迹(注册 Apple-ID 时需要借用一下别人的 iPhone)。 目前实现的功能:
-
服务器端后台运行 request_report 获取位置,定期下载位置数据并储存在本地服务器数据库,储存时间不限(目前市面上主流产品记录时长最多为 7 天),轨迹可永久保存于服务器。
-
支持任意时间段任意物品轨迹查询和显示,支持轨迹点的经纬度和时间点显示,可随意缩放查看,方便回溯。
-
支持热图显示( Hotspot ),类似地理信息系统的人流密度显示,经常去过的地方颜色更深,不去或偶尔去的地方颜色浅。
-
Web 前端支持密钥管理
-
地图采用开源的 Mapbox-GL 三维地图引擎,支持三维地形显示,渲染更加美观。
-
待测试 Query Apple's Find My network,write into sqlite database, convert to tracks(KML/GPX etc.)
- NinjiaTag
硬件 DIY 需要一定门槛,如果你不想自己动手,可以咸鱼搜索 “自制 Airtag”(用户名 Dijkstra 很贪心 ),我会不定时上架一些成品,但建议你自己搭建服务,我提供的服务器带宽有限。
成品使用教程:
- 一台 Linux 服务器(任意 Linux)。用来运行 Docker 服务和 Python 脚本。
- 需要一个使用实体 IOS 设备注册的,已启用 2FA (双重认证)的 Apple-ID。 建议不要使用个人常用的 Apple ID,而是注册一个新的 Apple ID 用于实验目的。 没有 Apple ID 的 可以找朋友借用一下苹果设备(iPad、Macbook、iPhone),注册一个。仅支持短信方式作为双重认证!如果有苹果设备登录着该 Apple ID,最好退出,否则有可能收不到短信验证码。 您需要在苹果设备上登录过该帐户才可以(获得了 iCloud 的 5G 免费空间才是有效的 Apple ID)。仅在 iCloud 网页上注册的 Apple ID 权限不足。 Only a free Apple ID is required, with SMS 2FA properly setup. If you don't have any, follow one of the many guides found on the internet.
- 一个蓝牙标签设备,目前支持 nRF5x 蓝牙模块,ST17H66 蓝牙模块,后续会支持更多低成本国产蓝牙模块 只需要最小系统模块,所以也可以购买 nRF5x ST17H66 芯片自己进行 PCB 打样。
-
下载刷机固件和刷机脚本
- ST17H66 芯片前往 Lenze_ST17H66 下载所需固件(FindMy.hex)和刷机脚本(flash_st17h66.py)
- nRF5x 前往 openhaystack-firmware 下载所需固件(nrf51_firmware.bin 或 nrf52_firmware.bin)
- TLSR825X 芯片,比如米家温湿度计 2(型号 LYWSD03MMC)也可以刷机成定位标签,但我没有尝试
-
执行本仓库的 keygen 目录下
python3 generate_keys.py来生成密钥对(在当前目录 6 位随机名称目录下)。(注意: 必须安装依赖cryptographyfilelock. 用pip3 install cryptography filelock命令安装) Windows 或 Linux 下都可以执行。 -
将固件刷入设备 说明:generate_keys.py 在原项目上做了修改,支持多物品多密钥自定义批量生成,如生成 5 个密钥的 8 个物品(在不同文件夹),执行
python3 generate_keys.py -n 5 -i 8
generate_keys.py 可以指定参数 python3 generate_keys.py -n 50 来生成包含多个密钥的 keyfile,其中 50 就是个数,可以自己改。不指定则默认单个密钥,也就是定位标签运行过程中只有一个蓝牙 Mac 地址(密钥其实就是加密了的 Mac 地址),而多密钥就是定位标签可以定时更换 Mac 地址(称为滚动密钥,苹果 AirTag 就是这样)。
经过测试,带密钥轮换机制的标签,其位置会被更频繁的上报,即位置更新更频繁,更能被精确定位。推荐使用多密钥的 keyfile。但是,密钥轮换会增加一定功耗。
在终端中执行以下命令,创建一个新的 docker 网络
docker network create mh-network2. 运行 Anisette Server
docker run -d --restart always --name anisette -p 6969:6969 --volume anisette-v3_data:/home/Alcoholic/.config/anisette-v3/ --network mh-network dadoum/anisette-v3-server注意:首次执行该命令会自动从 docker 官方仓库拉取镜像,因国内网络环境的原因,需要设置镜像仓库。如下修改 docker 的配置文件/etc/docker/daemon.json(不存在就新建),增加 registry-mirrors:
{
"registry-mirrors": [
"https://docker.1ms.run",
"https://hub.1panel.dev",
"https://docker.itelyou.cf",
"http://mirrors.ustc.edu.cn",
"http://mirror.azure.cn"
]
}之后运行如下命令重启 docker 服务:
systemctl restart docker
# 或者
service docker restart此时,镜像源应该生效了。可以用 docker info 命令验证,如果输出末尾有如下Registry Mirrors,说明镜像源配置成功了:
Registry Mirrors:
https://docker.1ms.run/
https://hub.1panel.dev/
https://docker.itelyou.cf/
......
使用 git clone 或下载 zip 解压
将硬件设置步骤中生成的.key 后缀的文件放置在本项目/keys 文件夹下,后续脚本会自动转化
安装 python3,并使用 pip3 安装相关依赖
pip3 install aiohttp requests cryptography pycryptodome srp pbkdf2 -i https://pypi.tuna.tsinghua.edu.cn/simple
如果成功通过pip3安装完成依赖,该步骤可忽略
python3 -m venv ./venv/
./venv/bin/pip3 install aiohttp requests cryptography pycryptodome srp pbkdf2 -i https://pypi.tuna.tsinghua.edu.cn/simple
在 python3 venv 环境执行
./venv/bin/python3 request_reports.py
或执行python3 request_reports.py
开始时会提示输入 Apple ID 和密码,然后是 2FA 短信验证,完成后能正常执行位置数据拉取。
如果输入 Apple ID 及密码后在 2FA 阶段出现gsa_authenticate类型的错误
r = gsa_authenticated_request({"A2k": A, "ps": ["s2k", "s2k_fo"], "u": username, "o": "init"})
raise InvalidFileException()
plistlib.InvalidFileException: Invalid file
可能当前服务器 IP 被 Apple 禁止访问,执行
curl -k https://gsa.apple.com/grandslam/GsService2 -v
如果返回401 Authorization Required字样说明当前 IP 正常,返回503 Service Temporarily Unavailable说明当前 IP 被禁,需要更换当前服务器 IP 重试
执行以下命令安装 nodejs 和 npm 用于提供后端服务
# Download and install nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
# in lieu of restarting the shell
\. "$HOME/.nvm/nvm.sh"
# Download and install Node.js:
nvm install 22
# Verify the Node.js version:
node -v # Should print "v22.17.1".
nvm current # Should print "v22.17.1".
# Verify npm version:
npm -v # Should print "10.9.2".如果网络有问题可尝试在 nodejs 官网下载安装包进行手动安装,不在本教程范围内,可自行搜索安装教程
完成后在项目目录下执行:
npm i
安装 node_modules 相关依赖
如果在 python venv 执行,将request_reports.mjs文件中
python3 request_reports.py
修改为
./venv/bin/python3 request_reports.py
可以通过修改*/5 * * * *来修改从 Findmy 服务器获取位置数据的时间间隔,具体参考 Cron 的文档,如*/5 * * * *表示每 5 分钟请求一次,不建议修改得太频繁
长期运行 "server.mjs" 和 "request_reports.mjs" 以保证服务器能定期取回位置数据并存于数据库
- 通过 npm 全局安装
npm install pm2 -g
- 验证安装:执行 "pm2 --version",输出版本号即安装成功。
- 权限问题(Linux/Mac):若提示权限不足,可添加
"sudo" 或执行
chmod 777 /usr/local/bin/pm2授权。
- 运行
"server.mjs"(数据库查询主服务):
pm2 start server.mjs --name "query-server" --watch
"--name":自定义进程名称(便于管理)。 "--watch":监听文件改动自动重启。
- 运行
"request_reports.mjs"(抓取位置数据任务):
pm2 start request_reports.mjs --name "report-task" --watch
- 保存进程列表
pm2 save保存当前运行列表,防止重启后丢失。 - 设置系统开机自启
pm2 startup# 生成启动脚本sudo pm2 startup systemd # Linux systemd 系统pm2 save # 关联保存的进程列表服务器重启后 PM2 自动恢复进程。 - 日志管理
- 查看实时日志:
pm2 logs web-server # 指定进程名
- 查看实时日志:
- 查看进程状态 "pm2 list" 显示所有进程及资源占用
- 停止进程 "pm2 stop server" 停止指定进程(保留配置)
- 重启进程 "pm2 restart server" 零停机重载(适用服务更新)
- 监控资源 "pm2 monit" 实时显示 CPU/内存
- 删除进程 "pm2 delete server" 彻底移除进程
前端页面需访问数据查询服务 url 地址" 形如 http://服务器ip:3000。
若要在公网使用,需将本地部署服务公开到公网,可以用 路由器端口映射 或 内网穿透(比如有公网 IP 可使用端口映射+DDNS,或使用反向代理 ngrok 、节点小宝、ZeroNews 都有免费版;花生壳 9 块 9 永久用,每月免费 1G 流量) 或使用 Zerotier tailscale 之类的的方式实现。具体操作不属于本文范畴,请自行搜索。
前端页面可以自行部署,也可以使用我提供的页面https://bd8cca.atomgit.net/NinjiaTagPage/,页面只是一个查询框架,建议使用我提供的页面。 前端基于 vue3 框架开发,目前存在少量 bug,但整体能用,欢迎提出 Issue 或 Pr,所有打包的前端页面位于https://atomgit.com/bd8cca/NinjiaTagPage 项目,可自行下载部署
NinjiaTagPage(http) NinjiaTagPage(https)
- 因浏览器限制,https 的网站只能访问 https 的后台服务。所以如果你选择使用 Atomgit Page(https),那么必须将 后端 node 服务部署为 https(需 SSL 证书)。可以反向代理工具,推荐使用Cloudflare tunnel将本地 NAS 或 Linux 服务器端口映射到子域名下。
- 访问 http 的地址,浏览器可能会自作主张转向 https 的地址,可以地址栏改成 http 再回车
NinjiaTag 前端页面,使用 Vue3 编写,结合 Mapbox-gl 三维引擎强大的渲染能力,后续可扩展更多的功能(如轨迹导出 KML,多物品时空交错)。
-
在前端页面有配置服务器地址选项,填入部署的服务器远程地址/query,注意加上/query 后缀,如
http://服务器ip:3000/query -
将 generate_keys.py 硬件设置生成的.json 密钥文件在
物品管理对话框解析json密钥文件导入即可 -
在
数据选择对话框选择物品数据和时间段进行查询,有几个选项:
-
轨迹点:历史的轨迹,鼠标悬停或点击可显示详情。
-
热图: 类似地理信息系统的人流密度显示,经常去过的地方颜色更深,不去或偶尔去的地方颜色浅。
-
最新位置: 最新的物品位置,以图标的形式显示。
如果没有获取到位置数据,带着 diy 的 NinjiaTag 到人流密集的地方走一圈,等待后台服务器获取到位置数据库并存入数据库。
-
查找部分的工作,主要基于 openhaystack 开源项目修改后实现,感谢https://github.com/seemoo-lab/openhaystack/项目的所做工作
-
Query Apple's Find My network, based on all the hard work of https://github.com/seemoo-lab/openhaystack/ and @hatomist and @JJTech0130 and @Dadoum
-
并且感谢 JJTech0130 降低部署门槛,目前服务端部署不再需要 mac 设备了 https://github.com/JJTech0130/pypush
-
lovelyelfpop 大佬开发的安卓 apk 也可以用于本项目,感谢他本地化 app 做的很多工作 https://gitee.com/lovelyelfpop/macless-haystack
KML stands for Keyhole Markup Language. It's a file format used to display geographic data in an Earth browser, such as Google Earth, Google Maps, and various other mapping applications.
./request_reports.py > input.txt
It will generate a json like file include main data of coordinate & date & time.
python3 make_kml.py
this script reads input.txt generated with request_reports.py and writes for each key a *.kml file
此存储库仅用于研究目的,此代码的使用由您负责。
对于您选择如何使用此处提供的任何源代码,我概不负责。使用此存储库中提供的任何文件,即表示您同意自行承担使用风险。再次重申,此处提供的所有文件仅用于教育和或研究目的。本项目仅用于物品的防丢,严禁用于非法用途,使用时请遵守当地的法律法规。
