亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

支持 Alexa 的 USB 电源开关

组件和用品

Arduino MKR1000
× 1
0.1uF 0805 电容
× 8
LED(通用)
× 4
按下按钮(长)
× 4
INA219 (soic 8)
× 1
LM3526M
× 2
USB 插座(垂直)
× 4
1k 0805 电阻
× 4
0.1 欧姆电流检测电阻
× 1
1uF 0805 电容
× 1

必要的工具和机器

3D 打印机(通用)
烙铁(通用)

应用和在线服务

亚马逊 Alexa Alexa 技能套件
Tinamous
亚马逊网络服务 AWS Lambda

关于这个项目

Alexa,打开 ThingyStick...

背景

越来越多的设备由 USB 供电,其中许多往往是没有互联网连接或家庭自动化选项(例如 LED 灯)的“愚蠢”设备,我们如何远程自动化或控制它们?也许将 USB 电源插入电源开关,这有点矫枉过正,尤其是当我们想要单独控制 4 个设备时!

该项目允许您通过互联网控制 USB 供电设备的电源,通过使用 Alexa 的 Tinamous SmartHome Skill,您可以为您的哑 USB 设备启用语音控制。

目前市场上很少有设备可以远程控制 USB 电源,当我开始这个项目时,我没有找到任何(在英国),但最近出现了一些作为多组插座的一部分(是的,这个想法很久以前开始,在一个遥远的星系),这些不是由知名的家庭自动化制造商,而是由无品牌制造商(即 ZLD-34UK)所以我们有一个问题,他们使用谁的设备云,数据将被中国再回来,如果那个制造商不再存在会怎样,它的安全性如何,软件的可用性如何,下周它是否会在回收箱中,以及互联网连接设备的许多其他正常问题,更不用说没有以与开源 Arduino 驱动的设备相同的方式进行黑客攻击。

用例

我们可能希望控制的 USB 供电设备示例:

  • USB 供电的灯
  • Kindle Fire / Chrome cast 棒(特别是在儿童房中,以阻止他们看电视)
  • USB 加湿器
  • Echo Dot(让 Alexa 自己关闭一夜?或者只是重启设备)
  • 开发板。需要重新启动该项目,因为您的代码进入了无限循环?
  • 难以访问但需要偶尔重启的设备(即阁楼中的传感器)。
  • 安装在我们希望确保其通电的客户端的设备(通过测量电流消耗和输入电压)

简单的电源控制: 通过 Alexa 语音控制或通过 Tinamous 的其他命令启用 Internet 电源切换。开和关。

智能电源控制: 很多 USB 灯都有触摸控制来开灯,这意味着我们不能远程开灯,但我们可以关掉它,很多时候这就是我们想要的(尝试睡觉,把灯开着? 出门,要关掉所有的灯?)。

但是,一旦我们使用 Alexa 关闭了 USB 灯,我们就必须让 Alexa 打开灯,然后才能打开它,这太愚蠢了。启用智能电源后,关闭命令将在恢复设备电源之前关闭灯电源几秒钟。够把灯关掉,之后还能正常工作。

定时器自动化: 让您的设备在设定的时间自动关机。孩子们在火上看亚马逊电视总是迟到?晚上 8 点自动关闭 USB 电源。

电源监控: 如果您正在开发 USB 供电的硬件,您可能很想知道您的设备消耗了多少电流,尤其是当它第一次打开时,或者您可能想了解电池组的充电情况。使用板载 INA219,您可以监控电流消耗(我毫不费力地管理了大约 1kHz 的采样)。高电流下 USB 引线上的压降也可能是一个问题,INA219 监控进入设备的电源,因此我们可以警告低电压。还提供了接线端子以允许使用更高的电流和更大的电缆。

电源故障: 通过使用 MKR 1000 上的电池选项,我们可以监控 USB 电源电压并在输入电源出现故障时发送通知。这对于使用 USB 电源但需要一些额外监控的远程(异地)解决方案可能很有用,或者只是作为您房屋的简单主电源故障检测。

硬件

该项目相当简单,以 Arduino MKR1000 为核心,使用两个 LM3526M 的 USB 电源切换提供高端切换和故障检测(低电压、过流),以及使用 INA219 的电源监控(电压和电流),最后用于本地控制选项的 LED 和开关。

我在 DirtyPCBs.com 制作了一块 PCB,您也可以将 .brd 文件发送到 OSHPark.com 以制作一些。 Arduino 插座在每个引脚的两侧都有 pcb 焊盘,以允许黑客入侵。例如你可以很容易地添加一些环境条件传感器,或者一个小的 OLED 显示器来显示电压和电流。

在 github 存储库中,它们是 2 端口和 4 端口选项。小心 2 端口 PCB,因为 我搞砸了 并且弄错了 USB 插座的布局(它们回到了前面 - 错误的极性 !)。

胜利 来自失败之口:

事实证明,将 USB 插座安装在电路板背面实际上是一个不错的解决方案,这意味着引脚连接是正确的(但是对于 2 端口电路板,这也意味着丝印在错误的一侧!)。带有插座中的接头的 Arduino 被推到了空间,其高度需要将 USB 插座从外壳中取出,因此实际上效果更好,我决定在背面重新制作带有插座、开关和 LED 的电路板侧面并添加两个额外的端口,因此创建了四端口版本(此外,我将 LED 可怕地对准了 2 端口,因此也得到了修复!)。

