{"id":22542096,"url":"https://github.com/littlebutt/fubuki-iot","last_synced_at":"2025-04-09T22:43:05.365Z","repository":{"id":60240908,"uuid":"537326612","full_name":"littlebutt/fubuki-iot","owner":"littlebutt","description":"物联网IoT智能终端，支持Windows和树莓派","archived":false,"fork":false,"pushed_at":"2022-10-12T01:46:20.000Z","size":39,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T00:41:21.571Z","etag":null,"topics":["ai","iot","iot-application","iot-platform","machine-learning","self-made"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/littlebutt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-09-16T06:05:04.000Z","updated_at":"2024-02-20T09:18:39.000Z","dependencies_parsed_at":"2022-09-27T04:30:25.149Z","dependency_job_id":null,"html_url":"https://github.com/littlebutt/fubuki-iot","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/littlebutt%2Ffubuki-iot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/littlebutt%2Ffubuki-iot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/littlebutt%2Ffubuki-iot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/littlebutt%2Ffubuki-iot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/littlebutt","download_url":"https://codeload.github.com/littlebutt/fubuki-iot/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248125028,"owners_count":21051758,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","iot","iot-application","iot-platform","machine-learning","self-made"],"created_at":"2024-12-07T13:08:30.761Z","updated_at":"2025-04-09T22:43:05.331Z","avatar_url":"https://github.com/littlebutt.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fubuki Iot —— 物联网智能终端\n\n\n![PyPI](https://img.shields.io/pypi/v/fubuki-iot) ![GitHub](https://img.shields.io/github/license/littlebutt/fubuki-iot) ![GitHub last commit](https://img.shields.io/github/last-commit/littlebutt/fubuki-iot) ![](https://img.shields.io/github/repo-size/littlebutt/fubuki-iot) ![](https://img.shields.io/badge/QQ-1136681910-9cf?logo=tencentqq\u0026logoColor=9cf)\n\n## 简介\n\nFubuki Iot是一款开源的物联网智能终端，类似于市面上的天猫精灵，小爱同学等。它可以监听智能家居的消息，也可以根据用户语音向智能家居\n发送消息，从而实现家居智能化。与市面上各种终端相比，它具有以下优点：\n\n- 定制化程度更高：用户可以自己实现对家居的控制，甚至对原有的家居电器改造\n- 安全性更好：由于可以部署在本地局域网上，因此个人信息不会被上传到外网\n- 效率更高：通过MQTT协议完成设备之间的交流，不需要复杂的流程\n\n经过测试，本框架可以很好的支持Windows系统和树莓派（Linux）系统。\n\n## 快速上手\n\n### 安装\n\n#### 方案一：通过`pip`安装（推荐）\n\n```shell script\npip install fubuki-iot\n```\n\n#### 方案二：下载安装\n\n首先在终端执行以下命令：\n\n```shell script\ngit clone git@github.com:littlebutt/fubuki-iot.git\n```\n\n然后进入根目录，执行以下命令安装`fubuki-iot`包\n\n```shell script\npython setup.py install\n```\n\n#### 方案三：通过`docker`安装\n\n同样像方案三中下载项目到本地，然后执行以下命令\n\n```shell script\ndocker build -t fubuki-iot:latest .\ndocker run -it fubuki-iot:latest /bin/bash\n```\n 就可以进入到容器内部了\n \n ### 启动\n \n 本项目内置了 [百度云](https://cloud.baidu.com/) 的语音合成和语音识别的功能，因此使用之前需要免费申请百度云账号，\n 点击 [这里](https://login.bce.baidu.com/new-reg?tpl=bceplat\u0026from=portal) 申请。申请之后开通\"产品\"-\"人工智能\"-\"语音技术\"的服务。\n 当然，您也可以用开源方案自己训练模型替代内置的语音功能，具体见 **进阶功能** 。\n \n 1.创建资源目录\n 首先创建一个Python工程 `demo` ，并在根目录下创建一个目录命名为`resources`\n \n 2.创建`.env`文件\n \n 在新建的工程下创建一个`.env`配置文件，其内容参考如下：\n \n ```text\nENVIRONMENT=dev\nRESOURCE_PATH=刚才创建的resources目录，结尾不要加“/”\nBAIDU_ACCESS_TOKEN=百度云API的token，可以留空\nBAIDU_API_KEY=申请的百度云的AK\nBAIDU_SECRET_KEY=申请的百度云的密钥\n```\n\n 3.创建主程序\n\n在根目录下创建文件 `app.py`，并写入以下内容\n\n```python\nfrom iot import Terminal\n\n\nTerminal.run()\n```\n运行即可启动\n\n\n### 使用\n\n目前主流的物联网信息交换都采用 [MQTT协议](https://www.runoob.com/w3cnote/mqtt-intro.html) ，因此要实现控制智能设备需要部署MQTT\n服务器。本项目建议使用 [EMQX](https://www.emqx.com/zh/mqtt) 服务器，具体安装和部署方法点击 [这里](https://www.emqx.io/docs/en/v5.0/deploy/install.html#tar-gz-linux-macos-windows) 。\n\n若要完整的实现对硬件设备的控制可以参考 **相关资料** 。\n#### 内置功能\n\n1.对话\n\n运行智能终端后，按下键盘上的f可以进行录音。对着麦克风说出“在吗”、“你好”后，智能终端会回应“在的”。\n\n2.控制开关和电灯\n\n运行智能终端，按下键盘上的f后对着麦克风说出“打开开关”，然后它会向MQTT服务器的`default/switch` Topic发送以下信息：\n\n```json\n{\n  \"switch\": \"on\"\n}\n```\n\n同样，对着麦克风说出“关闭开关”后，它会向MQTT服务器的`default/switch` Topic发送以下信息：\n\n```json\n{\n  \"switch\": \"off\"\n}\n```\n\n具体效果需要由订阅了 `default/switch` Topic的智能设备实现。\n\n此外，运行智能终端，按下键盘上的f后对着麦克风说出“打开卧室/客厅/餐厅灯”也会向MQTT服务器的`default/light` Topic发送以下信息：\n\n```json\n{\n  \"position\": \"bedroom/livingroom/dinningroom\" \n}\n```\n\n3.接受按钮信息\n\n运行终端，当由设备向MQTT服务器的 `self/button` 发送如下消息后，终端会说“有人按下了按钮”。\n\n```json\n{\n  \"topic\":\"self/button\",\n  \"device\":\"button\",\n  \"verbose\":\"false\",\n  \"message\":\"有人按下了按钮\"\n}\n```\n\n#### 自定义功能\n\n1.自定义语音功能\n\n语音功能可以理解为用户和智能终端进行对话，类似于机器人的对话功能。这种功能一般不涉及硬件。在天猫精灵中，\n就内置了提醒助手、墨迹天气等语音功能。\n\n首先在自己创建的Python项目的根目录中创建一个包（package）命名为 `models` ，在这个包中创建一个python文件 `acoustics.py`，\n在文件中定义一个语义模型：\n\n```python\nfrom iot import SemanticsGroup, SemanticsModel, SemanticsRedirectEnum, SemanticsFromEnum, SemanticsFunc\n\n@SemanticsGroup.add_model\nclass MySemanticsModel(SemanticsModel):\n\n    code = 'hello'                                  # 语义模型的标识，自定义\n\n    frm = SemanticsFromEnum.USER                    # 语义模型的来源，这里是接受用户的语音命令，所以是USER\n\n    topic = ''                                      # 由于不涉及发布消息，所以这个字段用不到，留空就行\n\n    regex = \"(.*)后提醒我(.*)\"                       # 匹配用户语音命令的正则表达式，比如这里是一个有关提醒的命令\n\n    regex_num = 3                                   # 上述表达式匹配后的分组（group）的数量，第一个为用户命令全量文本，第二个是“后”前面的文本，第三个是“我”后面的文本\n\n    redirect = SemanticsRedirectEnum.ACOUSTICS      # 语义处理好后的重定向，由于不需要发送消息等后续操作，所以这里是直接语音返回\n\n    func: SemanticsFunc = my_semantics_model_func   # 处理用户命令的回调函数\n```\n\n在上面的语义模型中，最后一个字段是一个 `SemanticsFunc` 实例，它是一个返回 `FunctionDeviceModel` 或者 `UniverseNoticeModel` 的方法\n因此，需要这样定义：\n\n```python\nfrom typing import Union\nfrom iot import UniverseNoticeModel, FunctionDeviceModel\n\ndef my_semantics_model_func(*args) -\u003e Union[FunctionDeviceModel, UniverseNoticeModel]:\n\n    time = args[1]                                      # 获取时间\n\n    content = args[2]                                   # 获取提醒内容\n\n    # 处理提醒命令，可以借助其他API实现\n\n    return FunctionDeviceModel(                         # 最后返回一个功能设备模型\n\n        smt_code='hello',                               # 对应的语义模型标识\n\n        is_raw=True,                                    # 是否为纯文本\n\n        acoustics=f\"好的，我会在{time}后提醒你{content}\", # 返回给用户的语音内容\n\n        data=\"\"                                         # 由于是纯文本，所以这个字段用不到\n\n    )\n```\n\n定义好以后需要在 `app.py` 中加入一行：\n\n```python\nfrom iot import Terminal\n\n\nTerminal.load_models('demo.models')\nTerminal.run()\n```\n\n2.自定义设备功能\n\n智能终端最大的优势就是可以通过语音控制智能家居。同样，需要定义一个语义模型实现这个功能：\n\n```python\nfrom typing import Union\n\nfrom iot import SemanticsGroup, SemanticsModel, SemanticsRedirectEnum, SemanticsFromEnum, SemanticsFunc, UniverseNoticeModel, FunctionDeviceModel\n\n\ndef curtain_semantics_model_func(*args) -\u003e Union[FunctionDeviceModel, UniverseNoticeModel]:\n    return FunctionDeviceModel(\n\n        smt_code=\"hi\",\n\n        topic=\"default/curtain\",                        # 发送的Topic，其实后续会被语义模型的Topic覆盖\n\n        is_raw=False,                                   # 不再是纯文本返回了\n\n        acoustics=\"好的，正在为你打开窗帘\",                # 返回给用户的提示信息\n\n        data={                                          # 发送的数据\n            'state': 'on'\n        }\n    )\n\n\n@SemanticsGroup.add_model\nclass SwitchOnSemanticsModel(SemanticsModel):\n\n    code = \"hi\"\n\n    frm = SemanticsFromEnum.USER\n\n    topic = 'default/curtain'\n\n    regex = \"打开窗帘\"\n\n    regex_num = 1\n\n    redirect = SemanticsRedirectEnum.MESSAGE # 重定向给消息，因为需要发送MQTT消息\n\n    func: SemanticsFunc = curtain_semantics_model_func\n```\n\n具体怎么消费这个MQTT消息，即硬件设备如何处理则需要改造硬件，具体参考 **相关资料** 。\n\n3.自定义消息推送\n\n和之前一样，也需要定义一个语义模型：\n\n```python\nfrom typing import Optional\n\nfrom iot import SemanticsGroup, SemanticsModel, SemanticsRedirectEnum, SemanticsFromEnum, SemanticsFunc, UniverseNoticeModel\n\n\ndef button_semantics_model_func(model) -\u003e UniverseNoticeModel:\n\n    #处理设备推送的统一推送模型\n\n    return UniverseNoticeModel(                 # 这次返回的是统一推送模型\n\n        smt_code='hei', \n\n        topic='self/weather',                   # topic，被用来检索语义模型的\n\n        device='remote_server',                 # 设备来源\n\n        verbose=False,                          # 是否多语，这里只需要通知以下用户所以选择False\n\n        message=\"天气播报：短期将有大量降雨\"       # 返回给用户的信息\n    )\n\n\n@SemanticsGroup.add_model\nclass ButtonSemanticsModel(SemanticsModel):\n\n    code = \"hei\"\n\n    frm = SemanticsFromEnum.DEVICE                  # 来自设备\n\n    topic = 'self/weather'\n\n    regex: Optional[str] = None\n\n    regex_num: Optional[str] = None\n\n    redirect = SemanticsRedirectEnum.ACOUSTICS      #直接返回\n\n    func: SemanticsFunc = button_semantics_model_func\n\n```\n至此，可以实现一个简单的物联网终端！\n\n## 进阶功能\n\n如果您对上述基本功能还不满足，可以试一下进阶功能。\n\n1.语音唤醒功能\n\n像主流的智能终端一样，本项目也可已开启语音唤醒功能。该功能是通过内置的 [Pocketsphinx](https://github.com/bambocher/pocketsphinx-python) \n实现的，因此需要安装其依赖，包括swig，C语言环境等，具体可以查看相关文档。\n\n成功安装好依赖后将 `.env` 文件添加以下两行：\n\n```text\nTERMINAL_MODE=0\nDEVICE_REC=PocketsphinxRecorder\n```\n\n再次启动程序可以通过对它说hello或者hi唤醒。\n\n2.生命周期和钩子函数\n\n本智能终端在运行时分为以下几个阶段，在不同的阶段可以调用不同的钩子函数实现流程定制化：\n\n```text\n                                                             ___________________________________循环______________________________________\n                                                             |                                                                           |\n    |加载用户模型| -\u003e  |加载上下文| -\u003e |执行启动钩子| -\u003e |监听用户/设备请求| -\u003e |执行前置语义处理钩子| -\u003e |处理请求| -\u003e |执行后置语义处理钩子| -\u003e|转发请求| -\u003e |执行卸载钩子| -\u003e |卸载|\n                                                             |                                                                           |\n                                                             |——————————————————————————————————循环——————————————————————————————————————|\n```\n\n从上图可以看出，一共有四个钩子函数，分别是 `OnStartUpHook`、 `OnModelPreprocessHook` 、 `OnModelPostprocessHook` 和 `OnTearDown`。可以通过以下方法编写钩子函数：\n\n```python\nfrom iot import HooksGroup\n\n@HooksGroup.on_start_up\ndef start_up(context, semantics_group):\n    ...\n\n\n@HooksGroup.on_tear_down\ndef tear_down(context, semantics_group):\n    ...\n\n\n@HooksGroup.on_model_preprocess\ndef model_preprocess(context, function_device_model):\n    ...\n\n\n@HooksGroup.on_model_postprocess\ndef model_postprocess(context, function_device_model):\n    ...\n```\n\n钩子函数可以获取到执行阶段的上下文，包括各种处理器信息和配置信息。此外，**启动钩子** 和 **卸载钩子** 可以获取语义处理模型的集合而 **前置语义处理钩子** 和 **后置语义处理钩子** 可以获取到语义模型。\n\n3.自定义设备和语音处理器\n\n本智能终端的设备（麦克风和扬声器）都是用的Windows默认的，如果要用在树莓派或者其他环境则需要自定义设备，包括麦克风（Recorder）和扬声器（Player）。\n\n首先实现对应的类：\n\n```python\nfrom iot import RecorderFactory, Recorder\n\n@RecorderFactory.set\nclass MyRecorder(Recorder):      # 继承Recorder类，并加上注解\n    \n    def awake(self) -\u003e bool:          # 实现awake方法，这个方法必须是个阻塞的方法，返回True则开始录音，返回False则推出程序\n        ...\n\n    def record(self, time: int) -\u003e str: # 录音，time为录音时长，返回录音后保存的路径\n        ...\n```\n\n然后在 `.env` 文件中修改默认的麦克风设备:\n\n```text\nDEVICE_REC=MyRecorder\n```\n\n同样，扬声器也是这样的步骤：\n\n```python\nfrom iot import PlayerFactory, Player\n\n@PlayerFactory.set\nclass MyPlayer(Player):\n\n    def play(self, path: str) -\u003e None:    # path为存储语音文本的txt文件路径\n        ...\n```\n\n然后更改 `.env` 文件\n\n```text\nDEVICE_PLY=MyPlayer\n```\n\n您也可以修改默认的语音处理器，包括语音识别（AsrProcessor）和语音合成（TtsProcessor），方法也是一样的。\n\n```python\nfrom iot import AsrProcessorFactory, AsrProcessor\nfrom typing import Optional\n\n\n@AsrProcessorFactory.set\nclass MyAsrProcessor(AsrProcessor):\n\n    def asr(self, path: str) -\u003e Optional[str]: # path为音频文件（一般为wav）的路径，返回语音文字，如果为None则说明处理失败\n        ...\n```\n\n`.env` 文件\n\n```text\nASR_PROCESSOR=MyAsrProcessor\n```\n\n语音合成可以这样修改：\n\n```python\nfrom iot import TtsProcessorFactory, TtsProcessor\n\n\n@TtsProcessorFactory.set\nclass MyTtsProcessor(TtsProcessor):\n\n    def tts(self, text: str) -\u003e str:  # text为需要被合成的文字，返回合成后的音频文件路径\n        ...\n```\n\n`.env` 文件\n\n```text\nTTS_PROCESSOR=MyTtsProcessor\n```\n\n\n## 相关资料\n\n1. [《手把手教你做一个天猫精灵》系列](https://juejin.cn/column/7149407148701663240)\n\n2. [如何实现智能设备](https://juejin.cn/post/7150085767887323149)\n\n3. [智能家居设备交流消息的抓取](https://juejin.cn/post/7151593732062576671)\n\n\n## 待实现功能\n\n1.语音追问功能\n\n2.音频等流媒体的播放\n\n3.语义模型的order","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flittlebutt%2Ffubuki-iot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flittlebutt%2Ffubuki-iot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flittlebutt%2Ffubuki-iot/lists"}