
IoT-For-Beginners 实战在 Raspberry Pi 与虚拟 IoT 设备上调用无服务器 REST 端点并实现语音定时器【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners导读本文是 IoT-For-Beginners 课程 Set a timer and provide spoken feedback设置定时器并提供语音反馈一课中面向单板计算机Raspberry Pi与虚拟 IoT 设备的任务指南。它承接上一课语音转文字 LUIS 语言理解 无服务器函数的成果当设备把用户语音转成文字后你需要把这段文字 POST 到无服务器 REST 端点由 LUIS 识别出set timer意图并返回定时秒数然后在设备端用 Python 标准库threading.Timer在后台线程中真正把定时器跑起来。读完本文你将掌握完整可运行的get_timer_time、announce_timer、create_timer等核心函数实现理解threading.Timer的线程语义、HTTP 状态码约定并能直接在 Raspberry Pi 或虚拟设备上运行整个smart-timer项目。一、任务背景从语音到定时器的完整调用链在进入本任务之前先回顾整条链路明确本任务所处的位置语音转文字Speech-to-Text设备录制用户语音并交给 Azure Speech 服务返回识别文本例如Set a two minute 27 second timer.语言理解LUIS文本被发送到无服务器函数函数调用 LUIS 预测 API识别出set timer意图与number、time unit实体无服务器函数返回秒数函数把2 分钟 27 秒换算成147秒以 JSON 形式返回本任务设备端设置定时器设备调用该 REST 端点拿到秒数用threading.Timer创建后台定时器在倒计时结束时报出Times up on your ... timer.。对应的无服务器端实现可在 text-to-timer/init.py 中查看其核心逻辑是从请求体读取text调用client.prediction.get_slot_prediction(app_id, Staging, prediction_request)获取预测结果当top_intent set timer时按顺序把number实体与time unit实体一一配对分钟数乘以 60 累加、秒数直接累加最后返回payload { seconds: total_seconds } return func.HttpResponse(json.dumps(payload), status_code200)识别失败意图不是set timer则返回status_code404。这一约定直接决定了设备端get_timer_time的写法以 HTTP 状态码 200 作为调用成功的判据。上一课完整搭建 LUIS 模型与 HTTP 触发器的过程见 2-language-understanding/README.md。二、任务 1把文本发送给无服务器函数设备端的第一步是新增一个get_timer_time(text)函数负责把识别出的文本发给上一课创建好的 REST 端点并解析出定时秒数。2.1 声明函数与定义目标 URL在process_text函数上方声明函数并用URL占位符定义要调用的端点地址def get_timer_time(text): url URLURL的取值取决于你的部署方式详见上一课make your function available to your IoT device一节发布到云端https://APP_NAME.azurewebsites.net/api/text-to-timer?codeFUNCTION_KEY其中APP_NAME是函数应用名FUNCTION_KEY是用az functionapp keys list --resource-group smart-timer --name APP_NAME获取的functionKeys下default项的值本机运行、设备同网访问http://IP_ADDRESS:7071/api/text-to-timerIP_ADDRESS是运行函数应用的电脑在局域网中的 IP端口固定为7071。这种方式要求 IoT 设备与电脑处于同一网络。2.2 以 JSON 形式传递文本并发送请求将文本放入text属性通过requests.post发送body { text: text } response requests.post(url, jsonbody)jsonbody参数会由requests库自动把字典序列化为 JSON并设置Content-Type: application/json与服务端req.get_json()req_body[text]的读取方式严格对应。2.3 解析响应失败返回 0成功调用时服务端返回 200 与形如{seconds: 147}的 JSON失败如意图不是set timer时返回 404。设备端据此做判断if response.status_code ! 200: return 0 payload response.json() return payload[seconds]这里的关键设计是用返回值0表达调用失败或无法设置定时器因为合法的定时时长必然大于 0——这为后续process_text中的if seconds 0判断埋下了伏笔。用return 0而不是抛异常也让主流程保持简单、健壮即使云端不可用也不会让设备崩溃。完整的get_timer_time实现在 code-timer/pi/smart-timer/app.pyRaspberry Pi 版与 code-timer/virtual-iot-device/smart-timer/app.py虚拟设备版中保持一致。三、任务 2在后台线程中设置定时器拿到秒数之后就要让设备真正计时。Python 标准库的threading.Timer正是为此设计的它接收一个延迟时间秒和一个回调函数延迟结束后在一个新线程中执行该函数不会阻塞主程序的其他逻辑。3.1 导入 threading 并实现 say 占位函数在文件顶部加入导入语句import threading随后在process_text上方定义一个say函数用于说出反馈。本任务阶段它只把文字打印到控制台在本课稍后的文本转语音Text-to-Speech步骤中say会被改为真正调用 Azure Speech 服务把文字朗读出来。先把接口定义好后续只需改动这一处def say(text): print(text)3.2 announce_timer定时器到点的播报函数该函数由定时器在倒计时结束时回调负责拼接Times up on your ... timer.这句英文播报def announce_timer(minutes, seconds): announcement Times up on your if minutes 0: announcement f{minutes} minute if seconds 0: announcement f{seconds} second announcement timer. say(announcement)值得注意的细节函数会分别检查minutes与seconds只有该时间单位数值大于 0 时才把对应部分拼入句子。例如分钟数为 0 时播报只会包含秒数Times up on your 27 second timer.避免出现 0 minute 这类冗余表达。拼好的句子统一交给say输出。3.3 create_timer换算时分秒并启动线程定时器create_timer是本任务的核心函数接收总秒数换算成分 秒并启动后台定时器def create_timer(total_seconds): minutes, seconds divmod(total_seconds, 60) threading.Timer(total_seconds, announce_timer, args[minutes, seconds]).start()逐行拆解divmod(total_seconds, 60)是 Python 内置函数同时返回商与余数divmod(147, 60)得到(2, 27)即 2 分钟 27 秒分别解包给minutes与secondsthreading.Timer(total_seconds, announce_timer, args[minutes, seconds])创建了一个总秒数后执行announce_timer的定时器对象args列表中的两个元素会依次作为announce_timer的minutes与seconds位置参数传入.start()立即启动该定时器线程。此时主线程继续运行用户仍可进行下一次语音输入倒计时结束时announce_timer在独立线程中被调用。3.4 反馈定时器已启动紧接着在create_timer末尾追加timer started播报的拼接逻辑规则与announce_timer相同——只包含数值大于 0 的时间单位announcement if minutes 0: announcement f{minutes} minute if seconds 0: announcement f{seconds} second announcement timer started. say(announcement)完整的create_timer含启动播报见 code-timer/pi/smart-timer/app.py。3.5 接入 process_text 主流程最后在process_text末尾把两个任务串起来先从服务端拿到秒数秒数大于 0 才创建定时器seconds get_timer_time(text) if seconds 0: create_timer(seconds)只有当秒数大于 0 时才创建定时器这一条件巧妙地复用了get_timer_time失败返回 0 的设计无论调用失败还是 LUIS 没识别出set timer意图都不会误创建定时器。process_text完整实现见 code-timer/pi/smart-timer/app.py。四、运行验证与预期输出运行前确保函数应用Function App也在运行云端发布或本机运行均可然后启动设备端程序piraspberrypi:~/smart-timer $ python3 app.py Set a two minute 27 second timer. 2 minute 27 second timer started. Times up on your 2 minute 27 second timer.三段输出的含义分别为Set a two minute 27 second timer.——来自语音转文字阶段的识别结果process_text第一行print(text)打印2 minute 27 second timer started.——create_timer中定时器已启动的播报Times up on your 2 minute 27 second timer.——threading.Timer倒计时结束后announce_timer的到点播报。五、两种硬件实现的差异对照本任务的代码按运行平台分为两份结构一致仅在语音采集入口上有区别Raspberry Pi 版code-timer/pi/smart-timer/app.py使用 Grove 按键 PyAudio 录音。capture_audio()在按键按住期间以 16 kHz 采样率采集 PCM 帧并封装成 WAV 缓冲之后convert_speech_to_text(buffer)调用 Azure Speech REST 接口主循环while True中等待按键按下再开始一轮录音 → 识别 → 处理虚拟设备版code-timer/virtual-iot-device/smart-timer/app.py使用 Azure Speech SDK 的SpeechRecognizer连续识别通过recognizer.recognized.connect(recognized)订阅识别事件在recognized回调中把args.result.text交给process_text主循环仅time.sleep(1)保持进程存活。两者中get_timer_time、say、announce_timer、create_timer、process_text的实现完全一致——这也印证了本任务的精髓设备端差异被封装在语音怎么进来这一层而拿到文字后如何设置定时器的逻辑与硬件解耦、可以复用。六、关键设计与边界情况小结HTTP 状态码即业务信号200 表示识别成功并已换算秒数404 表示意图不是 set timer设备端统一以status_code ! 200短路返回 00 的双重含义get_timer_time返回 0 既可能是网络/服务端错误也可能是意图不匹配process_text只需一个seconds 0判断即可安全跳过线程不阻塞threading.Timer让倒计时在后台线程进行主线程可继续处理下一次语音指令符合智能音箱式的交互模型可读性优先的播报分钟/秒分别判空拼接保证英文播报语法自然且该文案集中于say函数为后续接入文本转语音预留了唯一修改点。七、后续步骤本任务对应完整课程的中间环节后续将在本课继续把say从print升级为真正的**文本转语音Text-to-Speech**播报面向 Raspberry Pi 的步骤见 pi-text-to-speech.md面向虚拟设备的见 virtual-device-text-to-speech.md课程级挑战要求你利用 SSML 调整语音的重音、停顿与音调练习项目则是为上一课添加的取消定时器cancel timer意图补齐设备端取消逻辑见 assignment.md。课程整体概览与原理含文本转语音三阶段文本分析、语言分析、波形生成可参考 3-spoken-feedback/README.md。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考