他们几乎没有阻止将其扩展到 6 或 8 端口切换器,尽管 LED 和开关可能需要删除或改进。

构建原理图看起来要复杂得多。许多电阻器是可选的。电阻R23、19、27、26都是开关的上拉电阻,同样R20-22、R14、R15都是USB控制和故障检测的上拉电阻。这些都可以通过 Arduino 中的 INPUT_PULLUP 引脚模式完成,但是,如果您想让 Arduino 进入低功耗睡眠状态并使用中断来唤醒它,您可能希望填充这些,以便它们不会浮动(和反弹) .

我还在 USB D+/D- 线周围添加了可选电阻。可以安装这些来告诉设备它可以使用多少功率,但对于许多愚蠢的设备,这些无论如何都被忽略了。实际上只需要低于 R24 的 LED 电流限制。 R2-5和R28留空。

LED 和开关也是完全可选的。如果你只是想要一个远程控制 USB 的独立盒子,请不要添加这些部件。

电源输入

该控制器可以通过三个选项供电。

第一个是“内部”选项(连接 JP6 引脚 1 和 2),USB 电源来自 Arduino 的 5V 引脚(因此来自 Arduino USB 连接器)。但是,这应该仅用于低功率负载。

其他选项用于外部电源(连接 JP6 引脚 2 和 3),然后您可以通过 J2(板载 USB 微型连接器)或 JP8(接线端子)连接 5V。您不应同时使用这两个选项。外部电源也路由到 Arduino VIn 引脚,因此它也不需要自己的电源选项。

对于奖励点,将 0R 电阻器安装到 R10 和 R11,以及 J2 为 USB 3 提供 USB 直通,因此我们可以重新启动 USB 连接的设备,这在开发硬件时非常方便,而且您不想磨损 USB 插座电脑!

外壳

该项目包含一个 3D 可打印外壳。它使用 M3 热配合插件进行 PCB 和盖子连接,尽管盖子上的公差足以实现摩擦配合。

盖子包括几个选项。

  • 带或不带电池仓。
  • 带或不带支脚(也称为安装孔,用于将盒子固定在表面上)。

同样,可以配置(使用 OpenSCAD)底座盒以包括三个电源中的每一个的开口。

花了好几次才把外壳弄好。你如何版本化你的印刷品?我来自 Rigid.Ink 粉丝俱乐部的样品非常有用。

与 Tinamous 建立联系

我们使用 Arduino MKR1000 来控制插座,所以我们有 WiFi 连接。如果您不熟悉此开发板,则需要将开发板选项添加到您的 Arduino IDE。

我们将使用 Tinamous MQTT 服务器进行连接,主要是因为它很棒,但也可能是因为我是创始人/开发人员/茶师!我们将订阅发送到设备的消息的状态发布主题。 (即“Status.To”主题)。

在开始编码之前,我们需要确保 Arduino 具有最新的固件以及所需的 SSL 证书,以安全连接到 Tinamous。显然,如果您愿意,可以将其调整到您自己的本地 MQTT 服务器,而不必太担心安全性。

第一步

打开 Arduino IDE 并加载 FirmwareUpdater 来自 WiFi101 示例菜单的草图。将此上传到您的设备。

步骤 2

上传后选择 WiFi101 固件更新程序工具 菜单。

步骤 3

测试您的连接,然后更新固件 .完成后,使用添加域 按钮并添加 tinamous.com 确保 Arduino 拥有正确的 SSL 证书。按将证书上传到 WiFi 模块 按钮上传证书。

第 4 步

现在我们可以编写我们自己的固件了。您将在 GitHub 存储库中找到附加到该项目的文件(GitHub 将具有最新版本)。

我们将使用 WiFi101 和 MQTT 客户端到您的 Arduino 草图。

选择 MQTT by Joel Gaehwiler 选项。

文件 secrets.h 需要填充您的 WiFi 和 Tinamous MQTT 设置,出于明显的原因,我没有包含我的副本。

WiFi 和 MQTT 服务器设置:

#define SECRET_SSID "Your SSID"#define SECRET_PASS "Your SSIDs Password"/************************* Tinamous MQTT设置*********************************/#define MQTT_SERVER ".tinamous.com"#define MQTT_SERVERPORT 8883 #define MQTT_USERNAME "UsbSwitch."#define MQTT_PASSWORD "你的密码在这里。"#define MQTT_CLIENT_ID "UsbSwitch"#define DEVICE_USERNAME "UsbSwitch" 

如果您尚未注册 Tinamous,您可以在此处创建您自己的免费帐户。当您注册时,系统会要求您提供帐户/组织名称,这将成为您自己的 Tinamous 私人区域,您可以邀请其他成员(包括 Alexa)加入该区域,并与您的群组共享您的设备。

下面我将我的帐户称为“AlexaExample”,这是我需要包含在 MQTT 设置中的内容,我的 Tinamous 帐户位于 https://AlexaExample.Tinamous.com

