IoT-For-Beginners 进阶实战用 Twilio 为 Azure Functions 地理围栏触发器添加短信/邮件通知【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners导读本文基于 IoT-For-Beginners 项目「运输」课程第 4 课Geofences的课后作业展开讲解如何为已经具备地理围栏Geofence判定能力的 Azure Functions 应用接入第三方通信平台 Twilio从而在 GPS 坐标进入或离开围栏时自动发送短信或邮件通知。读完本文你将掌握 Azure Functions 输出绑定的配置方式、Twilio SMS 与 SendGrid 邮件两种绑定的取舍以及如何在既有地理围栏代码基础上落地仅当进入围栏时通知一次的实战方案。该作业的原始英文文本位于 3-transport/lessons/4-geofences/assignment.md本课程完整讲义位于 3-transport/lessons/4-geofences/README.md对应的可运行示例代码位于 3-transport/lessons/4-geofences/code/functions/gps-trigger。背景从记录距离到主动通知在课程主体部分你已经完成了一条完整的数据链路GPS 传感器上报坐标 → IoT Hub 接收事件 →iot-hub-trigger函数把事件写入 Blob 存储 →geofence-trigger函数调用 Azure Maps 的 Spatial Get Geofence API 判断坐标与地理围栏的位置关系。其中geofence-trigger的判定逻辑只做了日志输出。在仓库示例 geofence-trigger/init.py 中核心判定代码是这样的distance response_body[geometries][0][distance] if distance 999: logging.info(Point is outside geofence) elif distance 0: logging.info(fPoint is just outside geofence by a distance of {distance}m) elif distance -999: logging.info(fPoint is inside geofence) else: logging.info(fPoint is just inside geofence by a distance of {distance}m)distance的语义来自 Azure Maps Geofence API正数表示点在围栏外负数表示在围栏内当距离超过搜索缓冲区默认 50m可配置 0500m时返回999外或-999内。本次作业的目标就是把这个只写日志的环节升级为主动通知当 GPS 坐标位于地理围栏内部时向相关人员发送一条短信或一封邮件从而让卸货团队在卡车抵达处理中心前就做好准备。前置知识Azure Functions 的绑定Bindings机制Azure Functions 采用声明式绑定Bindings来连接外部服务触发器Trigger负责进入函数的数据源输出绑定Output Binding负责离开函数的写入目标。绑定关系在函数的function.json中声明。以仓库中的geofence-trigger为例其 function.json 声明了事件触发器{ scriptFile: __init__.py, bindings: [ { type: eventHubTrigger, name: events, direction: in, eventHubName: samples-workitems, connection: IOT_HUB_CONNECTION_STRING, cardinality: many, consumerGroup: geofence, dataType: binary } ] }要点说明type: eventHubTrigger表示该函数由 IoT Hub / Event Hub 事件触发consumerGroup: geofence指向你在本课新建的消费者组区别于iot-hub-trigger使用的$Default参见 iot-hub-trigger/function.json保证两个触发器各自独立消费事件而不互相抢占cardinality: many表示一次可批量接收多条事件对应 Python 代码中main(events: List[func.EventHubEvent])的签名。作业要求的做法是在此基础上追加一个输出绑定。Azure Functions 官方提供两类与 Twilio 相关的输出绑定Twilio SMS 绑定通过 Twilio 平台发送文本短信。适合通知对象在手机端、对实时性要求高的场景。Twilio SendGrid 绑定通过 SendGridTwilio 旗下的邮件平台发送电子邮件。适合需要携带较多上下文、留档追溯的场景。两类绑定都属于输出绑定配置方式与普通存储/HTTP 输出绑定一致差别仅在type、name与连接字符串设置项上。第一步注册 Twilio 免费账户前往 Twilio 官方网站注册一个免费账户作业原文指向 Twilio.com注册入口即官网首页。免费账户通常附带一个用于开发测试的额度trial credit足够完成本作业的短信或邮件发送验证。注册完成后从 Twilio 控制台Console获取本账户的Account SID与Auth Token它们会用于在 Azure Functions 中配置 Twilio 绑定的连接字符串。若选择短信方案还需要在 Twilio 控制台完成一个Twilio 电话号码的申请/验证免费账户默认只能向已验证的手机号发送短信并在后续请求参数中作为发件人号码使用。⚠️ 免费账户对发送对象有限制通常只能发给已验证号码正式环境需要升级账户并按量付费本文以开发验证为目的描述。第二步阅读官方绑定文档明确配置项作业明确要求先阅读两份官方文档再动手Azure Functions Twilio 绑定文档Python 标签页说明 SMS 输出绑定的function.json声明格式、name与连接设置的命名方式以及函数代码中如何通过func.Out返回消息对象。Azure Functions SendGrid 绑定文档说明邮件输出绑定的声明方式以及from发件人、to收件人、subject主题、textContent/htmlContent正文等字段的填充方式。两份文档的核心思想一致绑定本身只负责把消息对象交给服务具体发送逻辑由平台完成函数代码无需引入 Twilio SDK。这也正是绑定与直接在代码里调用 SDK的本质区别——绑定把第三方服务的连接细节从业务代码中剥离出去。第三步在 Functions 应用中添加通知绑定结合仓库现有代码推荐按以下步骤落地。以下以**短信Twilio SMS**方案为例邮件方案会在文末给出等价配置差异。3.1 修改function.json追加输出绑定在geofence-trigger的 function.json 中于现有bindings数组内追加一个对象{ type: twilioSms, name: message, accountSidSetting: TwilioAccountSid, authTokenSetting: TwilioAuthToken, from: 1XXXXXXXXXX, direction: out }字段说明字段含义取值建议type绑定类型短信为twilioSms邮件为sendGridname函数签名中的形参名本文示例为messageaccountSidSetting存放 Account SID 的应用设置键名建议与下文local.settings.json键名一致authTokenSetting存放 Auth Token 的应用设置键名同上from发件人号码Twilio 分配给您的号码需替换为实际号码direction方向输出绑定固定为out邮件SendGrid方案的差异type改为sendGrid并把from换成发件邮箱to、subject、正文内容通常在代码侧的对象字段中提供。3.2 在local.settings.json中登记敏感信息仓库中的 local.settings.json 是所有触发器共享的本地配置注意其备注——local.settings.json在 Function App 内的所有触发器间共享当前结构如下{ IsEncrypted: false, Values: { FUNCTIONS_WORKER_RUNTIME: python, AzureWebJobsStorage: UseDevelopmentStoragetrue, IOT_HUB_CONNECTION_STRING: connection string, STORAGE_CONNECTION_STRING: connection string, MAPS_KEY: subscription key, GEOFENCE_UDID: UDID } }请按function.json中声明的键名追加TwilioAccountSid: your Twilio Account SID, TwilioAuthToken: your Twilio Auth Token⚠️local.settings.json仅用于本地调试其中的连接字符串与密钥不应提交到版本库部署到云端时需要通过az functionapp config appsettings set之类的命令把同样的键值上传为 Azure 应用设置Application Settings详见 2-farm 课程第 5 课 部署与应用设置上传指引。3.3 修改__init__.py仅在围栏内发送通知作业有一个关键约束在坐标位于围栏内和坐标位于围栏外两种状态中只通知其中一种不能都发。仓库示例geofence-trigger/__init__.py的判定分支distance 999/distance 0/distance -999/ 其他天然适合改造——你只需在选定的分支中把日志替换为消息发送即可。以仅当点位于围栏内时发送短信为例在main函数中把message形参与function.json的name对应声明为func.Out[str]并在进入围栏的分支中写入消息from typing import List import logging import json import os import requests import azure.functions as func def main(events: List[func.EventHubEvent], message: func.Out[str]): maps_key os.environ[MAPS_KEY] geofence_udid os.environ[GEOFENCE_UDID] for event in events: event_body json.loads(event.get_body().decode(utf-8)) lat event_body[gps][lat] lon event_body[gps][lon] url https://atlas.microsoft.com/spatial/geofence/json params { api-version: 1.0, deviceId: gps-sensor, subscription-key: maps_key, udid: geofence_udid, lat: lat, lon: lon } response requests.get(url, paramsparams) response_body json.loads(response.text) distance response_body[geometries][0][distance] if distance -999 or distance 0: # 点位于地理围栏内部或处于搜索缓冲区内侧→ 发送通知 message.set(fTruck is inside the geofence) logging.info(Notification sent: point is inside geofence) else: # 点在围栏外 → 只记录日志不发送通知 logging.info(fPoint is outside geofence, distance {distance}m)代码要点message.set(...)是输出绑定在 Python 中的写入方式函数返回后平台负责把字符串内容交给 Twilio 发送判定条件distance -999 or distance 0覆盖深在围栏内-999与距围栏边界 50m 缓冲区内侧两种情况与仓库原代码中围栏内/外的判定口径保持一致若选择邮件方案可将message的类型改为func.Out[func.SendGridMessage]并填充to、subject、content等字段其余结构不变。3.4 本地运行与云端部署本地运行func start或按项目惯例使用 VS Code Azure Functions 扩展用虚拟设备或手机热点改变 GPS 坐标观察是否仅在进入围栏时收到短信/邮件。确认无误后把修改后的function.json与__init__.py部署到云端的 Function App。注意同步上传新增的TwilioAccountSid、TwilioAuthToken应用设置否则云端运行时会因找不到环境变量而报错。若本地与云端同时运行且都订阅了同一消费者组会产生重复处理可参照课程正文的做法用az functionapp stop临时停掉云端实例避免干扰验证。第四步按评估标准自测作业附带的评分表Rubric如下可作为验收清单标准优秀Exemplary合格Adequate待改进Needs Improvement配置函数绑定并收到邮件或短信能配置函数绑定并在坐标位于围栏内或外其中一种状态时收到邮件或短信能配置绑定但未能发出邮件或短信或坐标在围栏内外两种状态都会触发发送未能配置绑定也未能发出邮件或短信自测要点绑定是否生效进入围栏能否收到通知是否只发一种状态离开围栏时不应再次收到通知排除内外都发的情况配置完整性function.json、local.settings.json、云端应用设置三处配置是否一致密钥安全Token 类敏感信息是否只存在于应用设置中而非硬编码在源码里。常见问题与排错思路收到BadRequest/ 绑定初始化失败优先检查function.json中accountSidSetting、authTokenSetting指定的键名是否与local.settings.json/ 应用设置中的键名完全一致。短信发不出去确认 Twilio 号码已完成验证、接收方手机号在免费账户的白名单内确认from使用 Twilio 分配给账户的号码含国家码。邮件发不出去确认 SendGrid 发件人Sender已完成域名/邮箱验证且to地址合法。内外都收到了通知检查判定分支是否把两个方向都写了message.set(...)作业明确要求只通知一种状态。部署后本地正常、云端不触发检查云端 Application Settings 是否已上传新增的 Twilio 配置并确认consumerGroup: geofence在云端同样存在该消费者组由az iot hub consumer-group create创建与本地环境无关云端直接沿用。延伸从单围栏到多围栏课程正文的挑战环节Challenge指出FeatureCollection中可以包含多个带不同geometryId的多边形只要在properties.geometryId上保持唯一即可一次上传。若你在作业基础上继续扩展可以上传多围栏 GeoJSON然后遍历response_body[geometries]而不是固定取[0]找出距离最近或命中的那个围栏再决定是否通知——这与仓库示例中distance response_body[geometries][0][distance]的单围栏假设形成对照也是把通知做得更贴合真实业务如区分厂区、卸货区、禁行区的自然演进方向。总结本作业把课程中判断 GPS 坐标是否在围栏内的日志逻辑升级为进入围栏即自动通知的闭环能力通过 Azure Functions 的声明式输出绑定接入 Twilio短信与邮件二选一且严格限定只在一种状态触发。结合仓库中 geofence-trigger 的现有代码你可以在不改动地理围栏判定核心的前提下用最小代码量获得卡车即将抵达的实时告警——这正是课程所在供应链场景中提前组织卸货人力、减少车辆等待的关键一步。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考