第五步

接下来,我们需要添加我们的设备。在 Tinamous Devices 页面上,单击 Add 按钮。

因此,我的设备的 Tinamous MQTT 设置看起来像这样......

/************************* Tinamous MQTT 设置 **************** ******************/#define MQTT_SERVER "AlexaExample.tinamous.com"#define MQTT_SERVERPORT 8883 #define MQTT_USERNAME "UsbSwitch.AlexaExample"#define MQTT_PASSWORD "我的超级秘密密码完全不是密码...."#define MQTT_CLIENT_ID "UsbSwitch"#define DEVICE_USERNAME "UsbSwitch" 

这是我们的 Tinamous 帐户和设备启用。如果您愿意,您可以在此处添加更多设备,只需更新 DEVICE_USERNAME 和 MQTT_USERNAME 的 MQTT 设置(MQTT 不会像 http 那样发送标头信息,因此 Tinamous 不知道您使用的是哪个子域,因此我们需要指定用户名中的帐户)。

步骤 6

将附加的代码上传到您的设备(使用更新后的 secrets.h 文件)。花点时间看看 TinamousMQTTClient.ino 文件,它处理我们的 MQTT 交互,以及发送到我们设备的 Alexa 命令。

我们需要为 SSL 使用 WiFiSSLClient。如果您希望使用没有 SSL 的本地 MQTT 服务器,您可以使用常规 WiFi 客户端并下拉到端口 1883,但对于任何基于 Internet 的内容,请使用 SSL 客户端。

我们还需要为 MQTT 客户端保留比默认缓冲区多一点的缓冲区,这里我们保留了 4096 个字节。

WiFiSSLClient networkClient; MQTTClient mqttClient(4096);  

我们使用 mqttClient.begin 来设置客户端并在 onMessage 中指定一个函数处理程序,当从 MQTT 服务器接收到消息时调用该函数处理程序。

 mqttClient.begin(MQTT_SERVER, MQTT_SERVERPORT, networkClient); // 处理接收到的消息。 mqttClient.onMessage(messageReceived); 

然后我们可以连接和订阅我们感兴趣的主题。在这里你看到我们已经订阅了“Tinamous/V1/Status.To/UsbSwitch”,我们将收到从 Tinamous 时间线发送到 @UsbSwitch 的消息。这就是我们从 Alexa 获取消息的方式。

if (!mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) { if (mqttClient.lastError() ==LWMQTT_CONNECTION_DENIED) { // 这个错误是因为你的用户名或密码错误 } if (mqttClient. lastError() ==-6) { // 这个错误很可能是因为你没有添加 SSL 证书。 } // 重试连接延迟前强制延迟(10000); return false;}// 连接成功。现在订阅主题 mqttClient.subscribe("/Tinamous/V1/Status.To/" DEVICE_USERNAME); 

您可以将 Tinamous 时间线视为您和您的设备的私人 Twitter 版本,他们可以使用 MQTT 或 REST API(或其中一个机器人)查看发送给他们的消息并对其采取行动,以及发布回消息。

我们在 Tinamous 中还有一些工作要做以启用 Alexa 集成,但现在我们可以通过使用时间线和发送消息来测试我们的设备和固件。

如果您使用 Tinamous SmartHome 技能,这就是所需的全部编码。

Alexa 的微小智能家居技能

Tinamous 智能家居技能目前正在等待批准发布(在撰写本文时,手指交叉现在在商店里......)。要制作自己的 USB 切换器,您可以在此技能可用时使用它。

该技能实际上非常通用,它对设备或如何与之交谈一无所知。我们将标签应用于 Tinamous 中的设备,该技能将在 Alexa 帐户中创建一个合适的设备,因此,您可以使用此技能和 Tinamous 来语音启用您自己的项目之一,只需在设备上编写几行代码。

但是,你可能希望改变一些东西,或者写下你自己的技能,所以我会分享我的发展细节。

我在 C# 中为 .Net Core 2.0 编写了该技能,它实际上是为我的 BOFF 智能风扇项目开发的,但是对于这个项目,我将其扩展为允许设备有多个插座(端口),并且每个插座都是一流的Alexa 智能家居设备中的公民。

所有代码(包括一些测试!)都在 Tinamous SmartHome 存储库中,您可以随意克隆、下载或查看。我使用安装了 AWS 工具的 Visual Studio 2017 来帮助将技能推广到 Lambda。

该框架将来自 Alexa 的传入指令消息反序列化为我们可以通过代码访问的对象,根据 headers 命名空间和指令名称采取适当的操作,然后返回适当的响应。

感兴趣的主要消息是:

  • 帐号关联
  • 发现
  • 状态报告
  • 电源控制

帐号关联:

这是由 Alexa 为我们处理的,在我们将技能添加到我们的帐户后,Alexa 将请求身份验证,我们将被带到 Tinamous 授权页面以允许设备访问我们的帐户。在这里您需要输入您的帐户名(在本例中为 AlexaExample)、用户名(Steve)和密码(不,我不会告诉您!)

发现:

关联您的帐户后,Alexa 会提示执行发现,然后该技能会查询 Tinamous 以查找带有“Alexa.SmartDevice”标签的设备 "。没有这个的设备将被简单地忽略。

这些标签是通过在 Tinamous 中的“设备”页面编辑设备来应用的。

如果该设备还标有“MultiPort " 枚举每个端口,并为这些端口添加一个设备。我们还根据设备支持的 Alexa 指令应用标签,这里只是 "Alexa.PowerController " 还有一个标签来指示设备应该在应用中显示在哪个类别下,这里我使用了 "SmartPlug ”.

其他接口也可用,例如 Alexa.BrightnessController,但在这里用处不大。有关更多详细信息,请参阅存储库自述文件。

为了让我们的 MultiPort 设备向 Alexa 公开各个端口,我们还需要在编辑设备页面上设置状态变量。

PortCount 表示设备具有的端口数,然后“Port-1”..“Port-n”给出 Alexa 将用于端口的名称。任何没有名称的端口都将被忽略。您可以在此处轻松更改端口名称并重新运行发现以更新 Alexa。

在发现过程中,该技能还将根据需要查找标记、命名或标记为“powerState”或“powerState-port-n”的字段。如果找到此字段,则将其分配为设备支持的功能(更多信息请参见状态报告)。

状态报告

在发现阶段,我们告诉 Alexa 我们的设备具有哪些功能,该技能默认告诉 Alexa 可以请求这些功能,因此 Alexa 将发送 StateReport 请求以获取这些值。

我们要应用最后一组标签来支持这一点,这次是用于设备字段。一旦您的设备发送数据(这是在 Arduino 代码中通过 MQTT 推送的 senml 消息),Tinamous 将为设备创建字段。然后我们可以使用字段列表中的高级选项来编辑它。使用标签选项是最通用的,因为这意味着我们不需要在固件中正确获取字段名称,或者如果我们想重命名它就卡住了。

如果未找到特定于端口的字段,Alexa 将回退到非特定于端口的字段(此处命名为 powerState)。

电源控制

如果没有这个,我们的设备将无法在 Alexa 中使用! Alexa 将向我们的技能“TurnOn”和“TurnOff”发送两个指令。技能的主函数入口点首先查找命名空间 (Alexa.PowerController),然后将作业交给适当的控制器类 (PowerController.cs)。

然后该技能简单地将状态消息发布到 Tinamous 时间线。

例如:

@UsbSwitch 开启

@UsbSwitch 打开端口 1

其他支持的接口以几乎相同的方式处理。然后由我们的设备来监视此状态消息并执行操作。然后 Alexa 可以使用 StateReport 读回状态。

这就是技能的工作原理。现在我们只需要将它推送到 AWS Lambda 并在 Alexa 控制台上创建一个技能条目,以实际授予 Alexa 访问权限。

创建 AWS Lambda 函数:

我使用 Visual Studio 中的 AWS 工具将编译后的技能推送到 Lambda。但首先我们需要创建 Lambda。

专业提示: 在适当的 AWS 区域中为您支持的语言创建 Lambda。英语(英国)需要定位到欧盟西部(爱尔兰)。

从头开始创建一个新的 lambda 函数。现有蓝图有限且已过时(仅支持 V2 的 SmartHome 界面,该界面非常不同且已弃用 - 我们使用的是 V3)。

您需要创建一个新角色以允许 Lambda 访问它需要的资源。在这里,我们选择 Simple Microservices 作为默认值(它实际上超出了我们的需要)。如果您发现自己没有在 Cloud Watch 中获取日志,您可能还需要通过 IAM 部分为其授予角色权限。

然后我们需要从 Visual Studio 发布二进制文件。安装 AWS 工具后,右键单击项目并选择“发布到 AWS Lambda...”

然后填写 Lambda 表达式的详细信息并点击上传...

上传后,我们可以在 Lambda 上运行一些测试以确保它运行。然后我们需要从操作下拉菜单中“发布新版本”。

一旦发布,我们需要授予我们的技能权限来访问它,

单击“Alexa Smart Home”触发器并输入技能 ID(不过我们还没有....)

在 Alexa 控制台上创建技能:

随着我们的 Lambda 几乎准备就绪,我们需要前往技能开发人员控制台并实际为其创建一个条目。打开 https://developer.amazon.com,选择 Alexa Skills Kit 并添加新技能。

选择 Smart Home Skill API,您希望定位的语言(例如我们在英国的英语(英国)),然后选择 V3(首选)有效负载版本。

在配置页面上,我们进入了更有趣的细节。从我们的版本化 Lambda(屏幕右上角)输入 Lambda ARN。它应该以 :1 或 :2 或 :5246 结尾(如果您有几次尝试;-))。

虽然在 Lambda 中,我们也可以粘贴“应用程序 ID”或“技能 ID”或“ID”或今天从技能中调用的任何名称,但它应该类似于 amzn1.ask.skill.2_______________50。

添加应用程序 ID 后,请务必单击“保存”。在旧控制台中可以在技能名称下的标题中找到id,在新中,erm,打开一个新窗口,返回控制台技能列表,然后单击相应的链接。 (就好像他们从未使用控制台来实际制作技能一样)。

要启用帐户链接,我们需要在 Tinamous 创建一个 OAuth 应用程序,这是使用 Alexa Bot 完成的。前往您的 Tinamous 帐户机器人页面并添加一个 Alexa 机器人。创建后,该对话框将为您提供配置帐户链接所需的所有详细信息。

注意:如果您正在使用(即将...)发布的 Tinamous SmartHome 技能,您就不需要 Alexa Bot。

机器人创建的应用程序将允许任何其他 Tinamous 帐户持有人使用您的技能并链接他们的帐户。当然,您不必公开您的技能,您可以将其保密,他们将无法在您的 Tinamous 帐户中看到任何内容。

同样,如果您使用不同的设备云(说真的,您为什么要这样做;-)),那么您需要输入他们的 OAuth 应用程序详细信息。

在“测试”页面上,确保将“在 Alexa 应用程序中显示此技能”的技能设置为“是”。

保存并前往 alexa.amazon.co.uk(或适合您所在地区的那个),或者显然他们也是一个应用程序......

点击“技能”,然后点击右上角的“你的技能”,然后点击“开发技能”,你应该会看到你的技能用绿色标记列出,表明它是一项开发技能。

在“发布信息”页面配置了“Alexa,关掉usb灯”,以及选择时的附加技能信息,开发时输入信息,无需进行完整的发布。

如果您需要更新技能代码,请上传新的 Lambda 函数,创建新版本,重新添加 SmartHome 触发器和技能 ID,然后将版本化的 Lambda 函数粘贴到技能控制台(您可能可以使用非版本化的 lambda,但是当我尝试时它不起作用 - 尽管当时我也犯了很多其他错误)。

成功!

我们的技能代码在 Lambda 中运行并且技能安装在我们的 Alexa 帐户中,我们可以运行发现,然后开始控制设备。

You can click over to the CloudWatch logs to see the log information written by your skill.

Skill Debugging &Tips

Alexa provides next to no developer feedback when things go wrong, you can spend ages guessing why Alexa doesn't do as you hoped.

  • Avoid most things other than alpha-numerics in your endpointID's (I used * at one stage and everything broke, but not in an obvious way, however # was fine. Go figure!).
  • Log everything. Check for logs when you've invoked your skill. No log then it's probably authentication, or your skill isn't authorized for the Lambda expression.
  • Use matching AWS and Alexa email accounts.
  • Keep the Lambda in the same region as the skill (Ireland for UK skills).
  • If your skill is invoked but Alexa isn't responding to it (i.e. not listing devices), your response format is probably wrong.
  • If you don't want to use your day to day Alexa account you can use Amazon households to add a second adult account. Note however this appears to be limited to 2 adults, and you can't change it without an epic delay.
  • You can ask "Alexa, Switch Profiles" to switch between your developer and regular profiles.
  • I hope with the redesign of the Alexa Console some better debugging information will be available. However right now all I see is bigger boxes and a little better validation. Some logs are available but they are just success logs. aka management level feel good metrics, and delayed by 36 hours which isn't helpful for debugging!

One Skill, Any (IoT) Thing!

With the Tinamous SmartHome skill, as long as your (Internet of Things) thing can connect to the Tinamous MQTT server (or is connected via a supported bot) adding Alexa SmartHome control to your thing is simply a few lines of code to handle messages like "Turn On", "Turn Off", "Set brightness 20". Just add the tags in Tinamous, and....

"Alexa, Discover Smart Home Devices".

代码

  • AlexaUsbSwitcher.ino
  • TinamousMQTTClient.ino
  • UsbControl.ino
  • WiFiClient.ino
  • Secrets.h
AlexaUsbSwitcher.inoArduino
This is the main file.
#include #include #include #include // Provide your own Secrets.h with WiFi and Tinamous definitions in it.#include "Secrets.h"// ================================/*#define MAX_USB_PORTS 2// 2 Port board.int led_pin[MAX_USB_PORTS][2] ={{A5, A6},{0,1}};int switch_pin[] ={A0, A1};// Usb switch B channel -> pin 5 ==USB1int usb_enable_pin[] ={2, 5};int usb_fault_pin[] ={3, 4};bool usb_port_state[] ={false, false};bool usb_power_mode[] ={0, 0, 1, 1};*/// ---------------------------------// 4 Port board.#define MAX_USB_PORTS 4// The 2 port board has bi-color LEDs, 4 port doesn't so use same pin......// LEDs:TX, Rx, D7, D6 (1-4)int led_pin[MAX_USB_PORTS][2] ={{14, 14}, {13,13}, {7,7}, {6,6}};int switch_pin[] ={A0, A1, A2, A3};// USB Enable pins, D1, D3, D4, D5 (not in that order)int usb_enable_pin[] ={5, 4, 1, 3};// Single fault pin (D2)int usb_fault_pin[] ={2, 2, 2, 2};bool usb_port_state[] ={false, false, false, false};// Mode:0 - Switch off as requested.// Mode:1 - Switch off, then on after a delay (useful for LED lights that have touch controls).int usb_power_mode[] ={1, 0, 0, 0};// ================================// Automation options.// time (millis) that the USB port should be switched on/off at.// zero indicates ignore.unsigned long usb_power_switch_on_at[] ={0, 0, 0, 0};// Set> 0 to get processed on first loop.// Side effect is switching them off that those in smart power // mode will schedule to come back on again).unsigned long usb_power_switch_off_at[] ={1, 1, 1, 1};// Current monitor INA219Adafruit_INA219 ina219;// Flag to indicate if one or more USB ports has a fault.bool has_usb_fault =false;// Measured power .float shunt_voltage =0;float bus_voltage =0;float current_mA =0;float load_voltage =0;float power_mW =0;// Min/max float max_current_mA =0;float max_busvoltage =0;float min_busvoltage =20;// track power usage.unsigned long last_measurement_time =0;bool power_failed =false;bool over_current =false;// MQTT publishing.// Probably want it quicker when powering devices.// or slower when not!int update_interval_seconds =20;unsigned long next_message_send_at =0;// =================================================// Main setup entry point// =================================================void setup() { pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); for (int channel=0; channel MAX_USB_PORTS) { return; } // Light up the LED (1..4) based on the setup progress. SetLeds(stage-1 , true, true);}// ===================================================// Main Loop// ===================================================void loop() { // 4 port device, Debug LED is port 4 LED. // if any port 4 is on, then don't switch off the LED. // with all 4 ports off, the debug LED can blink as it likes... if (!hasPoweredPorts()) { digitalWrite(LED_BUILTIN, LOW); } // Check for a fault. bool faulted =false; for (int channel =0; channel  max_current_mA) { max_current_mA =current_mA; } if (bus_voltage> max_busvoltage) { max_busvoltage =bus_voltage; } if (bus_voltage  4.5) { Serial.print("External power restored. Bus voltage:"); Serial.print(bus_voltage); Serial.println(" V"); publishTinamousStatus("External power has been restored."); power_failed =false; } if (bus_voltage <4.2 &&!power_failed) { Serial.print("External power failed! Bus voltage:"); Serial.print(bus_voltage); Serial.println(" V."); publishTinamousStatus("External power lost!"); power_failed =true; } if (over_current &¤t_mA <1500) { publishTinamousStatus("Current fault cleared!"); over_current =false; } if (current_mA> 2000 &&!over_current) { // Overload! publishTinamousStatus("Over Current!"); over_current =true; } }void printPowerWide() { Serial.print("Bus Voltage:\t"); Serial.print(bus_voltage); Serial.print(" V\t"); Serial.print("Current:\t"); Serial.print(current_mA); Serial.print(" mA\t"); Serial.print("Max Current:\t"); Serial.print(max_current_mA); Serial.print(" mA\t"); Serial.print("Min Voltage:\t"); Serial.print(min_busvoltage); Serial.print(" V\t"); Serial.print("Max Voltage:\t"); Serial.print(max_busvoltage); Serial.print(" V\t"); Serial.println();}void printPowerSkinny() { Serial.print(bus_voltage); Serial.print("\t"); Serial.print(current_mA); Serial.print("\t\t"); Serial.print(max_current_mA); Serial.print("\t\t"); Serial.print(min_busvoltage); Serial.print("\t"); Serial.print(max_busvoltage); Serial.print("\t"); Serial.print("["); for (int channel=0; channel next_message_send_at) { Serial.println("------------------------"); Serial.println("MQTT publish measurements"); if (power_failed) { // reduce how often we send when the power // has failed to preserve battery power. sentNextPublishAt(update_interval_seconds * 10); } else { sentNextPublishAt(update_interval_seconds); } // And do one as senml... String senml ="{'e':["; // Voltage senml =senml + "{'n':'busVoltage'"; senml =senml + ", 'v':"; senml =senml + String(bus_voltage); senml =senml + ", 'u':'V'}"; // Max voltage senml =senml + ",{'n':'maxBusVoltage'"; senml =senml + ", 'v':"; senml =senml + String(max_busvoltage); senml =senml + ", 'u':'V'}"; // Min voltage senml =senml + ",{'n':'minBusVoltage'"; senml =senml + ", 'v':"; senml =senml + String(min_busvoltage); senml =senml + ", 'u':'V'}"; // Current senml =senml + ",{'n':'Current'"; senml =senml + ", 'v':"; senml =senml + String(current_mA); senml =senml + ", 'u':'mA'}"; // Max current senml =senml + ",{'n':'MaxCurrent'"; senml =senml + ", 'v':'"; senml =senml + String(max_current_mA); senml =senml + "', 'u':'mA'}"; // mAh consumed... senml =senml + ",{'n':'mAh'"; senml =senml + ", 'v':"; senml =senml + String(0); // TODO! senml =senml + ", 'u':'mAh'}"; senml =senml + ",{'n':'powerState"; senml =senml + "', 'bv':"; if (isPowered()) { senml =senml + "true"; } else { senml =senml + "false"; } senml =senml + "}"; for (int channel=0; channel 0 &&onAt  0 &&offAt  
TinamousMQTTClient.inoArduino
This file handled the MQTT connectivity (i.e. it's the bit that responds to Alexa commands).
// ======================================// Tinamous connectivity via MQTT// ======================================#include #include #include "secrets.h"// WiFi and MQTT settings in Secrets.h// Be sure to use WiFiSSLClient for an SSL connection.// for a non ssl (port 1883) use regular WiFiClient.//WiFiClient networkClient; WiFiSSLClient networkClient; // https://github.com/256dpi/arduino-mqtt// Specifying 4096 bytes buffer sizeMQTTClient mqttClient(4096); // If we have been connected since powered up bool was_connected =false;String senml ="";unsigned long nextSendMeasurementsAt =0;// =================================================// Setup the MQTT connection information// =================================================bool setupMqtt() { senml.reserve(4096); Serial.print("Connecting to Tinamous MQTT Server on port:"); Serial.println(MQTT_SERVERPORT); Serial.print("Server:"); Serial.println(MQTT_SERVER); mqttClient.begin(MQTT_SERVER, MQTT_SERVERPORT, networkClient); // Handle received messages. mqttClient.onMessage(messageReceived); connectToMqttServer();}// =================================================// Connect to the MQTT server. This can be called // repeatedly and will be ignored if already connected// =================================================bool connectToMqttServer() { if (mqttClient.connected()) { return true; } Serial.println("Reconnecting...."); Serial.println("checking wifi..."); if (WiFi.status() !=WL_CONNECTED) { Serial.print("WiFi Not Connected. Status:"); Serial.print(WiFi.status(), HEX); Serial.println();延迟(10000);返回假; } Serial.println("Connecting to MQTT Server..."); if (!mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) { Serial.println("Failed to connect to MQTT Server."); Serial.print("Error:"); Serial.print(mqttClient.lastError()); Serial.print(", Return Code:"); Serial.print(mqttClient.returnCode()); Serial.println(); if (mqttClient.lastError() ==LWMQTT_CONNECTION_DENIED) { Serial.println("Access denied. Check your username and password. Username should be 'DeviceName.AccountName' e.g. MySensor.MyHome"); } if (mqttClient.lastError() ==-6) { Serial.println("Check your Arduino has the SSL Certificate loaded for Tinmaous.com"); // Load the Firmware Updater sketch onto the Arduino. // Use the Tools -> WiFi Firmware Updater utility } // Wait 10s before it gets re-tried.延迟(10000);返回假; } Serial.println("Connected to Tinamous MQTT!"); mqttClient.subscribe("/Tinamous/V1/Status.To/" DEVICE_USERNAME); Serial.println("Subscribed to status.to topic."); // Say Hi. publishTinamousStatus("Hello! Usb switch is now connected. @ me with help for help."); was_connected =true; return true;} // =================================================// Loop for mqtt processing.// =================================================void mqttLoop() { // Call anyway, does nothing if already connected. connectToMqttServer(); mqttClient.loop(); }// =================================================// Publish a status message on the Tinamous timeline// =================================================void publishTinamousStatus(String message) { Serial.println("Status:" + message); mqttClient.publish("/Tinamous/V1/Status", message); }// =================================================// Publish measurements using the plain json format// =================================================void publishTinamousJsonMeasurements(String json) { Serial.println("Measurement:" + json); mqttClient.publish("/Tinamous/V1/Measurements/Json", json); }// =================================================// Publish measurements using senml json format// =================================================void publishTinamousSenMLMeasurements(String senml) { Serial.println("SenML Measurement:" + senml); mqttClient.publish("/Tinamous/V1/Measurements/SenML", senml); if (mqttClient.lastError() !=0) { Serial.print("MQTT Error:"); Serial.print(mqttClient.lastError()); Serial.println(); } Serial.println("Done.");}// =================================================// Message received from the MQTT server// =================================================void messageReceived(String &topic, String &payload) { Serial.println("Message from Tinamous on topic:" + topic + " - " + payload); // If it starts with @ it's a status message to this device. if (payload.startsWith("@")) { payload.toLowerCase(); if (handleStatusMessage(payload)) { Serial.println("@ me status message handled.");返回; } } // Didn't get an expected command, so the message was to us. // Publish a help message. publishTinamousStatus("Hello! Sorry I didn't understand the message. @ me with help for help.");} // =================================================// Message was a Status Post (probably Alexa)// =================================================bool handleStatusMessage(String payload) {char buffer[25]; // for 1..4 (maps to 0..3) for (int port =0; port  0) { Serial.print("Turn on port "); Serial.println(port); setUsb(port, true);返回真; } sprintf(buffer, "turn off port-%01d", port + 1); if (payload.indexOf(buffer)> 0) { Serial.print("Turn off port "); Serial.println(port); setUsb(port, false);返回真; } } // No port specified, turn on all. if (payload.indexOf("turn on")> 0) { allOn();返回真; } if (payload.indexOf("turn off")> 0) { allOff();返回真; } if (payload.indexOf("help")> 0) { Serial.println("Sending help..."); publishTinamousStatus( "Send a message to me (@" DEVICE_USERNAME ") then:" "'Turn on Port-1' to turn on usb port 1," "'Turn off Port-1' to turn off usb port 1," "'Turn on' to turn on all usb ports," "'Turn off' to turn off all usb ports," " \n* Port number can be 1, 2, 3 or 4." );返回真; } Serial.print("Unknown status message:"); Serial.println(payload); return false;}
UsbControl.inoArduino
This file is responsible for the iterations with the USB power switching.
// ======================================// USB Port power control// and indication.// ======================================// Determine if one or more of the ports is poweredbool hasPoweredPorts() { for (int channel =0; channel  
WiFiClient.inoArduino
This file deals with WiFi Connectivity
// ======================================// WiFi handling// ======================================#include "Secrets.h" char ssid[] =SECRET_SSID; char pass[] =SECRET_PASS; int status =WL_IDLE_STATUS; void setupWiFi() { Serial.println("Connecting to WiFi..."); // check for the presence of the shield:if (WiFi.status() ==WL_NO_SHIELD) { Serial.println("WiFi shield not present"); // don't continue:while (true); } // attempt to connect to WiFi network:while ( status !=WL_CONNECTED) { Serial.print("Attempting to connect to WPA SSID:"); Serial.println(ssid); // Connect to WPA/WPA2 network:status =WiFi.begin(ssid, pass); // 等待 10 秒连接:delay(10000); } // you're connected now, so print out the data:Serial.println("You're connected to the network"); printCurrentNet(); printWiFiData();}// ---------------------------------------// WiFivoid printWiFiData() { // print your WiFi shield's IP address:IPAddress ip =WiFi.localIP(); Serial.print("IP Address:"); Serial.println(ip); Serial.println(ip); // print your MAC address:byte mac[6]; WiFi.macAddress(mac); Serial.print("MAC address:"); Serial.print(mac[5], HEX); Serial.print(":"); Serial.print(mac[4], HEX); Serial.print(":"); Serial.print(mac[3], HEX); Serial.print(":"); Serial.print(mac[2], HEX); Serial.print(":"); Serial.print(mac[1], HEX); Serial.print(":"); Serial.println(mac[0], HEX);}void printCurrentNet() { // print the SSID of the network you're attached to:Serial.print("SSID:"); Serial.println(WiFi.SSID()); // print the MAC address of the router you're attached to:byte bssid[6]; WiFi.BSSID(bssid); Serial.print("BSSID:"); Serial.print(bssid[5], HEX); Serial.print(":"); Serial.print(bssid[4], HEX); Serial.print(":"); Serial.print(bssid[3], HEX); Serial.print(":"); Serial.print(bssid[2], HEX); Serial.print(":"); Serial.print(bssid[1], HEX); Serial.print(":"); Serial.println(bssid[0], HEX); // print the received signal strength:long rssi =WiFi.RSSI(); Serial.print("signal strength (RSSI):"); Serial.println(rssi); // print the encryption type:byte encryption =WiFi.encryptionType(); Serial.print("Encryption Type:"); Serial.println(encryption, HEX); Serial.println();}String hostName ="www.google.com";void doPing() { Serial.print("Pinging "); Serial.print(hostName); Serial.print(":"); int pingResult =WiFi.ping(hostName); if (pingResult>=0) { Serial.print("SUCCESS! RTT ="); Serial.print(pingResult); Serial.println("毫秒"); } else { Serial.print("FAILED! Error code:"); Serial.println(pingResult); }} void reconnectWiFi() { // attempt to reconnect to WiFi network if the connection was lost:while ( status !=WL_CONNECTED) { Serial.print("Attempting to connect to WPA SSID:"); Serial.println(ssid); // Connect to WPA/WPA2 network:status =WiFi.begin(ssid, pass); if (status ==WL_CONNECTED) { Serial.print("You're re-connected to the network"); printCurrentNet(); printWiFiData();返回; } delay(5000); } }
Secrets.hArduino
You need to update this with your own settings.
#define SECRET_SSID ""#define SECRET_PASS ""/************************* Tinamous MQTT Setup *********************************/#define MQTT_SERVER ".tinamous.com"#define MQTT_SERVERPORT 8883 #define MQTT_USERNAME "."#define MQTT_PASSWORD "The devices password"#define MQTT_CLIENT_ID "A random client id"#define DEVICE_USERNAME ""

定制零件和外壳

This is the best bet if you don't know how you'll connect. It's got holes for the Arduino, terminal block and additional USB micro.This is the all connectors version, but doesn't include the first layers of text which some printers may struggle with.This is the simplest version and quickest to print.

示意图

Send this off to OSHPark or DirtyPCBs to get your own one made. arduinostandaloneusbswitch-4port_q16AoF01Aq.brd arduinostandaloneusbswitch-v2_Xd45dtjndI.sch
GitHub USB Power Switcher Repository
You want:Arduino/StandAlone/ folder and the 4 port version.https://github.com/ThingySticks/USBPowerSwitcher

制造工艺

  1. 电源
  2. 推土机
  3. C# switch 语句
  4. 电池充电器提供更高的功率密度和更快的充电速度
  5. 断电传感器
  6. Raspberry Pi / Hologram SMS 控制的交流电源开关
  7. 风力
  8. 电锤指南
  9. 什么是自动动力压力机?
  10. 什么是动力卡盘?
  11. 动力卡盘快速指南
  12. 了解水力发电