原文:Smart Home Automation with Linux and Raspberry Pi

协议:CC BY-NC-SA 4.0

六、交流:人类会说话。电脑会说话

Abstract

人们常说,语言是使其他一切成为可能的发明。在技术的世界里,语言是使所有其他事物得以存在的协议。为一台独立的机器编写软件是非常好的,但是当它设法与外界接口,通过网络与另一个程序接口,或者控制一个外部硬件时,这似乎更令人满意。用电脑控制哪怕是最简单的机器人,对于外行人(和许多极客)来说,都是令人印象深刻的。)而不是演示行进立方体的优化实现。

人们常说,语言是使其他一切成为可能的发明。在技术的世界里,语言是使所有其他事物得以存在的协议。为一台独立的机器编写软件是非常好的,但是当它设法与外界接口,通过网络与另一个程序接口,或者控制一个外部硬件时,这似乎更令人满意。用电脑控制哪怕是最简单的机器人,对于外行人(和许多极客)来说,都是令人印象深刻的。)而不是演示行进立方体的优化实现。 1

我已经在第一章中介绍了许多能够与外部硬件通信的设备,现在我将讨论人机通信,并演示我们如何与一台机器或一个软件交互,并让它在其他地方控制另一台机器。这包括使用电子邮件、短信和网页。然而,新技术的出现是无情的,随着 iPhone 等设备提供宽带 2 体验,手机的典型作用(作为语音通话、短信或电子邮件的设备)大大降低了。

为什么是通信?

技术领域有四种沟通方式:

  • 计算机对计算机
  • 人与人之间
  • 计算机对人类
  • 人对计算机

出于不同的原因,这些对我们都很重要。第一个在第一章中有所介绍,它允许设备根据一些基于时间或逻辑的程序自动控制。

人与人之间的交流每天都在发生,但现在可以通过技术来促进。在电话出现之前,我们唯一的实时交流方式是面对面交流。现在我们有电子邮件、互联网中继聊天(IRC)、即时消息(IM)和 SMS 来执行同样的任务。都去掉了“面子”元素。

我们还简化了现有的沟通媒介。电话,曾经是低质量和硬连线到一个物理位置,现在是移动的。通过 IP 语音(VoIP)技术,您可以利用互联网的(几乎)免费成本来节省资金,并且当与移动技术结合时,可以促进使用移动电话通过网页在线订购比萨饼的有趣情况!

当我们谈到计算机与人的交流时,我们是在看计算机发送给我们的有关房子的报告和信息。在最简单的情况下,这可能是每天的叫醒电话或包含一天的电视时间表的电子邮件。在更复杂的情况下,它可能是一份关于房间内计算机及其性能的完整报告。 3

最后,人机交流是最常见的,包括我们通过电子邮件、短信或网页告诉机器我们想做什么。为了成为一个真正智能和自动化的房子,这个列表将包括触觉界面。我们不需要发出明确的命令来告诉计算机做什么;它通过研究环境知道该做什么。例如,当前门被打开时,计算机会知道开灯;不久之后,内部门垫传感器将关闭,因为它已经意识到有人正在进入房子。你已经在第二章中构建了类似的触觉功能,所以我将在本章中讨论显式通信。

IP 电话

IP 电话或 VoIP 通信是常见的,也是任何智能家居的预期功能。然而,对大多数人来说,由于电话通信的个人性质,VoIP 安装将是私人的,只存在于个人笔记本电脑或台式机上。但它可以与语音识别结合使用,以提供一种有趣的(尽管容易出错)数据输入方式和一种添加内部家庭内部通信系统的方法。

网络电话

正如胡佛已经成为真空吸尘器的同义词,Google now 是一个意为搜索的动词,Skype 是 VoIP 的代名词。Skype 始于 2003 年,以免费软件的形式发布,为 Linux、Mac 和 Windows 提供了客户端,每个客户端都有不同程度的功能,所有版本都允许您与其他 Skype 用户免费通话,并像任何标准电话一样为移动电话和座机提供补贴语音通话。大多数允许您从几个不同的地方用同一个帐户登录,这意味着您可以用同一个面向住宅的电话号码将 Skype 安装到住宅中的每一个终端上,这样您就可以在住宅中的任何房间发送和接收电话。使用额外的硬件,您可以采用免提方式,在通话过程中在房间之间移动,例如查看晚餐,让您回到自 20 世纪 80 年代无绳电话问世以来就存在的漫游状态!

星号

Asterisk 是另一个基于软件的电话解决方案,它还支持 VoIP、移动电话和固定电话。它对我们的好处是,它是真正意义上的免费软件,可以支持许多协议,因为它是一个完整的专用小交换机(PBX ),可以支持高度可配置的呼叫转移、语音邮件、会议和电话菜单(因此您可以实现自己的“按 1 开灯”系统!).与 Skype 一样,您需要一个服务提供网关来将基于 IP 的协议连接到一般的电话网络。这是一项付费服务,可以从许多地方购买,包括 Skype 本身,它有自己的 Skype-to-Asterisk 模块。作为一种选择,FXO 接口是可用的,它允许您将 SIP 接口到 PSTN。你仍然需要购买 FXO 接口(大约 15 美元),但是你不需要从手机供应商之外的任何人那里购买。

目前安装大量 Asterisk 代码的最简单方法是通过 FreePBX,但即使这样,如果你有一个足够大的房子,使大喊大叫成为不可能,或者你是电话的狂热用户,因为你可以通过电子邮件或网络(现在大多数电话上都有)或短信获得更可靠的沟通,那么即使这样也值得花时间。

电子邮件

电子邮件现在是全世界个人和职业生活的命脉。在任何时候发送和接收来自任何人的消息都是非常容易的——事实上,大多数垃圾邮件文件夹的状态都证明了这一点。但它会一直存在,所以我们可以把电子邮件添加到我们的房子将支持的协议列表中,允许我们向我们的视频、电灯开关或电视发送信息,并让我们的房子发送信息。

在 Linux 中准备电子邮件

电子邮件的传播路径在任何地方都是一样的,由三部分组成:

  • 邮件传输代理(MTA):MTA 也称为电子邮件服务器,是一种通过简单邮件传输协议(SMTP)与其他 MTA 通信的软件,用于将收到的电子邮件路由到正确的收件人,记录目的地址并将其传递到该计算机上的服务器。
  • 邮件检索:这是将电子邮件从邮件服务器传输到客户端的方法。这些数据通过邮局协议(POP)或互联网消息访问协议(IMAP)进行传输。在我们的例子中,这些将在同一台机器上,因为我们将运行我们自己的 MTA,但它们不必如此,因为我们也可以将我们的谷歌邮件下载到我们的本地机器上进行处理,我将在第六章中介绍。
  • 邮件用户代理(MUA):这是用于实际阅读和发送电子邮件的客户端软件。这包括 Thunderbird 等大型 GUI 应用程序、AtMail 等网络邮件解决方案,以及 Mutt 等基于控制台的小型应用程序。

尽管公司的无人驾驶飞机会不停地抱怨 Exchange 作为 MTA ( http://en.wikipedia.org/wiki/Comparison_of_mail_servers )的好处,但你有四个主要的电子邮件服务器可供选择,而且比简单的 Outlook 多得多。此外,由于 Linux(以及一般的类 Unix 系统)的设计,您可以非常灵活地自动处理收到的邮件,并发出非交互式命令来发送回复。

每个 MTA 都有其他人没有的优点和特点。四大巨头——Exim、qmail、Postfix 和 Sendmail——都有自己的拥护者和反对者。我个人使用 Exim,因为它有一个引导式安装,而且之后“就能工作了”。对于不同的观点,有一个 wiki 页面涵盖了这些包的最新版本,以及一些商业产品。你安装其中一个的时候我会在这里等着。

发送电子邮件

安装服务器并通过给自己(和另一个用户)发送一两封电子邮件来测试它之后,您就可以开始编写自动发送脚本了。这是在 Linux 上最容易做到的事情,涉及到mail命令,它发送带有任意数量的附加标题和设置的电子邮件。这里,您只需要一个抽象脚本,如下所示:

#!/bin/bash

SUBJECT=$1; shift

TOADDR=$1; shift

MSG=$*

echo "$MSG" | mail -s "$SUBJECT" "$TOADDR"

可以这样称呼它:

xmitemail "Hello" "steev@workaddress.com" "I bet you didn't think this would work!"

该命令将发送所示的简单电子邮件,并且可以通过在命令行上键入它来调用,从日常 crontab 触发它,或者作为一些其他家庭事件的结果来运行。例如,有人从前门进来(使用第二章中的 Arduino 门垫)可能会发出这样的电子邮件,或者当其中一个硬盘太满时,它可能会作为警告发送。

我在这里颠覆了原来的界面为mail,因为用户以前面显示的方式调用命令会更常见。但是,有时您会希望通过允许脚本接受来自 STDIN 的任何输入来恢复到最初的使用方式。这需要这里显示的三行替换来取代 MSG:

if [ $# -eq 0 ]; then

while read LINE ; do

MSG="$MSG""^M""$LINE"

done

else

MSG=$*

fi

请注意^M字符,它是通过 Ctrl+V 后跟 Ctrl+M 输入到类似vi的编辑器中的。现在可以从文件中输入消息,如下所示:

cat filename | xmitemail "Here's the file" "steev@myworkaddress.com"

在第七章中,你将学习如何扩展这个功能来支持一个基本的地址簿和多个接收者。

自动处理电子邮件

代表程序而不是人类用户接受电子邮件,可以用一个词来概括:Procmail。Procmail 是 Stephen R. van den Berg 于 1990 年开始的一个项目,旨在控制电子邮件消息的传递,尽管有些人认为它是一个死项目,但这使它成为一个稳定的项目,不太可能很快中断或引入新的复杂问题!

Procmail 由电子邮件服务器(MTA,如 Exim)触发,它将每条消息传递给一系列配方中的每一个,以便进一步处理。如果这些方法都没有声明该消息,那么它将正常传递。

我将从创建一个简单的例子开始,通过这个例子你可以用电子邮件发送你卧室的电灯开关。因此,使用以下内容创建一个用户,并填写所有必要的用户详细信息:

adduser bedroom

然后,创建一个.procmailrc文件(注意点!)中,并添加以下食谱代码:

:0

* ^From steev

* ^Subject: light on

|heyu turn bedroom_light on

这要求发送者是斯蒂夫 5 并且主题在运行heyu命令控制灯之前是“灯亮”的。这两个条件都必须满足。您可以并且应该扩展这些参数,以包括完整的电子邮件地址(以防止任何 steev 控制灯光)和一个正则表达式,使主题行不区分大小写。但在我们继续之前,我将分解这些元素。

每个配方由三部分组成:

  • 模式:这通常是:0,但也可以通过附加另一个冒号和一个锁文件的名称(例如:0:mylock)来包含锁定指令(这样该配方就不能同时运行多次)。
  • 条件:零行或多行(以星号开头),表示电子邮件必须如何显示才能进行处理。这也支持正则表达式。因为每个条件都必须以 AND 逻辑方式满足,所以您可以通过不包含任何条件行来接受所有邮件。
  • 操作:最后一行指示消息是应该转发到另一个电子邮件帐户(带有! forwarded@othermail.com)、传递到脚本或程序(| command arguments)还是仅仅复制到一个文件(文件名,不带前缀字符)。为了支持多个动作,你将需要执行一些重魔法(涉及多个食谱,:0c模式,或者分支处理;详见 http://partmaps.org/era/procmail/mini-faq.html#recipe-block )。

每个配方按顺序进行评估,直到找到一个满足所有条件的配方,然后停止。您可以通过使用formail工具来验证 Procmail 的输入,作为总括配方中操作的一部分:

:0

|formail >> ∼steev/procmail-log

您可以打开一个单独的终端窗口,键入以下内容,然后观察邮件信息的显示,从而实时查看这些信息:

tail -f ∼steev/procmail-log

您还可以在调试 Procmail 调用的脚本时使用这种技术,方法是复制一封已发送的电子邮件,并将其重定向到脚本的输入。您还可以使用LOGFILE指令来调试 Procmail 脚本。这里有一个例子:

LOGFILE=$HOME/procmail.logfile

.procmailrc脚本本身也具有标准bash脚本的一些功能,因此您也可以为命令准备PATH变量,并预处理邮件以提取主题行,如下所示:

PATH=/usr/bin:/usr/local/bin:/usr/local/minerva/bin

SUBJECT=formail -zxSubject:` ```

Note

有些安装还要求您创建一个包含单行"|/usr/bin/procmail"(带引号)的.forward文件,以便触发 Procmail。此时 Procmail 不是您的本地邮件递送代理。

你现在可以创建一个单独的再次关灯的方法,它会像你期望的那样简单。但是,为了提高灵活性,我将展示如何运行一个单独的脚本,该脚本也查看电子邮件的正文,并将邮件作为一个整体进行处理,以便您可以包含调暗或提高亮度的命令。首先将主题作为参数 6 和电子邮件内容(标题和正文)传递到 STDIN,这是从一个新的菜谱启动的:

:0

* ^From - steev.*

* ^Subject: light

|∼steev/lightcontrol $SUBJECT

然后使用lightcontrol脚本将正文连接成一个长字符串,用空格而不是换行符隔开:

#!/usr/bin/perl

# Skip the header, i.e. any non-empty line

while(<STDIN>) {

last if /^\s*$/;

}

my $body = "";

my $separator = "";

# Begin the message with the subject line, if it exists

if (defined $ARGV[0]) {

$body = $ARGV[0];

$separator = " ";

}

# Then concatenate all other lines

while(<STDIN>) {

chomp;

if ($_ !∼/^\s*$/) {

$body .= $separator;

$body .= $_;

$separator = " ";

}

}

然后,您可以处理$body来控制灯光本身,使用直接比较(意味着文本必须包含命令,并且只包含命令)或简单的正则表达式来允许它出现在任何地方,就像“dim”的例子一样。

if ($body eq "light on") {

system("heyu turn e3 on");

} elseif ($body eq "light off") {

system("heyu turn e3 off");

} elseif ($body =∼ /light dim (\d+)/) {

system("heyu dimb e3 $1");

}

Note

请记住,所有脚本都必须具有 execute 属性。

有了这些简单的规则,您现在可以为家中的每个房间创建用户帐户(以及相应的电子邮件地址),并添加脚本来控制您认为合适的灯、电器和茶壶。

Note

您可以使用语音识别宏来开始(和停止)录音,从而扩展我们在第二章中创建的听写程序。

你也可以使用一个house@电子邮件地址来处理更复杂的任务,比如等待一条写着“回家”的信息,然后等一个小时(或者无论你的通勤时间有多长)再提前打开茶壶,以及门廊和客厅的灯。这创造了一个受欢迎的景象,没有浪费任何电力。或者你可以将.procmailrc脚本放在你自己的电子邮件账户上,以查看来自你女朋友的邮件(当然,这些邮件非常重要,必须立即回复!)或包含单词 free 和 beer 的线程上,按此顺序!要阻止 Procmail 处理该邮件并丢弃它,您必须在将邮件传递给 recipe 之前“克隆”该邮件,方法是在第一行添加一个c。以下示例通过在收到此类邮件时发出语音通知并将原始邮件发送到收件箱来演示这一点:

:0c

* ^From- steev.*

|/usr/bin/play /media/voices/messages/youve-got-mail.wav

安全问题

作为一种纯文本的数据传输方法,电子邮件经常被比作明信片而不是信件的发送,因为它的内容(理论上)可以被途中的任何传送服务器读取。它也是一个公共协议,允许世界上的任何人向您的服务器发送消息。这两个因素结合在一起,很难确保没有人会试图给你的电灯开关发电子邮件。

我在这里采取了一些基本的预防措施,包括以下几点:

  • 电子邮件地址或格式的保密
  • 严格的命令格式(大多数情况下,电子邮件签名会导致解析失败)
  • 不对正确或不正确的消息进行确认
  • 限制发送者(尽管是原始的)

同样,我们通过默默无闻获得了安全感。但是,即便如此,黑客仍然有可能制造麻烦。如果您打算将电子邮件用作主要渠道,那么值得花费时间和精力来确保它的安全,方法是安装 GnuPG,为您的所有电子邮件帐户生成证书,并使用它们的公钥来验证发件人。这确实意味着新用户不能控制房子,除非首先由系统管理员手动确认他们的密钥。这种方法唯一失效的时候是当你无法访问一个注册的电子邮件帐户时(例如,当你在度假时),你需要从一个临时地址发送一个命令。然而,这是一种罕见的情况,希望通过 SSH 连接来处理如此严重的问题,或者为这种紧急情况配置一个合适的备用电子邮件帐户。

为了更快地安装,并且可以在任何地方工作,可以在服务器上保存一个循环的密码列表,并且电子邮件必须声明列表中的第一个密码可以被访问。一旦通过验证,就会执行该命令,列表循环往复,第一个元素被推到底部:

tail -n +2 list >tempfile

head -n 1 list >>tempfile

mv tempfile list

通过这种方式,任何看着你输入电子邮件或监控你的流量的人都只能使用旧密码。

自然,两种方法都可以结合起来。

声音

使用语音进行交互控制是许多人的目标,尤其是在询问家庭自动化时。我个人怪《星际迷航》上的会说话的电脑!但是所有的交流都需要两个部分,说话者和听者,自然语言的流动性使得这两个任务都很困难。然而,这两个领域都取得了良好进展。

理解声音输入是一个由两部分组成的问题。第一个涉及理解实际说过的话,这与语音识别软件有关。第二种要求计算机理解这些单词的意思以及应该如何解释它们。用这些信息做一些事情的命令,比如开灯,是比较容易的。因为目的是控制你家里的物品,而不是命令电子邮件或信件,所以意思可以由你创建的一组规则来管理。因此,每个命令都必须以computer开头,例如,后跟一个设备名称(bedroom lights),再跟一个特定于该设备的命令(switch on)。再说一遍,我怪《星际迷航》!

对于那些使用多种语言的家庭来说,还需要额外考虑目标语言。诸如“卧室的灯亮着”这样的短语可以翻译成“卧室的灯亮着”的等价物这意味着任何类似这样的代码都需要根据不同的语言进行更改:

$message = "the $room light is $state";

这是软件本地化现实世界中的问题,但在这里不是!这是因为社会契约的存在,一个家庭通常会在家里对着电脑说同一种语言,即使他们在公共场合并不这么做。

相比之下,生成语音输出是一项相对简单的任务…但只是因为这是为我们做的!有三种方法:声乐音素,采样语音,以及两者的结合。我很快会谈到这些。

语音识别软件

Linux 目前对这部分问题的支持相当差,这并不奇怪。为了理解最简单的短语,您需要一个声学模型来以统计方式生成声音本身的表示(通常作为特定说话者初始训练的一部分),以及一个语言模型来考虑哪些单词和声音可能会跟随另一个单词和声音的概率(以限制分析语音时所需的处理),这两个模型都是特定于语言的。

大多数原生 Linux 软件要么是旧的、不完整的、无法编译的,要么是商业化的。即使是高级的解决方案,如斯芬克斯( http://cmusphinx.org ),也需要这么多级的安装和培训,没有人真正确定它是否有效!

商业产品存在稀缺的问题,很少甚至没有所谓的可用软件带有“在此购买”的页面。这种缺席甚至包括 IBM 的 ViaVoice,它曾经是免费的,但在 2002 年被撤回。甚至曾经作为商业 Linux 软件存在的旧软件也已经转变成了 Windows 专用的软件包。

在 Linux 下处理语音命令最简单的方法是通过 Windows,这确实是一种奇怪的情况!这可以采用运行虚拟机(通过 Wine 或 VMware 服务器)的方法,也可以使用本地 Windows 机器。

由于虚拟和真实声卡之间的不协调,虚拟化方法存在一些问题,但 ViaVoice 或 Dragon Naturally Speaking 等软件通常可以在一段时间后工作。如果该软件要在您的服务器上运行,通常是这样的,那么您也给它添加了对 X Windows 的依赖,增加了它的处理负载。

因此,最有效的方法是使用一台单独的 Windows 机器运行前面提到的软件。或者,你已经付了“Windows 税”,使用 Vista 内置的软件,下载 Windows 语音识别宏模块。随着平板电脑和笔记本电脑开始在其最新版本中包含语音识别软件,在不久的将来,可能很快就会在 Linux 机器中找到一个(封闭源代码)库。

虽然有一个好的识别算法很重要,但更重要的是能够访问它的结果。在大多数 Windows 软件中,这从来不是一个高优先级。对他们来说,更常见的是采用“我们将在一个包中为您提供我们认为您会需要的所有功能”,而 Linux 使用“这里有许多我们认为您会需要的工具;你可以想出如何产生功能”的方法。因此,您需要在购买前试用该软件。此处给出的解决方案涵盖了 Windows Vista 内置软件的使用。

从在 Vista 中训练语音识别系统开始;然后完成教程,安装 Windows 语音识别宏,可从微软网站下载( www.microsoft.com/downloads/details.aspx?FamilyID=fad62198-220c-4717-b044-829ae4f7c125&displaylang=en )。接下来,您需要为想要使用的命令编写一系列宏,例如“开灯”和“关灯”每个宏都会触发一个命令;在我们的例子中,这将是wget来欺骗 Apache 在我们的服务器上运行必要的代码。图 5-1 显示宏配置面板。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-1。

Preparing a voice macro under Vista. (Used with permission from Microsoft.)

自然地,auth关键字是一个误称,因为任何人(从任何地方)都可以请求同一个页面并触发命令。然而,通过使用机器的本地 IP 地址,请求将永远不会离开您的内部网,并且通过锁定 Windows 机器,没有其他人能够发现密钥。 7 所以,再一次,你只容易受到那些能接触到机器的人(也就是你的家人,他们能接触到电灯开关本身)的攻击!

从这里开始,服务器代码是琐碎的,并且是预期的:

<?php

$cmd = $_GET['cmd'];

if ($cmd == "lightson") {

system("heyu turn bedroom_light on");

}

else if ($cmd == "lightsoff") {

system("heyu turn bedroom_light off");

}

?>

然后,您可以随意对其进行抽象和扩展。在第七章中,你将把它集成到一个通用消息系统中。

Note

在对语音识别软件进行大量投资之前,确保它能够区分可以控制系统的不同声音,因为许多软件只能听单一的预选声音,因为其主要目的是听写而不是语音识别。

请注意,大多数这种类型的软件不提供对您实际说过的话的访问;电脑只是认为这个比那个更有可能。虽然这减少了出错的机会,但也防止了使用任何模拟或缩放命令,如“调暗至 72%”

来自 iOS

云已经部分解决了语音识别的问题。通过将处理过程转移到远程设备上,意味着你可以使用比传统的手持机器更强大的算法来执行识别,尽管代价是要求你自己在线,并发现自己受到(传统的)非开放技术的支配。这方面最著名的例子是 Siri。

Siri 于 2010 年作为独立应用发布,后来被整合到 iPhone 4s 中,并成为 iPhone 和 iPad 上 iOS 5 以来版本的主要功能。在其传统操作模式下,会发生以下情况:

  • Siri 从麦克风录制您的声音
  • 您的 iOS 设备将它的渲染上传到位于 guzzoni.apple.com 的服务器上
  • guzzoni 服务器处理语音,并处理请求
  • guzzoni 服务器向您的 iOS 设备返回一个命令包

如您所见,该链的两个部分需要 iOS 设备。然而,通过修补(以及 SiriProxy 等软件),你可以避开这个过程的一半。然后,操作变成:

  • Siri 从麦克风录制您的声音
  • 您的 iOS 设备将它的渲染上传到您的服务器
  • 您的服务器将请求传递给 guzzoni.apple.com
  • guzzoni 服务器处理语音,并处理请求
  • guzzoni 服务器向您的服务器返回一个命令包
  • 然后,您的服务器可以使用已识别的文本字符串处理任何任意命令
  • 您的服务器将结果字符串(带有可选图像)传递给 iOS 设备

正如您所看到的,这里发生了一个相当传统的代理隐喻,您的服务器充当 iOS 设备和 guzzoni 服务器之间的中间人,以便它能够进入进程的中间,执行自定义命令。

请注意,路由的 iOS 部分仍然是强制性的,因为 guzzoni 服务器将只与经过身份验证的 iOS 设备通信。代理通过从您的原始 iOS 设备 ID (UDID)重新生成它来管理它。

传统上,您只能在本地网络中运行 SiriProxy,因为您不希望随机的陌生人连接到路由器上暴露的端口。然而,使用 VPN 连接到您的内部网络是可能的,尽管这超出了我们这里的范围。

为此,你需要在 https://github.com/plamoni/SiriProxy 安装软件

有安装脚本和视频可用,过程列在 https://gist.github.com/plamoni/1428474

考虑到这个软件是多么的新,我只能建议你使用最新的说明和在那个要点文件中列出的错误修复。

编写插件

假设代理是用 Ruby 编写的,那么插件也是有意义的。因为实际上不涉及任何代码,所以做起来并不困难。没有什么可以阻止您调用另一个 shell 脚本。

require 'cora'

require 'siri_objects'

require 'pp'

class SiriProxy::Plugin::ControlLights < SiriProxy::Plugin

def initialize(config)

# standard initialization

end

listen_for /computer light (on|off)/i do |light_state|

state = homedevice default #{light_state} bedroom_light``

say state

request_completed

end

end

这个库提供了额外的功能,比如一个基本的状态系统,因此您可以检测单词“next”是指下一首音乐还是下一条新闻。您还可以通过 SiriAddViews、send_object 和一个模型“ask”命令添加内容来提供视觉反馈,例如天气,这样您就可以获得关于最新命令的说明。

Note

一旦你创建了自己的插件,不要忘记把它添加到 config.yml 文件中。

来自 Android

对于 Android 来说,Siri 的最佳替代品是三星的 S Voice。它的工作方式与 Siri 相同(而是使用 Vlingo 服务器),尽管在这种情况下,它需要一个有效的 Galaxy S III 手机 id 来连接和使用该服务。然而,在撰写本文时,唯一的黑客工具是 voicetalk.apk,它需要一个根电话,因此不推荐这样做。

远程语音控制

能够在房子的几个不同房间里使用你的声音肯定有好处。但是,这增加了新的复杂性,因为您必须执行以下操作之一:

  • 在房子的每个房间里将一个麦克风连接到电脑:你可以购买小型混音器,将来自多个麦克风的输入组合起来,非常便宜。最自然的地方是在灯座和灯泡附近,因为附近已经有一根电缆了。然而,你需要屏蔽他们的电缆,以避免电源嗡嗡声。一些司法管辖区还会(合法地)要求电源线和非电源线之间保持最小距离。例如,在澳大利亚,这个距离是 300 毫米。您应该注意安全,并在继续操作之前查看您所在国家的当地法律。
  • 在每个房间都有一台单独的计算机,并在本地处理数据:这为您提供了最高级别的控制,因为多个人可以同时与服务器对话,并且服务器只处理请求数据,而不处理音频数据。然而,这更贵,而且要求你能在每个房间里藏一台(小)电脑。

在每种情况下,每个房间的音响效果会有所不同,因此您可能需要从房间的不同位置录制您的声音。

Note

使用 Siri hack 只对手持语音控制解决方案有用,因为 Siri 需要你按下按钮才能激活它。事实上,这是许多软件的一个主要障碍,这些软件不能在“触发”或初始“关键”短语或单词上开始记录。

在过去的电影中,在麦克风盛行之前,麦克风被藏在收音机或电话等大型道具中,这样它们就可以放置在离演员足够近的地方,以便在没有外来噪音的情况下拾取他们的声音。你也可以通过安装麦克风(甚至个人电脑)在更小的范围内做同样的事情。)在椅子里或桌子底下。主要考虑的是如何让电缆(电源和数据)回到语音机器。如果你正在从头开始一个家庭自动化项目,或者正在装修,那么你可以选择拉起地板,在下面铺设电缆。然而,这样的决定不能掉以轻心,特别是因为维护是非常昂贵的!

Note

旧的蓝牙耳机和免提装置既昂贵又笨重。然而,它们现在便宜得多,可以提供一种偷偷摸摸的方式,在整个房子里添加无线远程麦克风,用于捕捉语音命令或安全监控。

然而,对我来说,第二种选择更可取,因为拥有一台独立的语音识别机并不像听起来那么糟糕。好吧,这涉及到高成本和额外的电力问题,但因为机器没有其他事情可做,它可以在没有键盘、鼠标或显示器的情况下存在,并且安静地坐着,不被触摸,无需维护许多年。此外,随着低成本笔记本电脑的出现,您可以在两个或更多拥有自己麦克风的房间中放置(阅读:隐藏)一个,从而消除您可能会遇到的大多数音频声学问题,以及如何在房间之间连接麦克风和前置放大器的思考。预装 Vista(包括语音识别软件)的低端机器的成本,现在并不比其他一些软件包的软件许可成本高多少。我希望那些开发者在这本书的第二版出版之前能很快意识到这一点和他们所错过的市场!

语音合成

这是问题中容易的部分,因为困难的工作已经为我们完成了,其中一个软件包是可用的。

节日

这个领域的爸爸是一个叫节日( http://www.cstr.ed.ac.uk/projects/festival/ )的包。Festival 始于 2004 年,位于爱丁堡大学的语音技术研究中心(CSTR ),现在仍然存在,尽管最近的功能已经由许多来源提供,包括 Carnegie Melon 大学,因为它有开源许可证。它通过一个复杂的音素和韵律系统生成单词,并能够通过使用特定于语言的代码动态处理不同语言的细微差别,这些代码由 Festival 的内置 Scheme 解释器处理。

大多数发行版都提供了 Festival 的基本安装,尽管声音有限。快速研究一下/usr/share/festival会告诉你有多少。这些可以通过运行 Festival 并使用交互式提示进行采样:

$ festival

Festival Speech Synthesis System 1.96:beta July 2004

Copyright (C) University of Edinburgh, 1996-2004\. All rights reserved.

For details type (festival_warranty)``

festival> (SayText "Hello automation")

#<Utterance 0xb6a8eff8>

festival> (voice_lp_diphone)

lp_diphone

festival> (SayText "Hello automation")

#<Utterance 0xb6c56ec8>

festival> (quit)

括号符号是因为处理命令的 Scheme 解释器,lp_diphone引用是默认情况下提供的另一种意大利女性“声音”。在你继续之前,写一个简短的脚本来简化演讲过程(为明显的英语偏见道歉):

#!/bin/bash

SPEAKER=/usr/share/festival/voices/english/$1

if [ -d $SPEAKER ]; then

VOX=\(voice_$1\)

fi

shift

echo "$VOX (SayText \"" $* "\")" | festival --pipe

然后,您可以调用以下内容:

say default Hello automation

或下面的更容易切换到另一种声音:

say kal_diphone Hello automation

为了更好的声音,你需要在姆布拉看得更远。

MBROLA 是一个(目前)仅支持二进制的 Festival 后端,它提供了 Festival 的备选声音,而不需要升级 Festival 包本身。通过 Debian 在基于 Intel 的系统上安装基本的 MBROLA 代码,如下所示:

wgethttp://tcts.fpms.ac.be/synthesis/mbrola/bin/pclinux/mbrola3.0.1h_i386.deb

sudo dpkg -i mbrola3.0.1h_i386.deb

然后,您需要下载新的语音数据来使用此代码。在这里,我们可以听到几种声音,但这里最感兴趣的是以美国为中心的三种声音。我将演示 us1 的安装,us2 和 us3 需要对 URL 进行明显的更改: 8

wget -chttp://tcts.fpms.ac.be/synthesis/mbrola/dba/us1/us1-980512.zip

wget -chttp://www.festvox.org/packed/festival/latest/festvox_us1.tar.gz

unzip -x us1-980512.zip

tar xvf festvox_us1.tar.gz

然后可以将数据复制到适当的地方,根据你的分布:

# these require root privileges

mkdir -p /usr/share/festival/voices/english/us1_mbrola/

mv us1 /usr/share/festival/voices/english/us1_mbrola/

mv festival/lib/voices/english/us1_mbrola/* /usr/share/festival/voices/english/us1_mbrola/

当然,其他发行版可能会为您打包,从而节省工作。

现在你有了一个备用声部,如果安装正确,可以用 Festival 命令(voice.list)(带括号)来验证。它现在应该显示出us1_mbrola是一个合适的声音,所以您可以用下面的代码来测试它:

say us1_mbrola Hello automation

当您很高兴找到了自己喜欢的声音时,您可以通过在之前的脚本中设置 VOX 来将其设为默认声音:

VOX=\(voice_us1_mbrola\)

能够听到不同的声音是一件好事,因为人们会根据情况对不同的声音做出不同的反应。心理学家告诉我们,女性的声音有利于传递信息、提供帮助和报告文本,而人类对男性声音发出的命令反应更好。在一个家庭中,你可能会用不同的声音向不同的人传达信息。如果听者知道自己的声音,他们就有可能(通过一种被称为鸡尾酒会效应的听觉怪癖)将自己的声音从许多其他辅助噪音中分离出来,包括其他口头命令。

默认的声音(通常是kal_diphoneked_diphone)很刺耳,作为早晨的最后一个闹钟也不错。然而,确保客人知道你正在使用它,因为被斯蒂芬·霍金和 Dalek 的混合体吵醒是相当令人不安的。

除了简单的短语,您还可以通过以下方式要求 Festival 为您朗读文件:

say default cat filename``

或者通过下面的,哪个更优雅:

festival --tts filename

虽然只直接支持文本文件,但有许多工具,如 html2txt(可以与pdftohtml结合使用),允许为您朗读大多数文档,可能作为您的闹钟呼叫的一部分,或者当您正在做饭而无法从屏幕上阅读时。

Note

试着让声音尽可能的短,将较长的短语分成单独的呼叫来庆祝,因为长的段落通常会导致声音变慢,变得难以理解。

也可以为节日打造自己的声音。虽然这个过程过于复杂,无法在这里讨论,但可以通过卡耐基梅隆大学的 FestVox 项目( http://festvox.org )了解细节。如果您想要自定声音,将声音录制为音频样本会更容易。

Note

自然,也有商业语音合成包可用,这是大多数开源爱好者所忘记的。一个这样的例子可从 http://cepstral.com .获得。该网站还提供动态的示例声音。

Espeak

节日不是镇上唯一的游戏。如果你不喜欢节日的声音,或者只是喜欢改变,那么 espeak 包可以提供一个替代的解决方案。像 Festival 一样,它能够用多种语言说话,并使用音素在文本和语音之间进行转换。然而,与它的大兄弟不同,它的尺寸要小得多(对树莓派很有帮助),并且只使用共振峰合成,这使得声音对许多人来说更像机器人。用法很简单:

espeak "This is my other voice"

(引用很重要)

以及:

espeak -f weather_report.txt

这些命令可以用其他选项来补充,这些选项提供对声音的音高和速度的基本控制。它也有各种语音文件来提供地方口音,但这些都是新奇和有用的,只提供音调的轻微变化,而不是更复杂的界面。

争吵

对于非常小的 Linux 系统,比如 Raspberry Pi,您可能会从 Flite 中获得更好的收益,因为它只包含一个可执行文件,没有数据文件。正如您所料,这是本文介绍的工具中最机器人化的,但它非常适合低功耗 ARM 处理器。使用模式遵循 espeak:

flite "My quotes are also necessary"

flite -f another_file.txt

它目前仅适用于英语。

零碎样品

大多数自动列车广播由单独的语音片段组成,然后由计算机重新排序。这使用相对较小的原始样本集提供了大范围的可能短语。通过对声音文件的仔细整理,它们听起来会非常人性化。这种方法的问题是不可能将迄今未知的短语引入词典。例如,如果你用一个人的声音作为闹钟,你会提前知道可能发出的每个短语和部分短语。在软件包错误报告的情况下,你可能不会,特别是当它涉及到文件名和用户输入时。在这些情况下,您可能必须承认样本不存在,并恢复到 Festival。

例如,要制作一个语音闹钟,你首先需要考虑你需要的样本。这可以是你准备记录的最大限度。许多国家都有自己的语音时钟服务,可以通过电话获得,每隔 10 秒钟报一次时间,许多国家会用每个特定的短语记录整个 24 小时的时钟。你还需要考虑你希望在语法上有多精确。“1 秒钟”这句话让你不爽吗?如果是这样,你需要一个特定的样本。你还需要考虑个人喜好,比如“过去 15 分钟”听起来是否比“过去一刻钟”好听,等等。

就我个人而言,我有一个我认为重要的标准时钟短语列表:

  • “时间到了”
  • “下午。”
  • “上午。”
  • 《午夜》
  • “点钟”
  • “过去一刻钟”
  • “过去一半”
  • “差一刻”

所有其他时间可以由以下短语组成:

  • “过去分钟数”
  • “分钟到”
  • “过去”
  • “收件人”

还有数字 1 到 20、30、40、50 和 60,后者是我那些书生气十足的极客朋友偶尔来访时闰秒所需要的!我还为以下内容添加了特定的示例,以保持语法正确:

  • " 1 分钟过去"
  • “还有 1 分钟”

然后,我可以用以下代码检索时间,并用代码将它们拼凑在一起:

HOURS=date +%I``

MINS=date +%M``

100 行的脚本留给您作为练习! 9

虽然编程相对简单,但记录处理却不简单。你需要让你的嗓音天赋录下整个短语的几个样本,以感受他们讲话中的节奏模式。然后,你应该对所有的单词 10 进行取样,并对单个短语进行修剪,以在开头不留死角,同时在结尾留下合适的间隙,以便在第二个单词直接连接到结尾时与说话者的节奏相匹配。让他们先说一些示例短语,让你对他们的语速有一个概念,这样在某些情况下,你可以要求他们在每一项之后留下比平时更长的停顿。记住这一点,让他们读一份比你实际需要的更长的清单。所以对于以 60 结尾的数字列表,问他们要 61。除非他们是有经验的演员,否则当读列表中的最后一个元素时,人们会自然地降低他们的声音,当它以另一个数字为后缀时,听起来不自然。

整个过程可能需要几个小时进行录制、重新录制和编辑。但是,为远方的伴侣准备一个个性化的闹钟或者作为一个古怪的 22 世纪的小玩意是值得的。如果你同时录下其他短语(如“早上好”、“晚安”或“哦,滚出我的房子!”),您可以在其他时间因其他原因触发样本。

在 Arduino 上

样本的回放在所有 Linux 机器上都很简单,包括 Raspberry Pi。但是即使这个看似简单的任务对 Arduino 来说也很难处理。这是可能的。但是它确实需要你做更多的工作,而且在所有情况下,一次只能管理一个文件。

软件解决方案

只需一个 Arduino 和一个扬声器,就可以播放录制的声音样本。鉴于 Arduino 的输出水平,它可以在没有放大器的情况下管理合理的音量——得分高于不起眼的 Pi!

为了实现这个小小的工程奇迹,你需要意识到它的局限性:

  • 最大回放频率为 8KHz,这意味着可以准确描绘的最高频率声音为 4KHz(这是奈奎斯特极限)
  • 标准存储器只允许 4 秒钟的采样数据
  • 您必须将样本预先格式化为合适的格式,因此不可能有动态样本(或实时更新)
  • 使用示例播放器时,直接控制 Arduinos PWM 占空比,以提供 8KHz 采样速率。这意味着不可能有其他模拟输出。

如果这些限制还不能阻止你,那么合适的代码和示例(原谅双关语)可以从 http://hlt.media.mit.edu/?p=1963 获得。

然而,对于如此短的样本存储器,你要么需要使用一个外部存储器屏蔽,要么利用它作为比上述更基本的时钟。或者把它当成一只虚拟的狗。

硬件解决方案

Raspberry Pi 的最大好处之一是芯片足够快,可以处理开箱即用的样本回放。毕竟,它是一台真正的计算机。然而,在微控制器是首选解决方案的情况下,总是可以添加一个“wave shield ”,以允许从连接的 SD 卡回放样本。这将处理最大带宽的声音,即 22 千赫的单声道 16 位波。

虽然 shield 的成本很高,但它比软件版本的得分高,因为它能够处理 16 位波形,并且在没有放大器电路的情况下工作,因为有一个放大器电路。此外,根据您可能拥有的音频量,内置的 SD 插槽比普通的 Arduino 提供更多空间。

Web 访问

到目前为止,20 世纪和 21 世纪最有影响力的交流方式是万维网。也被称为网络、互联网、互联网、互联网(作为一个整体)、互联网(作为一系列管道),HTTP 协议无处不在,以至于它现在出现在最低端的手持和移动设备上。这本身就使它非常有价值,因为您不必考虑其他协议的技术问题、操作它们的特定代码或为市场上的每个手持设备定制的应用程序。用它来控制我们的房子意味着你,真的,有了一个主页。

Web 就像你看到的所有东西一样,既可以使用客户端组件,也可以使用服务器组件。客户端通常被称为 web 浏览器,运行在世界上某个地方的任意机器上,而服务器处理来自 web 浏览器的请求,并位于家庭服务器上。这些请求通常针对静态 HTML 网页,但它们也可以是脚本——用几乎任何语言编写——以动态生成页面或在本地运行软件。服务器在一个用户如www-data下运行,这取决于分布,意味着任何本地处理将在该用户的管辖下完成,这可能需要一些软件将需要适当的许可来访问必要的设备。音频设备(用于语音和音乐播放)和串行端口(用于 X10 控制)通常都是如此。

当对 web 服务器产生一组需求时,您必须区分哪些处理是在客户端完成的,哪些是在服务器端完成的。例如,如果您认为从网页上播放 MP3 是一个好主意,那么了解您的目的是在工作时听您的音乐收藏,还是在家里(也许在聚会期间)组织一个播放列表是很重要的,在家里您可以听到服务器的音频输出,但不一定要实际访问它。

构建 Web 服务器

许多开源社区选择的 web 服务器是 Apache。目前是第 2 版,这个项目起源于 1992 年,被称为“拼凑的”web 服务器,因为它在早期的开发过程是临时的。它已经发展成为世界上最常用的软件之一,运行着互联网上大约 50%的网站。

Apache 的强大之处在于它对模块的灵活性。这允许高效且安全的内核能够利用可以随意加载和卸载的补充代码的功能。自然,每个模块都提供了另一个打开意外安全漏洞的机会,所以我们将只安装您需要的模块。对于这些主要目的,您只需要基本的服务器和脚本语言。Debian 软件包安装了以下内容:

apt-get install apache2 libapache2-mod-php5

其他发行版的名称类似。安装完成后,你可以将浏览器指向本地主机,在那里你会看到“祝贺”网页,默认存储在/var/www中,从而证明 web 服务器工作正常。然后,您可以通过创建一个名为test.php的页面来测试脚本模块,该页面包含以下内容:

<?php

echo phpInfo();

?>

通常,这些模块的安装也会正确地配置它们,以便.php文件与 PHP 模块的执行相关联。如果这不明显,您可以通过以下方式启用该模块:

a2enmod php5

万一这些方法不起作用,会在/var/log/apache2/error.log中保存一个日志。许多重要的流量依赖于一个工作的 web 服务器,所以值得花时间来确保它的稳定性。

虚拟站点

一台 web 服务器可以为多个站点提供网页服务,即使它们位于同一个 IP 地址。这从 HTTP 协议的 1.1 版本(所有主流浏览器都支持)开始就已经存在了,它在请求中包含了域名和 IP 地址。在家庭环境中,这很不常见,但它很有用,因为它允许你将传入的网络流量分成两部分,以转移好奇者的注意力。您可以有一个供朋友和家人访问的网站,其中包含一个包含您的狗和孩子的照片的博客,另一个供 HA 控制。

你可以从建立两个域开始,也许是通过 Dyndns.org,就像你在第四章看到的那样,然后创建两个不同的目录:

mkdir -p /var/www/sites/homepublic

mkdir -p /var/www/sites/homecontrol

然后创建两个配置文件,每个站点一个。遵循这里的惯例,在每个站点前面加上一个数字。这允许您将您的可公开访问的命名为000-public,这意味着它将在任何 web 配置问题的情况下首先提供服务,或者该站点仅通过一个 IP 地址访问。以这种方式返回到公共站点造成的损害更小,但是无法使用 HA 控制网站来纠正问题。然而,这种类型的大多数错误只能通过 SSH 来修复,所以它们不是问题。

这两个文件/etc/apache2/sites-available/000-default包含以下内容:

<VirtualHost *:80>

ServerName mypublicpresence.homelinux.org

ServerAdmin webmaster@localhost

DocumentRoot /var/www/sites/homepublic/

<Directory /var/www/sites/homepublic>

Options Indexes FollowSymLinks MultiViews

AllowOverride AuthConfig

Order allow,deny

allow from all

deny from none

</Directory>

</VirtualHost>

/etc/apache2/sites-available/001-control包含相同的东西,但是用homecontrol和替代ServerName代替了homepublic。然后手动启用它们,并使用以下三个选项重新启动 web 服务器,以 root 用户身份运行:

a2ensite 000-default

a2ensite 001-control

apache2ctl graceful

现在,您可以访问两个可以相应准备的虚拟站点,其中包含稍后您将发现的模块和软件。但是,即使有了这种基本的配置,您也可以通过在deny行添加空格分隔的点四边形,而不是短语none,明确拒绝用户使用已知的坏 IP 地址。或者,更好的做法是,您只允许来自那些您知道是安全的地址的邮件,例如使用相同格式的工作、学校或家庭。后者更复杂,因为家庭用户通常由他们的 ISP 分配一个动态 IP 地址,尤其是那些有拨号连接的亲戚。因此,您通常需要使用单独的用户名和密码来保护站点。

安全服务器

随着 Web 成为自然开放的协议,而家庭机器成为传统的安全环境,提供一种安全访问您的家庭及其数据的方法是必须的。您可以提供基本的授权,将名为.htaccess的特定文件放在每个目录中。这些由 web 服务器读取,以控制执行以下操作的访问:

  • 使添加和更改用户访问权限变得容易
  • 可以基于每个目录进行更改,而无需成为超级用户
  • 更改之间不需要重启

与直接更改配置文件相比,这种方法的一个缺点是每次访问时都会读取这些文件,从而使服务速度变慢。然而,在私有 web 服务器的情况下,这不太可能被注意到。更重要的是,尽管用户名和密码以加密的形式存在于磁盘上,但在连接时它们是以明文形式通过网络发送的。此外,它们被存储(并且可以被访问)为从该区域内部运行的任何脚本的纯文本。因此,建议只对从家庭网络外部无法访问的 web 服务器使用。

要启用基本身份验证,您需要两样东西:密码文件和访问文件。密码文件通常被称为.htpasswd,它存在于文件系统中一个 Apache(即www-data用户)可以访问的位置,但 Apache 服务的文件(而不是/var/www下面的文件)不能访问。您像这样创建文件和您的第一个用户:

htpasswd -c /etc/apache2/.htpasswd steev

然后,系统会提示您输入一个加密并添加到文件中的密码。此密码仅用于访问网站。如果他们共享一个名字,它不需要匹配用户的密码,事实上你可以允许没有 Linux 帐户的用户访问网站。

然后,您必须通过在其中包含一个.htaccess文件来指示要保护的目录,如下所示:

AuthType Basic

AuthUserFile "/etc/apache2/.htpasswd"

AuthName "Enter your username and password."

require valid-user

您通常会以这种方式保护整个目录,任何基于用户的控制都是通过如下代码实现的:

if ($_SERVER['PHP_AUTH_USER'] == "steev") {

// allow this

}

添加任何带有对.htaccess的更改的每文件控件,因此:

<Files private_file.php>

require valid-user

</Files>

但是,请注意,虽然您不需要重启 Apache 来使这些更改生效(因为您没有更改apache2.conf或它的合作伙伴),但是您需要确保以下内容出现在使用该身份验证系统的目录指令中:

AllowOverride AuthConfig

这是因为大多数示例将前面的行默认为下面的行,这不支持该功能:

AllowOverride None

您还可以通过向.htpasswd文件添加行来创建用户组:

FamilyGroup: mum dad sister

HouseOwnersGroup: mum dad

您可以将需求行.htaccess修改为:

Require group HouseOwnersGroup

当访问这些仅授权的网页时,您将看到一个对话框,要求您输入用户名和密码。这自然会使页面看起来更难添加书签。其实并不是!HTTP 规范允许这两者作为 URL 的一部分传递。

http://myusername:mypassword@myprivatesite.homelinux.org

虽然这是一个安全缺陷,但必须记住,授权凭证已经以纯文本形式传递,因此它不会打开任何新的漏洞;它只是降低了脚本小子的准入门槛。只要书签没有存储在任何可公开访问的机器上,你的情况不会更糟。

Note

请注意,一些媒体播放器在播放来自此类网站的音乐时会显示完整的 URL(包括登录凭证)。

一种大大改进的安全形式是通过安全套接字层(SSL)。这是两个站点(客户端和服务器)只有在通过交换证书建立了可靠的安全连接后才能进行通信的地方。例如,这些证书证明声称是minervahome.net的服务器确实是位于minervahome.net的服务器。可以说,这份真品证书是由一个你可以信任的更高权威人士签发的。而这种权威被更高的权威所验证,等等。在这个层级的顶端是像 VeriSign 这样的公司,它们的全部价值是基于这样一个事实,即它们永远不会与其他任何公司混淆。虽然家庭用户没有被明确排除在外,但获得这些信任证书需要花钱,而且通常是为企业保留的。但是,您总是可以通过生成一个您自己签名的证书来绕过这一要求。这并不提供完整的安全包,但它提供了对您的数据的安全访问,网络上的其他任何人都无法看到。

从技术层面来说,SSL 是 HTTP 协议的一个扩展,它可以确保用户名和密码不会被监控您家用机器流量的数据包嗅探器监控到。但是,因为安全握手发生在域名之前,所以只有一个虚拟站点可以使用 SSL。 12 在我们的例子中,这将是我们的私人住宅控制网站。

自签名身份验证证书在一定天数内有效,并在启动时应用于 web 服务器。要防止此证书被复制并在另一个 web 服务器上使用(从而消除其作为安全机制的目的),您必须在创建证书时以及在任何时候使用、转换或应用到 web 服务器时键入密码(更长形式的密码,至少应包含 20 个字符和几个单词,以避免基本的字典攻击)。越长的短语自然越好,但是如果你忘记了短语,你将不得不撤销那个证书并且发行一个新的。

SSL 自签名证书是用几个(相当不透明的)命令生成的。网上有许多例子以不同的详细程度详述了这些。为了我们的目的,你不关心为什么,只关心如何。因此,作为 root 用户,从以下内容开始:

cd /etc/apache2

mkdir ssl

cd ssl

并发出以下命令,按照要求填写提示:

openssl genrsa -des3 -out server.key 1024

openssl rsa -in server.key -out server.pem

openssl req -new -key server.key -out server.csr

openssl x509 -req -days 30 -in server.csr -signkey server.key -out server.crt

chmod 600 *

然后,您可以通过克隆现有的001-control版本并用以下内容包装它,将 SSL 主机添加到您的可用站点列表中:

<IfModule mod_ssl.c>

<VirtualHost _default_:443>

# Normal configuration data goes here...

SSLEngine on

SSLCertificateFile  server.pem

SSLCertificateKeyFile server.key

BrowserMatch ".*MSIE.*" \

nokeepalive ssl-unclean-shutdown \

downgrade-1.0 force-response-1.0

</VirtualHost>

</IfModule>

然后,您应该使用以下命令重新启动 web 服务器:

a2enmod ssl

a2ensite 002-control-ssl

apache2ctl graceful

如果一切顺利,你将被要求输入密码,该网站只有在使用 HTTPS 时才可用。

Note

设置和配置 SSL 的过程充满了出错的可能性,从密钥和证书之间的差异(通常是在输入位置和域信息时)到 SSL 协议被破坏,再到优先使用旧证书而不是新证书。因此,只有当您有时间并且能够很好地访问各种互联网留言板时,才使用 SSL!

为了确保您的用户始终使用网站的 SSL 版本,您可以通过将任何 HTTP 请求重写为 HTTPS 请求,在配置中引入一些简单的规则。这使用了著名的mod_rewrite模块,可以通过虚拟主机配置文件引入,如下所示:

<Directory /var/www/sites/homeprivate>

Options Indexes FollowSymLinks MultiViews

AllowOverride AuthConfig

Order allow,deny

allow from all

deny from none

RewriteEngine On

RewriteCond %{SERVER_PORT} 80

RewriteRule ^(.*)$https://myprivatesite.homelinux.org/$1

</Directory>

然后,您必须启用该模块并重新启动:

a2enmod rewrite

/etc/init.d/apache2 restart

作为一层额外的保护,利用“通过模糊实现安全性”的方法并不罕见。这意味着你让别人很难偶然发现你的服务器。例如,您可以将真正的主目录放在一个子目录中,这个子目录是从根目录开始的,没有指向它的链接。这将使用一个更隐晦的名字,而不是housecontrol,并作为第一层密码。由于您无法查询 web 服务器来确定哪些文件可供下载,因此只有在您知道该区域存在及其名称的情况下,才可以访问该区域。如果你选择一个随机的名字,比如bswalxwibs,你可以在物理安全机器上把它加入书签。

当然,这应该是标准安全方法的补充,而不是替代。如果你注册了一个像 MyMegaCoolAutomatedHouse.com 这样的域名,那么很有可能有人会发现它,并能够使用 Whois 目录获取你的真实地址 13 (除非你记得屏蔽它)。

控制机器

虽然 Apache 能够在 web 页面被请求时动态运行脚本,但是它们是作为运行 Apache 的用户来运行的。根据您的配置,这通常是www-datanobody用户。通过在您的 web 服务器上包含以下whoami.php脚本并将其加载到浏览器中来确认这一点:

<?php

system("whoami");

?>

仔细考虑这个用户。因为服务器(代表访问网页的用户)发出的所有系统调用都将作为www-data发生,所以对正在运行的代码有进一步的考虑:

  • 该用户对您的文件系统的访问权限可能比您预期的要多。人们不再需要 Linux 机器上的用户帐户来读取文件系统;如果软件或其配置存在安全问题,他们可以通过网页来解决。
  • 此外,权限也会有所不同,不仅是必要的配置文件,还有对设备(如 CD-ROM 或声卡)的访问权限。例如,如果您允许一个网页控制您的 CD-ROM,那么/dev/cdrom必须拥有授予www-data用户的读写权限。因为这有点特殊,所以更常见的是授予一个音频组读写权限,并将用户www-data添加到该组。请注意,每当对用户组进行这样的更改时,您都必须重新启动 Apache 服务器。对/dev/dsp的访问也是如此。
  • 用于确定命名可执行文件位置的路径将与您测试的普通用户的路径明显不同。这意味着您应该在发出的所有命令中显式使用该路径。
  • 环境变量也会不同。您可能需要通过以 Apache 用户身份登录(例如,rlogin www-data@localhost)并相应地设置环境来手动设置这些。您还可以使用这种方法,通过手动运行命令来确认您的权限设置是否正确。这也允许您创建任何可能需要的配置文件。
  • 最后,记住大多数系统命令都是阻塞的。也就是说,他们直到完成任务才回来。因此,当从 web 页面内部调用任务时,用户将处于一个空白的 web 页面(带有“等待”光标),直到页面完成。因此,该命令的任何输出或错误代码都不会显示在页面上。相反,您必须编写您的软件,以便:
  • 您的命令异步执行,使用shell_exec("cmd &")或类似的。
  • 您可以通过 Ajax 更新错误或输出状态。
  • 您可以通过异步命令调用后发出的辅助命令来检索错误状态。

这些都不是未解决的问题,但是对于那些想要编写自己的家庭自动化 web 应用程序的人来说,这是一个额外的复杂性层。

媒体访问

一个常见的功能是提供从家庭以外(例如从办公室)对您的音乐集合的访问。有几个 Apache 模块可以处理这个问题;其中一个就是mod_musicindex ( http://freshmeat.net/projects/musicindex/ ,在libapache2-mod-musicindex package中也有)。尽管它能够用于列出通用目录(就像它自己的在线文档一样),但它能够呈现特定于音乐的图标,让您在世界任何地方下载和/或流式播放音乐,并为当前文件夹及其下的所有子目录交互式创建播放列表。

要为您的音乐准备一个在线门户,首先在您的 web 目录中创建一个目录:

mkdir music

然后在里面创建一个.htaccess文件,授予你认为合适的用户权限。这些权限适用于该目录及其下的所有目录,除非被另一个.htaccess文件取代。因为您的音乐收藏可能存储在 web 根目录之外,所以您必须向它添加一个符号链接:

ln -s /net/media/mp3 mp3

这也强调了您在根目录中创建单独的媒体目录的原因——它消除了对污染我们的非 web 媒体文件层次结构的目录结构的 web 特定文件的需要。然后,您可以将适当的配置行添加到您的虚拟站点配置文件中,例如001-homecontrol:

<Directory /var/www/sites/homecontrol/media>

Options Indexes``FollowSymLinks

MusicIndex On +Stream +Download +Search -Rss -Tarball

MusicSortOrder filename album disc track artist title filetype filename

MusicFields title artist album length bitrate

MusicPageTitle Media Jukebox

MusicDefaultCss musicindex.css

</Directory>

然后以通常的方式重新加载 Apache 配置。这提供了一个功能强大但不够美观的页面,如图 5-2 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-2。

An example of music index and your music being available anywhere

在客户端播放是一件简单的事情,安装一个网络友好的媒体播放器,如 VLC。当你的浏览器第一次遇到未知类型时(比如mp3或者m3u,它会要求启动一个合适的应用。如果可能的话,您希望设置此功能,以便每首新歌都在媒体播放列表中排队,而不是启动单独的播放器实例。这就是所谓的入队。

一些浏览器(如 Firefox)通常提供有媒体插件,这些插件控制所有媒体并试图在浏览器中播放媒体。这通常是不可取的,因此通过使用“文件类型”菜单选项,您可以移除此关联并手动应用它。

一个范围类似的备选包是smb2www。顾名思义,这提供了从 Web 上对所有 Samba 相关共享的访问。这具有难以置信的灵活性的优点,并且消除了对你想要共享的每个文件夹的特定符号链接的需要,但是代价是向外部世界开放你的许多个人网络。虽然我已经安装了这个,但我在默认情况下保持关闭状态,只有在需要时才打开它(通过 SSH 会话进入),也就是说,当我需要访问不允许远程连接的 Windows 机器时。当您的服务器经常负载很重时,也就是说,当它被用作媒体服务器时,那么smb2www的好处是在更改其配置后不需要重启。编辑文件后,新配置立即可用:

vi /etc/smb2www/smb2www.conf

或者使用以下内容:

dpkg-reconfigure smb2www

短信

毫无疑问,双向无线通信的最低标准是短消息服务(SMS)或文本消息。该协议作为移动电话网络基础设施的一部分存在,使其对提供商来说是零成本,因此对消费者来说是低成本,许多网络提供免费文本消息作为其每月套餐交易的一部分。尽管移动互联网的兴起,短信仍然是一种广泛使用的通信协议,尤其是在年轻人中。要在家中使用 SMS,您可以使用两种方法之一发送和接收信息。第一种也是最显而易见的方法是用连接到电脑的辅助手机来执行所有的处理。还有第二种方法,电信公司向你提供一个伪手机号码,其功能与物理电话相同,只是你使用的是 API 而不是键盘。在某些情况下,这个 API 就像 SMTP 网关一样简单。在这两种情况下,都有命令行工具来处理电信数据,所以您选择的方法取决于财务偏好。

Note

一些硬件设备将在接收到移动电话呼叫时控制电力线(像 GSM 遥控开关;见 www.gsm-auto.com ),但它们的功能有限,而且往往比自家酿造的同类产品更贵。

用电话处理

这是试验短信控制家庭的最快方法,因为大多数人(至少)在家里有一部旧手机,或者从伴侣那里借来测试。即使没有现有的设备,简单的现收现付设备的成本也不是很大。您还需要一张有效的用户识别模块(SIM)卡和一根连接电脑的连接线。许多手机店(甚至超市)出售信用额度非常低的 SIM 卡,如果你没有自己的第二张卡,这是一个理想的起点。

大多数移动电话套餐有两种类型,在 HA 领域各有千秋。

  • 合同交易一开始很便宜,因为一部(新)手机的成本是有补贴的,但维护起来很昂贵。除非你把所有的电子邮件都转换成短信,否则你不太可能充分利用“终身免费短信”服务来使你每月支付的订阅费物有所值。
  • 现收现付交易提供了一个相对便宜的进入壁垒,因为大部分费用是预先支付的;运营成本几乎为零。如果你有一部剩余的手机,比如说,之前升级过的手机,情况就更是如此。个别消息的价格会更高(比免费!),但是因为大多数 HA 安装发送的消息非常少,所以这是一个值得的权衡。然而,如果你的软件出了问题,发出了太多的消息,你将很快耗尽你的信用,导致进一步的(可能更重要的)通信丢失。

Note

手机的质量或年龄并不重要,因为它将永远插在家里的电脑上,不太可能遭受日常生活的虐待。

手机的具体品牌将取决于所使用的软件。这里有几个开源项目,大多数支持诺基亚设备上的大多数功能,还有一些索尼爱立信手机。从软件的角度来看,我们的基本要求是,您应该能够向我们的手机发送和接收消息。访问电话地址簿是有用的,但不是必需的,因为这可以更好地用软件来表示。它也应该作为一个命令行工具。

Gnokii ( www.gnokii.org )曾经是这个领域的领先软件,这些年来它的技术已经衍生出了几个分叉。它的名字表明了这样一个事实,即大多数受支持的设备都是基于诺基亚的,尽管这些设备确实可以使用标准电缆。(参见 http://wiki.gnokii.org/index.php/Config 了解已知良好设备列表。)对于其他人来说,使用蓝牙驱动可能运气更好。

如果您有一部兼容的手机,设置包括一个简单的配置文件,如下所示:

[global]

port = /dev/ttyACM0

model = AT

connection = serial

其中端口可以在插入手机后通过dmesg来确定,尽管其他一些端口是根据手机的品牌和型号来选择的。(从 http://wiki.gnokii.org/index.php/Config 的网站确定此点)。)插入后,您可以发出以下命令来确定连接是否正常工作:

gnokii --identify

尽管手机可能能够与 Gnokii 通信,但可用的功能可能会有所不同。所以,在没有合适备份的情况下,不要对你的手机做关键性的改动(比如把数据写入通讯录)。 14

最容易测试和演示的功能是发送文本消息。这也是支持最广泛的。

echo "This is a test message" | gnokii --sendsms myphonenumber

不再涉及消息的接收,这取决于你想做什么。要简单地检索您的所有消息,您可以执行以下命令:

gnokii --getsms ME 1 end

这将把你手机内存中的每一条短信写到屏幕上,在屏幕上它也可以被重定向到一个文件中或者被解析。有一个内置的解析器,它会将文本信息格式化成电子邮件的格式,并将其附加到您的收件箱中。

gnokii --getsms ME 1 end -a /var/mail/steev

因为这是一个已发布的命令,所以使用接收到的消息来控制家庭设备需要一些工作,但这是可行的,因为您需要定期轮询电话。要实现这一点,首先需要对收件箱中的邮件进行计数。这不是直接可用的,因为该命令报告来自每个收件箱的所有邮件:

$ gnokii --showsmsfolderstatus

GNOKII Version 0.6.26

No. Name               Id #Msg

============================================

0 Internal memory         ME  92

1 SIM card             SM  0

然而,因为我们无论如何都要解析每条消息,所以这并不困难,也不要紧,您也可以下载您之前发出的相同消息。因此,您可以得到总消息数,如下所示:

#!/usr/bin/perl

my $status = gnokii --showsmsfolderstatus 2>/dev/null;

$status=∼/ME\s+(\d+)/;

my $count=$1;

在检索最后一个总数(保存在您决定使用的临时或日志文件中)后,您可以只调用新消息,然后相应地处理它们:

for(my $msg=$lastCount;$msg<=$count;++$msg) {

my $txt = gnokii --getsms ME $msg $msg 2>/dev/null;

if ($txt=∼/Inbox Message/) {

$txt=∼/Date\/time\:(.*?)\n.*?Sender\:(.*?)Msg.*?\n.*?Text\:\n(.*)/;

my $date = $1;

my $sender = $2;

my $message = $3;

# process here...

}

}

使用消息控制其他设备需要我们创建一个标准格式并坚持使用。短信的核心要素——事实上,任何信息的核心要素——都是从一个地址到另一个地址和信息。您可以使用 from 地址验证用户,并使用消息在本地计算机上执行命令。消息系统的案例研究在第七章中。

Note

可以将两部手机连接到一台机器上。这使得你可以使用一个发送日常日程或提醒的标准信息,另一个发送任何需要发送的紧急“房屋警报”信息。这样,即使第一个帐户的信用额度用完了,您仍然可以收到高优先级的邮件。

也可以通过使用--setlogo控制手机标志中使用的文本和/或图形,将手机用作显示设备。这可能会报告有关您的电子邮件、天气或 RSS 源的基本状态信息。

您还可以使用语音拨号功能拨打另一部电话,这样您就可以通过以下方式听到房子的声音(如高科技、遥控、婴儿监控器):

gnokii --dialvoice 12345678

要做到这一点,你需要让手机的麦克风可以接触到(也就是说,不要放在 Node0 里面的橱柜里),或者给手机连接一个外部麦克风。这可以扩展为个人“拨号上网”服务,将电脑的音频输出连接到手机的麦克风,你可以通过短信点播音乐,然后以语音呼叫的形式播放。然而,这并不实际,除非你有免费(或非常便宜)的语音通话。

手机短信的使用正在减少,因为新手机标配了宽带和可用的网络浏览器。web 界面比 SMS 消息拥有更多的控制和灵活性。但是给所有家庭成员都配备一部手机是一个昂贵的首次展示,而且如果你闪亮的新手机被大象坐在上面,你也没有退路!然而,结果是,更少的新手机可能具有 SMS 驱动程序,因为开发工作将被相对较少的人口所欣赏。这就是下一个解决方案出现的地方…

自定义编号和 API

在你的电脑上安装一部(或多部)手机并不是处理信息的最划算的方式。毕竟,所有的信息都被输入到手机中,由移动网络的计算机系统处理,然后转换回来显示在手机上。显而易见,一定有一种方法可以直接连接到这些计算机系统来发送和接收消息。

有!

一些公司,如 IntelliSoftware ( www.intellisoftware.co.uk )和 Txtlocal ( www.txtlocal.co.uk )提供短信网关服务,通过一个 API 提供对移动网络的访问,让你可以从任何可以上网的电脑上发送和接收信息。他们的成本结构是一个现收现付的电话,有安装费(通常为零)和每条信息的费用。这通常比现收现付手机便宜,因为你不需要定制号码(这是贵的一点!),而且它消除了您最初购买手机的成本。因为它是一项网络服务,你可以拥有尽可能多的不同服务(例如,高优先级和低优先级的消息),而不会耗尽 USB 端口。在忙忙碌碌的时候,仍然会有信用额度用完的问题,但是你通常可以提供一个信用卡号码,在这些情况下,它会自动补足你的余额(在我看来,这很危险!),或者您可以注册(通常免费试用)许多短信网关服务,以提供单独的通信渠道,提供内置冗余来减少故障转移。

发送消息

这是最容易实现的部分,因为提到的两个服务(我将把它作为一个例子)都提供了一个 API,该 API 接受一个基本的 HTTP 请求并将其转换为文本消息。例如,我对mxsms-intelli的代码如下:

#!/usr/bin/php

<?php

include 'IntelliSMS.php';

array_shift($argv);   // ignore program name

$type = array_shift($argv);

$toAddr = array_shift($argv);

$message = implode(" ", $argv);

$fromAddr = "MinervaHome";

$objIntelliSMS = new IntelliSMS();

$objIntelliSMS->Username = 'MyUserName';

$objIntelliSMS->Password = 'MyPassword';

$objIntelliSMS->MaxConCatMsgs = 1;

$result = $objIntelliSMS->SendMessage($toAddr, $message, $fromAddr);

?>

信不信由你,这就是所有必要的代码!您可以通过以下方式可疑地调用它:

mxsms-intelli sms 012345678 This stuff really works

虽然文本消息可以扩展到几个包,但我将这里的最大值限制为 1,以防失控应用程序输出过多。自然,巧妙的格式化隐藏在库中,类似于 Txtlocal 版本中的使用,如下所示:

#!/usr/bin/php

<?php

array_shift($argv);   // ignore program name

$type = array_shift($argv);

$toAddr = array_shift($argv);

$message = implode(" ", $argv);

$fromAddr = "MinervaHome";

# Things get different now...

$uname = ' MyUserName';

$pword = 'MyPassword';

$message = urlencode($message);

$data = "uname=".$uname."&pword=".$pword."&message=".$message."&from=". $fromAddr."&selectednums=".$toAddr."&info=1&test=0";

$ch = curl_init('http://www.txtlocal.com/sendsmspost.php

curl_setopt($ch, CURLOPT_POST, true);

curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$result = curl_exec($ch);

curl_close($ch);

?>

每段代码的序言都是有意相同的。这使您可以根据您是否有信用或发送高优先级或低优先级的消息,交替使用这两种服务,也许是在循环的基础上。通过编写两个不同名称的脚本,您可以通过发出以下命令在它们之间手动切换,或者使用一个名为mxsms的单独脚本来确定使用哪种传输:

ln -s mxsms-intelli mxsms

我已经将一个$type参数传递到这段代码中,例如,SMS 可以变成sms-high,如前所述。这也可以用来更改$fromAddr,当您收到信息时,它会出现在您的手机上。它限于 11 个字符,但由于它是可定制的,它可以成为您的信息的一部分,可能表示以下内容:

  • 消息的优先级
  • 使用的服务提供商
  • 剩余的点数
  • 消息的前 11 个字母

每个提供者都有稍微不同的 API,具有不同的功能,但是就最终结果而言,它们都可以以相同的方式使用。

SMS 的一些应用包括向你的手机发送每日天气预报、新闻提要或彩票结果——或者报告其他住户何时到达或离开去工作(这样你可以打电话鼓励他们)。

Note

消费者可以使用的 SMS 协议并不保证消息会到达或会迅速到达。大多数人会,但也有可能(正如我们大多数人亲身经历的那样)它们会延迟几个小时,甚至几天,有时它们根本不会出现。因此,你应该没有什么重要的东西——比如生命维持机——依赖于这些信息。

您可能还想发送另外两种类型的消息,WAP 和二进制。WAP 消息是包含一段文本和一个 URL 的单信用 SMS 消息,可以使用电话本身打开(这可能会在该设备上产生费用)。这可用于更复杂的统计信息,其中执行摘要在文本中,URL 链接到同时上传到您的 WAP 服务器的预建图表。

二进制消息有 140 个字节,但是由于它的大小,仅限于发送小徽标(也可以表示服务器性能图!)或者铃声。

通过大多数(如果不是全部的话)SMS 网关 API 向一组用户发送多条消息是可能的,但是它们的管理通常是通过 Web。因为您有一个完全授权的 Linux 机器来控制您的环境,您也可以将地址存储在您的机器上,并以这种方式发送多条消息。费用一样,时差一般可以忽略不计。我将在第七章的中扩展mxsms脚本。

接收消息

这并不比发送信息更难,但它确实需要一些额外的步骤——而且,如果你想要自己的定制号码,成本会更高。在这两种情况下,SMS 网关公司代表您接收一条消息,然后通过另一种普遍认可的协议将它传递给您,以便您可以用它做一些特定的事情。根据公司、服务级别和 API,您可以执行以下操作:

  • 将短信作为电子邮件转发
  • 请求一个以发件人和消息为参数的网页
  • 发送自动回复
  • 转移到另一个(手机)号码

这里感兴趣的两个是电子邮件和网页处理程序。无论是哪种情况,SMS 基于文本的格式意味着解析器通常很容易编写。

用手机发送信息有几种方式。最便宜的方法是与其他用户共享一个号码。在这种情况下,您将向短信网关提供的号码发送一条包含您的用户名的消息。然后,网关用目标机器查找给定用户,并发出请求。该消息的格式可能如下:

username+your message here

或者如下:

username your message here

或者甚至如下:

null your message here

在后一种情况下(如 Txtlocal 所采用的),网关会查找您发送请求的电话号码,并在传递消息之前将其与您的帐户信息联系起来。该用户名(或 null)是否包含在消息中也取决于网关。

Tip

选择一个短用户名,如果可能的话,以节省短信字符!如果您在草稿文件夹中保存一个版本,并且每次都将它复制出来,就可以避免重复编写用户名。

或者,您可以购买特定的号码供我们自己使用。在这种情况下,您不必再在消息中包含用户名。这条路线通常会产生安装费。对于那些更有钱的人来说,你可以买一个特殊的短码(4 到 6 位数),它是长码的别名。然而,这些通常用于商业,并相应地定价。它们可能更容易记住,但只有当你的手机没电了,导致你的地址簿无法访问时,你才真正需要它们。在这种情况下,携带号码的书面副本更便宜!

因此,一旦消息到达,您必须处理它。对于电子邮件,您可以像前面看到的那样使用 Procmail,通过一个简单的正则表达式将以下内容处理成有用的东西:

##You have a new message from 012345678 saying Null This is my test.

注意,单词Null是免费协议和特定提供者的症状,如前所述。

网页请求是更简单的方法,因为 SMS 网关调用包含所有必要参数的预定 URL。每个公司都有不同的格式,所以创建一个名为echo.php的脚本用于测试是个好主意。

<?php

$rt.= "Get:\n";

$rt.= print_r($_GET, TRUE);

$rt.= "Post:\n";

$rt.= print_r($_POST, TRUE);

file_put_contents( '/tmp/log.txt', $rt, FILE_APPEND );

?>

因为 SMS 网关忽略它所请求的网页的所有输出,所以您永远看不到这些数据,这就是为什么您将其输出重定向到日志文件中的原因。您可以使用以下内容对此文件进行滚动更新:

tail -f /tmp/log.txt

然后发送一条文本消息,并让它重定向到echo.php,您将确切地看到提供了哪些参数。使用前面的示例,IntelliSoftware 提供了以下内容:

Get:

Array

(

)

Post:

Array

(

[from] => 012345678

[text] => This is my last test tonight

[msgid] => 50011005000001624552

[type] => 1

)

Txtlocal 给出了这个:

Get:

Array

(

)

Post:

Array

(

[sender] => 012345678

[content] => Null Wow this might work, you know!

[inNumber] => 447786202240

[submit] => Submit

[network] => UNKNOWN

[email] => none

[keyword] => NULL

[comments] => Wow this might work, you know!

)

两者都包含足够的信息,让你用一条短信就能打开灯。代码如下所示:

if ($_POST['from'] == "012345678") {

if ($_POST['text'] == "bedroom on") {

system("/usr/local/bin/heyu turn bedroom_light on");

} else if ($_POST['text'] == "bedroom off") {

system("/usr/local/bin/heyu turn bedroom_light off");

}

}

为了避免发送复杂的文本消息(也许还能省钱),您可以用一个简单的网页来测试这个脚本的未来排列。使用更简单的格式,您可以编写如下代码:

<form action="echo.php" method="POST">

<input name="from" value="phone num">

<input name="text" value="your message here">

<input name="msgid" value="" type="hidden">

<input name="type" value="1" type="hidden">

<input type="submit" value="Send Fake SMS">

</form>

因为这是在一个开放的 web 服务器上,所以存在一些安全问题。您可以通过在服务器上用一段代码验证电话号码来消除这种情况(不要在客户端验证凭证)。您可以通过将简单命名的echo.php脚本更改为iuytvaevew.php来进一步限制另一个问题(虽然不能消除它),通过模糊使用安全性,使它不会被意外发现。一些提供商将使用 HTTPS 调用您的网页,这是最好的解决方案,值得花费额外的时间为他们设置特定的用户名和密码。

您可以通过允许多部电话访问房屋、创建一个手机号码白名单以及显式添加到该列表来重新平衡安全性和可访问性的概念。或者,你可以禁止任何来自一个不被认可的 IP 地址访问你的页面。如果您可能通过 SMS 进行大量通信,您可以自动将新的电话号码添加到预批准设备的待定列表中,该列表反过来会向 SMS 管理员发送通知消息,管理员可以发出特殊命令将这些电话号码添加到列表中。

如果您的设施允许,在紧急情况下,当您没有互联网连接,并且您希望得到路由器正在进行自动电源循环的通知时,通过 Gnokii 连接一部物理移动电话可能会很有用(可能带有 AW12,如第一章中所述)。

结论

由于有如此多的进出系统的方式,您必须从一个坚实的框架开始。我的方法是将输入系统与处理分离,允许任何输入机制(移动电话、电子邮件或 web 界面)以已知的通用格式生成一个命令,该命令可以由一个脚本处理。同样,所有消息都被发送到一个脚本,然后该脚本将消息格式化为适合给定通信通道的特定格式。您还可以添加一个在收到任何或所有这些消息时的自动流程。因此,一旦你有了控制视频、灯开关或闹钟的代码,你就可以以任何顺序处理它们,或者通过电子邮件发送视频,或者通过短信发送灯开关,或者对着闹钟说话,或者进行上述操作的任意组合。

Footnotes 1

行进立方体算法代表了从体素空间提取多边形网格的方法,并且是 1987 年 SIGGRAPH 会议的特征。

2

真正意义上的“永远在线”宽带,与它的实际传输速度无关。然而,iPhone 用户可以启用网络共享,并在家中使用移动宽带共享坞站来利用他们的本地 WiFi 路由器。

3

如果你有几台机器,Nagios 之类的软件可以自动监控服务和应用程序,在出现故障时发送消息和更新网页。

4

为了客观起见,我也承认maildropdovecat存在并执行相似的任务。

5

显然,要将它与您将要用来测试的电子邮件地址相适应。

6

虽然我可以在主脚本中从头部解析它,但我是通过演示的方式来做的。

7

您还可以设置一个虚拟主机,只响应您的 intranet 上的机器,这样任何来自外部的请求都无法访问该文件。

8

如果你想复制粘贴,可以在 http://ubuntuforums.org/showthread.php?t=751169 查看详细内容。

9

声乐时间脚本在 Minerva 包中作为vtime提供。

10

在我看来,Audacity 仍然是 Linux 中音频采样和编辑的事实标准。

11

请给/dev/null发一封电子邮件!

12

互联网上有详细的相反的解决方案,但它们太复杂,无法在此讨论。

13

小偷使用类似的想法,在他们忙着向警方报告他们最近被盗的汽车时,按下satnav s 上的 home 按钮,开车到受害者的家。

14

Gnokii 能够用gnokii --getphonebook ME 1 end --vcard >myphonebook.vcf为你提供这种备份。

六、数据来源:智能家居

Abstract

虽然能够给你的电灯开关发电子邮件非常有趣,而且比编写另一个版本的“你好,世界”要酷得多,但它永远不会给人一种自动化房屋的感觉。毕竟,你作为一个人类正在控制它。通过向你的房子提供真实世界的信息,它就能自己做决定。这就是自动化家居和智能家居的区别。

虽然能够给你的电灯开关发电子邮件非常有趣,而且比编写另一个版本的“你好,世界”要酷得多,但它永远不会给人一种自动化房屋的感觉。毕竟,你作为一个人类正在控制它。通过向你的房子提供真实世界的信息,它就能自己做决定。这就是自动化家居和智能家居的区别。

为什么数据很重要

多年来,“内容为王”这句口头禅一直在各个技术领域重复。虽然到目前为止,您的家庭自动化环境中的大部分数据都是从您自己的私人生活模式中生成的,但仍有一小部分(但意义重大)数据是您没有生成的,例如电视时间表。我现在将介绍这些数据,看看有什么可用的,以及如何(合法地)利用它们。

法律上的义务

所有数据都受版权保护。无论是过去 20 年的降雨量表还是今晚的电视节目表,任何由人类编辑的信息都享有版权。例外的情况是,数据是由计算机程序生成的,在这种情况下,源数据的版权归创建它的个人所有,而编译版本的版权归帮助计算机生成它的人所有,通常是为机器付款的人。不幸的是,所有有用的数据都属于第一类。即使当数据公开时,例如在网站上,或者当它看起来是不言而喻的(例如前十名音乐单曲),数据仍然有版权,这要求您拥有使用它的许可。根据管辖范围的不同,版权将在最后一位在世作者去世后 50 年或 75 年失效。然而,随着新法律的出台,如《桑尼·波诺著作权保护期延长法》,即使是这么长的时间也可能会延长。在这个领域中,数据在变得可用之前就变得无用,这很不幸。

幸运的是,大多数国家都有供私人使用和研究的规定,允许您处理这些数据供个人使用。不幸的是,这不包括将数据重新分发给其他人或将数据转换成另一种格式。从纯粹的技术和法律角度来看,这意味着您不能执行以下操作:

  • 将这些数据提供给你家中的其他人。他们必须自己下载。这包括复制主页上的信息或将电视或无线电信号分发给其他机器。
  • 改进数据格式,并将其提供给技术上无法做到这一点的其他人。这包括解析来自一个网站的数据,以便在家中以更紧凑的格式显示。

在某些领域,是否允许你提供工具来改进或改变现有(受版权保护的)数据的格式,甚至存在合法性问题。幸运的是,大多数公司对这一领域视而不见,就像他们对你家庭成员的内部数据分配一样——即使你知道,他们也不会知道,或者能够证明。

更大的问题与数据的改进有关,因为大多数数据要么太原始,要么太复杂,没有用。让我们以一个包含天气预报的网站为例;原始数据可能只包含字符串“rain,25”,需要将其解析为一个漂亮的图标和一个温度条,以便于用户使用。一个复杂的报表可以在原始站点上包含一组友好的图形,但是如果其他人试图通过深层链接从另一个站点加载报表,或者试图引用用于构建图像的源表数据,则原始数据集对他们来说是不可用的。

屏幕抓取

这是一个通过命令行工具(如wgetcURL)下载网页的过程,然后由 HTML 解析器处理,以便从中读取和提取单个元素。这是法律上最可疑也是最麻烦的处理信息的方法。

这是最可疑的,因为你从一个网站下载版权内容的方式违反了该网站的条款和条件——以至于直到最近,一个著名的气象网站还将其图片标记为please_dont_scrape_this_use_the_api.gif

抓取很麻烦,因为很难准确解析网页的内容。在技术层面上解析页面非常容易,因为这种语言是基于计算机的,而且解析器已经存在。对于用户来说,解析呈现的页面中的数据也是非常容易的,因为人眼会自然地找出它想要的信息。但是知道信息在屏幕的左上角对机器来说是一件很难评估的事情。相反,大多数铲运机将根据阻塞原理工作。这是已知信息存在于特定块中的地方,由程序员预先确定,解析器盲目地从该块中复制数据。例如,它将转到网页,找到第三个表,在第五列和第二行中查找,并从第一个段落标记中读取数据。确定这一点很耗时,但很容易解析。这很麻烦,因为 HTML 格式本身的任何损坏(无论是开发人员有意引入的,还是由于广告 2 的变化而意外引入的)都需要修改或重写脚本。

由于潜在的屏幕抓取者可以使用的不同语言和库的数量,以及您想要将数据转换成的无限多的(尚未确定的)格式,所以实际上没有一个已知网站的数据库具有匹配的抓取代码。编制这样一个数据库将是一项艰巨的任务。然而,如果你不能编写合适的抓取代码,最好是去寻找当地的团体或基于相关网站的社区,比如电视粉丝页面。任何家庭通常都有大量的数据源,如果您单独尝试,为每个数据源维护刮刀将会非常耗时。

刮擦的机制最好用一个例子来解释。在这种情况下,我将使用 Perl 以及WWW::MechanizeHTML::TokeParser模块。首先,以任何适合您的发行版的方式安装它们。我个人使用 CPAN 模块,它通常在调用cpan命令时自动配置自己。可以通过添加到 URL 列表来添加其他镜像,如下所示:

o conf urllist push``ftp://ftp-mirror.internap.com/pub/CPAN/

o conf commit

接下来是模块本身的安装:

perl -MCPAN -e 'install WWW::Mechanize'

perl -MCPAN -e 'install HTML::TokeParser'

为了避免我主张抓取一个诉讼公司的页面,我将提供一个例子,使用我自己的 Minerva 站点从 http://www.minervahome.net/news.htm 的新闻页面中检索最新的故事。

首先在 web 浏览器中加载页面,感受一下页面布局,看看目标信息在哪里。此外,查看其他页面,看看是否有任何可以利用的共性。您可以通过查看源代码(查看整个页面或使用“查看源代码选择”选项)或借助 Firebug 3 来突出显示表和表中的子组件。

然后寻找任何“低垂的果实”这些是问题中容易解决的部分,所以您可能会在专门命名的div元素中找到所需的文本,或者在具有特定id属性的表中找到所需的文本。许多专业设计的网站这样做是为了让重新设计更快,并在不知不觉中帮助了刮刀。

如果文本周围没有明显的特征,就去寻找它周围的元素…以及周围的元素。向外工作,直到你找到足够独特的感兴趣的东西,或者到达根html节点。如果您没有发现任何独特之处,那么您必须用代码描述数据,例如“在第三个表的第一行第二列中”

一旦你能够用人类的语言描述数据的位置,你就可以开始写代码了!这个过程包括一个能够加载网页和遍历链接的机械化代理和一个跳过 HTML 标签的流处理器。您从一个相当常见的装载块开始刮削,如下所示:

#!/usr/bin/perl -w

use strict;

use WWW::Mechanize;

use HTML::TokeParser;

my $agent = WWW::Mechanize->new();

$agent->get("http://www.minervahome.net/news.htm

my $stream = HTML::TokeParser->new(\$agent->{content});

给定$stream,您现在可以跳到第四个表,例如,通过使用下面的代码跳过四个开始的table标签:

foreach(1..4) {

$stream->get_tag("table");

}

注意,get_tag将流点定位在给定的开始标签之后,在本例中是table。因此,流点现在在第四个表中。因为我们的数据在第一行,你不需要担心跳过tr标签,所以你可以直接跳到第二列:

$stream->get_tag("td");

$stream->get_tag("td");

因为跳过td标签将自动跳过前面的tr。该流现在被精确地定位在您想要的位置。该块的 HTML 结构如下:

<a href="url">Main title</a></td>

<td valign="top">

Main story text

到目前为止,我一直使用get_tag来跳过元素,但是它也有一个返回值,包含标签的内容。因此,您可以使用下面的代码从锚点中检索信息,根据其本质,可以返回多个标记:

my @link = $stream->get_tag("a");

因为您知道在这个特定的 HTML 中只有一个,所以感兴趣的是$link[0]。这是另一个数组,包含以下内容:

$link[0][0] # tag

$link[0][1] # attributes

$link[0][2] # attribute sequence

$link[0][3] # text

因此,您可以使用以下内容提取链接信息:

my $href = $link[0][1]{href};

因为get_tag只检索关于标签的信息,所以您必须返回到流中提取这个<a></a>之间的所有数据:

my $storyHeadline = $stream->get_trimmed_text("/a");

从这里,您可以看到您需要跳过下一个开始td标签,并在它和下一个结束td标签之间获取故事文本:

$stream->get_tag("td");

print $stream->get_trimmed_text("/td");

因为你只是从页面上获取第一个故事,所以你的抓取工作已经完成。例如,如果您想获得前两个故事,在再次重复解析循环之前,您需要正确地跳过该表或行的其余部分。

自然,如果这个网页以任何方式改变,代码就不能工作了!

当使用 Javascript 控制网页内容或布局时,这种公认的简单方法可能会失败。最常见的情况是,当页面使用 AJAX 调用进行分页时会出现这种情况。在这种情况下,next 按钮从服务器动态加载一些数据(用 Javascript)并重写适当的<div>元素的内容。您不太可能遇到这种带有有益于家庭自动化解决方案的数据源的页面,因为这里给出的示例都没有这样做。然而,如果你真的发现了一个(例如,超市经常这么做),那么你需要升级到一个无头浏览器解决方案,比如CasperPhantomJS,它允许你以编程方式点击页面上的按钮并调用这些 AJAX 请求。另一项旨在简化这一过程的新技术是“复制为卷曲”,在 https://twitter.com/ChromiumDev/status/317183238026186752 有所介绍。

幸运的是,web 开发人员和屏幕抓取人员之间的这场猫捉老鼠的游戏通常会有一个愉快的结局。为了我们!厌倦了每周重新设计他们的网站,并试图与 Web 2.0 和 Web 上的 mashup 社区连接,许多公司都提供 API 来访问他们的数据。而且,像大多数好的 API 一样,它们在不同版本之间保持稳定。

通过 API 的数据

API 是程序员与底层操作系统交互的方式。在 web 世界中,API 控制着脚本如何在 web 服务器上检索(有时改变)数据。这些可分为几大类:

  • 基本文件访问:这些文件通过网络服务器分发,文件名根据一些预先确定的规则格式化。例如,要获得三天后 BBC1 的英国电视节目表,您可以使用 URL http://www.bleb.org/tv/data/listings/3/bbc1.xml 。从最真实的意义上来说,这些不是 API,而是 REST 请求。然而,与静态文件不同的是,根据请求的时间或位置,相同的请求会产生不同的数据。
  • 公共查询:它们可以以多种形式存在,包括基本的文件请求,但它们通常基于简单对象访问协议(SOAP)对象或 HTTP 上的 XML。这允许使用强类型参数将函数调用发送到服务器,并使用 XML 或 JSON 返回类似的复杂回复。
  • 私有查询:这需要软件开发者注册一个开发者 API 密匙。这些,像 Amazon 的那些,被嵌入到您的代码中,以便服务器 API 可以验证用户并监控您的使用模式,从而消除大多数 DoS 攻击。

这些实现没有一致的法律术语。仅仅因为一个网站使用可公开访问的文件并不意味着你可以重新分发他们的数据。同样,您必须检查他们的服务条款(TOS),这些条款并不总是明显地显示出来。

在私人查询的情况下,TOS 将提前显示,并且您需要同意这些条款,然后才能分配给您一个密钥。这些条款通常会将您限制在每天或特定时间范围内的特定访问次数。通常这些限额可以随着货币的兑换而增加。

如果您正在寻找可以进行实验的 API,那么一个好的起点是 http://www.programmableweb.com/apis

分配

除非另有明确说明,否则您生成的任何数据都被视为原始版权版本的衍生作品。我只是演示了获取这些数据的方法(并且只供个人使用)。毕竟,在大多数情况下,版权所有者已经允许数据在有争议的网站上使用,但除此之外不得再分发。法律条文包括你家内部的再分配,但在大多数情况下(家庭服务器是私人的,对外界不可用),这成为一个争论点。

公开日期

在这一节中,我将介绍公众可以获得的数据。然而,它不一定在公共领域中可用,因此您仍然必须遵守前面提到的所有合法性规则。在每一节中,我将介绍一些对您的智能家居有用的示例数据,研究如何访问和处理这些数据,并讨论如何在家中私下合并公共数据。

电视指南

这么多国家有这么多电视台,为世界上所有的电视频道(更不用说它们的节目了)建立一个通用数据存储是一项巨大的任务。在英国,你要感谢 Andrew Flegg 处理英格兰、苏格兰、威尔士和北爱尔兰的所有数字、模拟和主要卫星站。

这个网站上提供的数据来自广播公司自己的网站,以及传统的数据,所以它是准确和及时的。这也是合法的,因为网站已经被允许收录。

Note

奇怪的是,英国互动电视公司的数据并不可用。这包括 ITV、ITV2、ITV3 和 ITV4。这是因为 ITV 不希望它的数据在其他网站上共享,尽管它不反对在自己的网站上使用其他电视时间表数据!这可能是因为其业务的纯商业方面。然而,在 ITV 改变规则(或者请愿书生效)之前,没有一个遵循这些指示的极客能够确定 ITV 上有什么,这反过来会限制 ITV 的广告收入,导致他们搬起石头砸自己的脚!

数据本身在网站上以网页的形式提供,或者以 XML 文件的形式提供,可以下载到你的电脑上,在你空闲的时候进行处理。每个 XML 文件的 URL 都遵循严格的格式,这样您就可以自动完成这个过程。

根 URL 是 http://www.bleb.org/tv/data/listings ,后面是:

  • 日偏移量,在-1(昨天)和 6(下周)之间
  • 站名

因此,你可以在这里找到今天的 BBC1 时间表:

http://www.bleb.org/tv/data/listings/0/bbc1.xml

明天的 TMF 指南在这里:

http://www.bleb.org/tv/data/listings/1/tmf.xml

格式是 XMLTV,很容易用合适的库甚至 XSLT 来解析。有了这种本地可用格式的数据,您就可以搜索由您最喜爱的演员主演的电影的描述,获得新系列的提醒,或者检查出现在您通常范围之外的脱口秀或节目中的音乐家。这些结果可以通过管道传输到任何文件,如网页或电子邮件,以供审查。

尽管它是免费的,但是 Bleb 本身也有一些限制,但是唯一的要求是不要通过在请求之间包含两秒钟的间隔来重复向服务器请求数据,并且在电子邮件中包含发出这些请求的程序名。

Minerva 提供了一个这样的例子;我在第七章中介绍了这一点。还有许多其他示例,如 Windows 的可执行文件、Flash 代码和 WhensItOn 代码,可在此处找到:

http://ccgi.useyourhead.force9.co.uk/

这将按字母顺序排列整周的电视时间表,以便您可以看到节目的播放时间和重播时间。

火车时刻

就像电视时刻表一样,获取世界上所有列车的完整时刻表是一项费力不讨好且不可能完成的任务。但幸运的是,像电视一样,感兴趣的铁路旅行通常基于一个国家,所以您只需要为您的地区找到一个合适的数据源。

任何搜索引擎都会为这些信息返回几个不同的数据源,这取决于您所在的国家,因此您需要花一点时间来查看每个数据源,以确定哪些具有 API(可用的),或者如果没有,哪些可以用最少的努力获得。大多数经常乘坐火车的人都有一个常规,他们知道时间表,所以最感兴趣的网站是那些报道实时信息的网站,包括晚点的火车和取消的火车。

在英国,最重要的网站是实时发车板( www.nationalrail.co.uk/times_fares/ldb/ ),它提供关于英国网络上大多数列车的相当准确的信息。不幸的是,它不包括 API,但它很容易为当前的火车时间收集信息,并且还附带了一个 Twitter feed,详细介绍了车站关闭和工程工作的超限情况。它还有一个优点是使用一个基本的GET请求来检索两个指定车站之间所有列车的时间,这使得书签更容易。我偶尔会在圣潘克拉斯和卢顿机场之间旅行。在查看该网站时,我可以看到 URL 在表单中包含了这两个位置:

http://ojp.nationalrail.co.uk/service/timesandfares/STP/LTN/today/0630/dep

所以,这可以用我们之前看到的同样的方法刮出来。然而,对该网站源代码的研究显示,有一个 AJAX 请求填充了该页面:

http://ojp.nationalrail.co.uk/en/s/ldb/liveTrainsJson

该页面可以通过修改参数(?liveTrainsFrom=STP&liveTrainsTo=LTN)来控制,并且可以合并到whattrain.php的代码 4 中,如下所示:

$url = "http://ojp.nationalrail.co.uk/en/s/ldb/liveTrainsJson

departing=true&liveTrainsFrom=$fromCode&liveTrainsTo=$toCode&serviceId=";

$contents = getContents($url, "ldb_${fromCode}_${toCode}", 5*60);

作为一个简单的请求,它只使用 GET,因此可以简单地通过 cURL 访问,或者直接在浏览器中访问,这有助于简单和直接的测试。您还可以将输出保存到一个临时的本地文件中,以便进行离线测试。URL 的结果输出提供了一个 JSON 对象,其中包含接下来要出发的几趟列车。然而,没有今天午夜之前的历史数据。

还值得注意的是,这里的 getContents 方法涉及一个临时文件,如果在上一个查询的五分钟内进行了后续查询,它可以避免再次下载数据。这可能需要根据您的需求进行更改。从这里开始,我们只需要解码 JSON:

$trainTimes = json_decode($contents);

$trains = $trainTimes->{'trains'};

这反过来允许您读取每个列车的信息:

foreach($trains as $entry) {

$expectedTime = $entry[1];

$destination = $entry[2];

$status = $entry[3];

$platform = $entry[4];

$arrivalTime = $expectedTime;

if (preg_match('/((\d+):0?(\d+))/', $status, $matches)) {

$expectedTime = $matches[0];

}

这个网站之所以被使用,部分原因是因为它提供了足够的信息,可以在赶火车时自动做出价值判断。例如,知道从工作地点到圣潘克拉斯需要 35 分钟,您可以排除在该窗口离开的任何列车。此外,通过添加宽限期,您可以将输出限制为在您到达车站后十分钟内离开的列车:

my $graceMinutes = $minutesAway - $timeToStation;

if ($graceMinutes >= $graceThreshold && $graceMinutes < $maxGracePeriod) {

print "Get the $expectedTime to $destination from platform $platform.";

print "There is $graceMinutes minutes grace.\n";

}

这个代码自然可以扩展为交换源位置和目的地位置,以便可以类似地考虑回程。例如,这可以通过观察一天中的时间来实现。

Tip

在单独的行上输出每段数据,使其他工具更容易提取信息。或者使用低级的结构化格式,比如 JSON,它有针对大多数语言的处理模块。

你现在有办法知道下一趟火车是哪趟了。这可以整合到每日新闻中,在做早餐时由语音合成器背诵,添加到个人聚合页面,或用于控制闹钟。(这种方法将在后面讨论。)

公路交通

随着全世界和他的狗都爱上了卫星导航系统,基于网络的交通报告的作用近年来变得不那么有用了。随着成本逐年下降,它不太可能很快复苏。然而,如果你只能选择一个小工具——卫星导航或有网络功能的掌上电脑——后者仍然可以通过一个实时交通网站胜出。

英国有像 Frixo ( www.frixo.com )这样的网站,报告所有主要道路的交通速度,并集成谷歌地图,这样你就可以看到各种热点。他们似乎也想到了 HA 市场,因为大部分数据都很容易获取,每个高速公路交叉口之间的道路速度、道路施工位置和旅游新闻都有清晰的标签。

天气

获取天气数据有三个来源:网上供应商、个人气象站或向窗外看!在接下来的部分中,我将只考虑前两个。

预测

虽然网上似乎有许多在线天气预报,但大多数来自天气频道自己的 Weather.com 。这个网站提供了一个网络插件( www.weather.com/services/downloads )、移动应用程序和一个本地桌面应用程序(仅限 Windows,唉)来访问其数据,但目前没有什么比 API 更开放的了。幸运的是,许多购买了这些数据的许可证的公司为他们网站的访问者提供了对这些数据的访问,并且限制较少。雅虎!例如,天气有 XML 格式的数据,可以很好地工作,但是需要一个样式表将它转换成任何可用的格式。

就像你刚刚看到的火车时刻表一样,每个网站都展示了它认为是信息和清晰度之间的最佳权衡。因此,一些天气预报只有一行每日评论,而其他的有每小时的细目分类,包括温度、风速和风寒因素。选择一个你喜欢的细节,如前所述,可以通过 API 获得,或者可以很容易地抓取。

在这个例子中,我将使用 Yahoo!报告。这是一个像天气一样经常变化的 XML 文件(真的!)并可根据您所在的地区下载。这可以通过浏览雅虎来确定!天气网站作为一个人,并注意到在网址上的论点。对于伦敦,这是UKXX0085,这使得预测源可以通过以下方式下载:

#!/bin/bash

LOGFILE=/var/log/minerva/cache/weather.xml

wget -qhttp://weather.yahooapis.com/forecastrss?p=UKXX0085

然后,您可以使用样式表和xsltproc用 XML 处理它:

RESULT_INFO=/var/log/minerva/cache/weather_info.txt

rm $RESULT_INFO

xsltproc /usr/local/minerva/bin/weather/makedata.xsl $LOGFILE > $RESULT_INFO

这将典型的 XML 转换成如下形式:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

http://xml.weather.yahoo.com/ns/rss/1.0【xmlns:geo = "http://www.w3.org/2003/01/geo/wgs84_pos#【版本= " 2.0】>

<channel>

<title>Weather - London, UK</title>

<language>en-us</language>

<yweather:location city="Luton" region=""  country="UK"/>

<yweather:units temperature="F" distance="mi" pressure="in" speed="mph"/>

<yweather:wind chill="26"  direction="50"  speed="10" />

<yweather:atmosphere humidity="93" visibility="3.73" pressure="30.65" rising="1"/>

<yweather:astronomy sunrise="7:50 am"  sunset="4:38 pm"/>

<image>

<title>Weather</title>

<width>142</width>

<height>18</height>

<url>``http://todays_weather_chart.gif</url

</image>

<item>

<yweather:forecast day="Tue" date="26 Jan 2010" low="30" high="36"

text="Mostly Cloudy" code="27" />

<yweather:forecast day="Wed" date="27 Jan 2010" low="26" high="35"

text="Partly Cloudy" code="30" />

<guid isPermaLink="false">UKXX0085_2010_01_26_4_20_GMT</guid>

</item>

</channel>

</rss>

变成这样的文字:

day:Tuesday

description:Mostly Cloudy

low:30

high:36

end:

day:Wednesday

description:Partly Cloudy

low:26

high:35

end:

这非常适合语音输出、状态报告或电子邮件。然而,makedata.xsl文件有点令人生厌:

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform

xmlns:scripts="http://www.bluedust.com/sayweather

xmlns:msxsl="urn:schemas-microsoft-com:xslt"

xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0

>

<xsl:output method="text" encoding="utf-8" media-type="text/plain"/>

<xsl:template match="/">

<xsl:apply-templates select="rss"/>

<xsl:apply-templates select="channel"/>

</xsl:template>

<xsl:template match="channel">

<xsl:apply-templates select="item"/>

</xsl:template>

<xsl:template match="item">

<xsl:apply-templates select="yweather:forecast"/>

</xsl:template>

<xsl:template match="yweather:forecast">

<xsl:text>day:</xsl:text>

<xsl:if test="@day = 'Mon'">

<xsl:text>Monday</xsl:text>

</xsl:if>

<xsl:if test="@day = 'Tue'">

<xsl:text>Tuesday</xsl:text>

</xsl:if>

<xsl:if test="@day = 'Wed'">

<xsl:text>Wednesday</xsl:text>

</xsl:if>

<xsl:if test="@day = 'Thu'">

<xsl:text>Thursday</xsl:text>

</xsl:if>

<xsl:if test="@day = 'Fri'">

<xsl:text>Friday</xsl:text>

</xsl:if>

<xsl:if test="@day = 'Sat'">

<xsl:text>Saturday</xsl:text>

</xsl:if>

<xsl:if test="@day = 'Sun'">

<xsl:text>Sunday</xsl:text>

</xsl:if>

<xsl:text>

description:</xsl:text>

<xsl:value-of select="@text"/>

<xsl:text>

low:</xsl:text>

<xsl:value-of select="@low"/>

<xsl:text>

high:</xsl:text>

<xsl:value-of select="@high"/>

<xsl:text>

end:

</xsl:text>

</xsl:template>

</xsl:stylesheet>

在几个地方,你会注意到奇怪的回车产生了一个更友好的输出文件。

由于查询这些 API 涉及到 CPU 时间,所以您下载并使用一个脚本(如前面所示)处理它们,并将其输出存储在一个单独的文件中。通过这种方式,您可以将天气更新脚本安排在凌晨 4 点,如果/当您查询它时,数据将立即可用,您会很高兴。然后,weatherstatus脚本变成如下所示:

#!/bin/bash

RESULT_INFO=/var/log/minerva/cache/weather_info.txt

if [ -f $RESULT_INFO]; then

cat $RESULT_INFO

exit 0;

else

echo "No weather data is currently available"

exit 1;

fi

这允许您将文本传输到语音合成的报警电话、网络报告、SMS 消息等。这里有几个通用规则,应尽可能在此类和其他类型的数据馈送中采用:

  • 每段数据使用一行,以便于后续处理
  • 首先删除旧的状态文件,因为错误的过期信息比没有信息更糟糕
  • 不要存储时间戳;文件里已经有了
  • 不要包含图形链接,不是所有的媒体都支持它们

在天气预报的情况下,您可能会反对最后一条规则,因为为每个天气状态提供可视图像是很好的。在这种情况下,更容易采用两个不同的 XML 文件,以适当的介质为目标。Minerva 通过一个用于完整报告的makedata.xsl和一个为语音和 SMS 生成稀疏文本的更简单的sayit.xsl来实现这一点。

本地报告

大多数小工具和电子产品商店出售简单的家用气象站。这些显示温度、湿度和大气压力。所有这些,经过一些练习,可以预测你所在地区第二天的天气,并提供最准确的预报,除非你住在国家气象中心的隔壁!

不幸的是,这些设备中的大多数都没有为它提供与计算机以及世界其他地方的接口。然而,有一些设备和一些名为wview ( www.wviewweather.com )的免费软件与之连接。该软件是一个守护程序和工具的集合,用于从兼容的气象站读取存档数据。如果工作站仅报告实时信息,则软件将使用 SQL 数据库来创建档案。然后,您可以像前面显示的那样进行查询,以生成您的个人天气报告。

Note

如果温度是你唯一关心的问题,市场上有几种基于计算机的温度数据记录器,可以让你监控室内和/或室外温度。其中许多可以通过标准串行端口与 PC 通信。

收音机

长期以来,广播一直是电视的穷亲戚,以至于许多人忘记了它曾经是我们最重要的媒体,对许多国家的战争努力至关重要。而且它还没死!没有其他地方能让你获得合法免费的音乐、乐队采访、新闻和电视剧(通常没有广告——比如 Spotify!)直接传到你耳朵里。此外,这些内容是经过专业编辑和选择的,以便与广播的时间(或晚上)相匹配。编写一个智能软件来自动选择一些夜间音乐,不太可能像你当地的电台 DJ 那样选择。

从技术的角度来看,许多电视卡都可以免费使用收音机,它有简单的软件来扫描带有fmscan的电台,并使用fm调谐它们。但是,它们通常必须与电视调谐软件分开安装:

apt-get install fmtools

了解各个电台的频率可以通过研究您当地的电台列表杂志(通常与电视指南捆绑在一起)或查看您所在国家的无线电监管机构的网站来实现,例如美国的联邦通信委员会(FCC)(使用 http://www.fcc.gov/encyclopedia/fm-query-broadcast-station-search 的表格搜索电台)或英国的 Ofcom。在后者的情况下,我被允许获取其封闭格式的 Excel 无线电频率电子表格(可从 http://stakeholders.ofcom.org.uk/broadcasting/guidance/tech-guidance/tech_parameters/ 下载各种格式)并生成 RadioXML 格式的开放版本( www.minervahome.net/pub/data/fmstations.xml )。从这里,您可以使用一个简单的 XSLT 表来提取电台列表,然后使用如下命令来调谐收音机和设置音量:

fm 88.6 75%

当这些信息不可用时,您需要搜索 FM 范围(通常是 87.5 6 到 108.0 MHz)来寻找可用的电台。幸运的是,有一个自动工具可以解决这个问题,它有一个额外的参数来指示信号必须有多强才能被视为“合拍”:

fmscan -t 10 >fmstations

我在这里用了 10 %,因为我所在的地区接收信号特别差,大多数电台的信号都在 12.5%左右。您将它重定向到一个文件中,因为fmscan过程相当长,并且您可能希望以后重新格式化数据。您可以使用以下命令列出各种电台和频率:

cat fmstations | tr ^M \\n\\r | perl -lane 'print $_ if /\d\:\s\d/'

或者按实力排序:

cat fmstations | tr ^M \\n\\r | perl -lane 'print $_ if /\d\:\s\d/' | awk -F :

'{ printf( "%s %s \n", $2, $1) }'| sort -r | head

在这两种情况下,通过按 Ctrl+V,然后按 Ctrl+M 来输入^M符号。

你会注意到有些电台在列表中出现了几次,例如 88.4 和 88.6。简单地挑选一个听起来最干净的,或者检查车站呼号。

有了频率,你就可以开始在网上搜索节目指南,寻找有趣的节目。这些必须总是从通过搜索电视台自己的网站找到的网页上抓取而来。像下面这样的术语:

radio 88.6 MHz uk

如果你用你自己的国家代替uk,通常会得到好的结果。你可以在 www.bbc.co.uk/programmes 找到 BBC 的主要电台。

还有一些预先录制好的 MP3 格式的新闻报道,可以下载或者用标准的 Linux 工具播放。这里有一个例子:

mplayerhttp://skyscape.sky.com/skynewsradio/RADIO/news.mp3

光盘数据

播放 CD 时,通常有两条信息您希望保留:曲目名称和封面图片扫描。前者更容易获得并集成到大多数翻录软件中,而后者则不是(尽管许多基于新媒体中心的软件都包含它)。

确定曲目名称的过程是确定 CD 上每首歌曲的起始位置和长度,并通过哈希算法使用它们来计算单个“指纹”数。因为制作中的每张 CD 都有不同数量的歌曲,并且每首歌曲都有不同的长度,所以这个数量应该是唯一的。(实际上,它几乎是唯一的,因为存在一些副本,但它足够接近。)然后将这个数字与已知专辑数据库进行比较,以检索由世界各地的志愿者人工输入的曲目名称列表。这些曲目名称和标题随后被翻录软件添加到 MP3 或 OGG 文件的 ID 标签中,以供以后参考。

如果您使用的是 CD 本身,而不是翻录版本,那么每次您想知道正在播放什么时,都必须手动检索这些信息。可以通过使用cdcd包来使用一个兼职解决方案,它允许您检索光盘的编号、名称、轨道及其持续时间。

cdcd tracks

前面的示例将生成如下开头的输出:

Trying CDDB serverhttp://www.freedb.org:80/cgi-bin/cddb.cgi

Connection established.

Retrieving information on 2f107813.

CDDB query error: cannot parseAlbum name:

Total tracks:  19   Disc length:  70:18

Track  Length   Title

-------------------------------------------------------------------------------

1:  > [ 3:52.70]

2:   [ 3:48.53]

3:   [ 3:02.07]

4:   [ 4:09.60]

5:   [ 3:55.00]

虽然这可以让您看到当前曲目(由>指示),但它并不比任何其他媒体播放器提供的更有用。然而,如果你已经安装了abcde ripper,你也已经(并且自动地)安装了cddb-tool组件,它将为你执行 CD 散列函数和数据库查询。因此,您可以用少量的脚本代码来确定光盘 ID、其名称以及每个轨道的名称:

ID=cd-discid /dev/dvd``

TITLE=cddb-tool query[http://freedb.freedb.org/∼cddb/cddb.cgi`](http://freedb.freedb.org/)

apphost参数是指当前机器的应用程序名和主机名。尽管它们的内容被认为是强制性的,但它们并不是至关重要的,只是出于对开发人员的一种礼貌才包括在内,以便他们可以跟踪哪些应用程序正在使用数据库。神奇的数字 6 指的是正在使用的协议。从这个字符串中,您可以提取流派:

GENRE=echo $TITLE | cut -d ’ ’ -f 2``

以及光盘的 ID 和名称:

DISC_ID=echo $TITLE | cut -d ’ ’ -f 3``

DISC_TITLE=echo $TITLE | cut -d ’ ’ -f 4-``

使用光盘 ID 和类型,您可以为相关光盘确定一个唯一的曲目列表(因为类型用于区分哈希值中的冲突),这允许您使用以下信息检索可解析的曲目列表:

cddb-tool read http://freedb.freedb.org/∼cddb/cddb.cgi 6 $(app) $(host) ←中

$GENRE $DISC_ID

光盘标题、年份和真正的流派也可以从该输出中获得。 8

要检索的一种更复杂的数据形式是专辑的封面艺术。这是 rippers,尤其是基于文本的 rippers 不做的事情,在开源世界中是一件碰运气的事情。这也是因为缺乏可用的数据来源。苹果拥有一家音乐商店,在那里封面被用来销售音乐,并随着专辑的购买而下载。如果你自己翻录音乐,你就没有这样的选择。

一个有用的图形工具是albumart。你可以从 www.unrealvoodoo.org/hiteck/projects/albumart 下载这个包,安装如下:

dpkg -i albumart_1.6.6-1_all.deb

它使用 MP3 文件中的 ID 标签在各种网站上执行搜索,例如 Buy.comWalmart.com 和 Yahoo!这种方法只不过是屏幕抓取,但是只要文件命名合理,结果就足够好,并且包含很少的误报。然而,当它在确定正确的图像时遇到问题,它会出于谨慎而不分配任何内容,等待您手动单击“设为封面”,这可能需要一些时间来纠正。一旦它获得了这些艺术文件,它就在适当的目录中把它们命名为folder.jpg,在那里它被大多数操作系统和媒体播放器拾取和使用。然而,额外的好处是,因为专辑封面使用文件中的 ID 标签,而不是 CD 指纹,所以它可以用来查找您已经翻录的音乐的图像。

Note

与曲目列表不同,封面艺术仍然是受版权保护的材料,因此没有独立的开发者试图用他们自己的数据库来简化这一过程。

正确地找到没有任何 id 或元数据的专辑封面是非常困难的工作。如果发生这种情况,有一个两阶段的过程可用。第一部分包括通过查看歌曲的音频属性来确定标题和艺术家,从而确定标签。MusicBrainz 是这个领域的主要(免费)竞争者。然后,一旦有了 ID 标记,就可以正常检索图像。这些步骤已经在 Jaikoz 这样的软件中进行了组合,jai koz 也可以作为一个海量元数据编辑包,可能对那些已经抓取了你的音乐但没有这些数据的人有用。

新闻

任何发生变化的数据都是新的,因此也是新的,这使它成为实时访问的理想选择。制作一个个性化的新闻频道是大多数聚合器正在做的事情,通过使用 RSS 提要和定制的小部件。例如,即将退役的 iGoogle ( www.google.com/ig )也包括与谷歌邮件和日历服务的集成,当作为主页查看时,这使其成为一个令人不安的有用主页,但其封闭的性质使其难以利用它作为家庭的数据输入。相反,我将介绍将典型的新闻条目作为单独的数据元素进行检索的方法,这些数据元素可以以适合我们自己的方式进行合并。这分为两种类型:推和拉。

报道的故事:推送

基于推送的媒体的引入可以追溯到 24 小时滚动新闻(Arthur W. Arundel 在 1961 年)或 RSS 9 提要,这取决于你的情况。这两种格式似乎都是在信息一被接收到的时候,就实时地将信息推给观众。实际上,两者的工作原理都是让查看器不断地从数据流中提取数据,忽略任何没有改变的内容。以电视为例,每次拉动都由一幅新图像组成,每秒钟发生几次。RSS 出现的频率要低得多,但却是我们感兴趣的。

RSS 源

RSS 是一种基于 XML 的元数据文件格式。它描述了大量频繁更新的信息。这可能包括对博客文章的引用、从国王十字车站离开 9 号站台的下一趟列车、新闻网站上的当前故事等等。在每种情况下,每一次更改都记录在 RSS 文件中,并带有非常重要的时间戳,使 RSS 阅读器能够确定对其中提到的数据的任何更新。生成这些 RSS 订阅源的软件也可能会删除对以前故事的引用,一旦它们变得不相关或太旧。但是,老是作者定义的。

这个事实上的标准允许您使用公共库来解析 RSS 提要,并非常简单地提取信息。其中一个这样的库是基于 PHP 的 MagpieRSS ( http://magpierss.sourceforge.net ),它也支持 RSS 的替代品 Atom feeds,并包含一个数据缓存。第二个特性使您的代码更加简单,因为您可以从 RSS 提要中请求所有数据,而不必考虑最新的数据,因为库已经自动缓存了较旧的故事。

在 PHP 中使用 MagpieRSS 的方法是从通常的代码开始:

require_once 'rss_fetch.inc';

然后,您从给定的 URL 请求一个提要:

$rss = fetch_rss($url);

自然,这个 URL 必须引用一个 RSS 文件(比如 www.thebeercrate.com/rss_feed.xml ),而不是它所描述的页面(比如 www.thebeercrate.com )。它通常由一个带有白色无线电波的橙色按钮或一个简单的表示“RSS-XML”的图标来表示。在所有情况下,RSS 文件都出现在您要读取其数据的同一页面上。您可以使用一个简单的循环来处理故事,如下所示:

$maxItems = 10;

$lastItem = count($rss->items);

if ($lastItem > $maxItems) {

$lastItem = $maxItems;

}

for($i=0;$i < $maxItems;++$i) { /* process items here */ }

当添加新故事时,它们会在文件的开头添加。如果您想要捕获所有内容,那么从项目列表的末尾开始非常重要,因为它们会很快从提要中消失。

如前所述,RSS 只包含元数据,通常是标题、描述和完整数据的链接。您可以通过数据成员从每个项目中检索这些内容:

$rss->items[$i]['link'];

$rss->items[$i]['title'];

$rss->items[$i]['description'];

然后它们可以用来以你想要的方式建立信息。例如,要在您自己的主页上重新创建信息,您应该编写以下内容:

$html .= "<a href=".$rss->items[$i]['link'].">".$rss->items[$i]['title']."</a>";

$html .= "<p>".$rss->items[$i]['description']."</p>";

或者您可以使用语音合成器来朗读每个标题:

system("say default "+$rss->items[$i]['description']);

然后,您可以使用一个 Arduino 来响应传感器发出的突然噪音,如拍手或挥手(使用第二章中的分压器电路,分别带有麦克风和 LDR)来触发完整的故事。

你还可以添加更多的逻辑,这样如果故事的标题包含特定的关键词,比如 NASA,你就可以把信息直接发送到你的手机上。

if (stristr($rss->items[$i]['title'], "nasa"))

system("sendsms myphone "+$rss->items[$i]['description']);

这对于接收最新的体育比赛结果、彩票号码或来自仍在世界各地播放的大量电视真人秀的投票信息特别有用。即使它需要一点智能修剪来将相关信息减少到 140 个八位字节(在美国)或 160 个字符(在欧洲、RSA 和大洋洲),这是单个未链接文本消息的最大长度,但它通常比注册提供相同结果的付费服务更便宜。

检索数据:拉取

这包括在需要时有目的地请求的任何数据。一个典型的例子是天气或金融信息,你可能会在新闻公告的结尾。在这些情况下,尽管可以通过模拟推送技术来实时更新信息,但很少有人需要这种粒度级别—每天一次就足够了。对于本例,您将使用从在线 API 中检索的数据来生成您自己的货币报表。这可以在以后扩展到生成货币换算表,以帮助您的假期融资,因为家庭自动化,正如我们所看到的,不会停在前门。即使你在国外,你也可以利用公共数据源,通过执行货币转换来检查你的支出。

货币兑换

虽然有许多转换网站,但它们提供的内容却千差万别。有些需要注册和申请 ID。有些将广告引入数据流。有些就是不起作用!因为谷歌免费提供转换功能作为其搜索引擎的一部分,所以没有理由使用其他任何东西。因此,我们可以从请求中提取数据,例如:

http://www.google.com/ig/calculator?hl=en&q=100EUR=?USD

它以如下形式返回一个 JSON 文本:

{lhs: "100 Euros",rhs: "134.14 U.S. dollars",error: "",icc: true}

因此,很容易理解如何构建一个应用程序来提供一个方便的双向转换图表。

<?php

$amount = "1";

$fromCurrency = "GBP";

$toCurrency = "EUR";

$url = "http://www.google.com/ig/calculator?hl=en&q=$amount${fromCurrency}=?$toCurrency

$rawdata = file_get_contents($url);

$data = explode('"', $rawdata);

$data = explode(' ', $data['3']);

$conversionRate = $data[0];

for($i=1; $i<=20; ++$i) {

print "$i $fromCurrency\t= " . number_format($i * $conversionRate, 2) . " $toCurrency \t";

print "$i $toCurrency\t= " . number_format($i / $conversionRate, 2) . " $fromCurrency \t";

print "\n";

}

?>

当然,在使用 explode 方法时,你可能不会像我一样懒,你可能更喜欢正式解码 JSON!

按照编写本报告时的汇率,这将产生:

1 GBP = 1.16 EUR        1 EUR = 0.86 GBP

2 GBP = 2.32 EUR        2 EUR = 1.72 GBP

3 GBP = 3.48 EUR        3 EUR = 2.59 GBP

4 GBP = 4.64 EUR        4 EUR = 3.45 GBP

5 GBP = 5.80 EUR        5 EUR = 4.31 GBP

6 GBP = 6.96 EUR        6 EUR = 5.17 GBP

7 GBP = 8.12 EUR        7 EUR = 6.03 GBP

8 GBP = 9.28 EUR        8 EUR = 6.89 GBP

9 GBP = 10.44 EUR        9 EUR = 7.76 GBP

10 GBP = 11.60 EUR       10 EUR = 8.62 GBP

11 GBP = 12.76 EUR       11 EUR = 9.48 GBP

12 GBP = 13.92 EUR       12 EUR = 10.34 GBP

13 GBP = 15.08 EUR       13 EUR = 11.20 GBP

14 GBP = 16.24 EUR       14 EUR = 12.07 GBP

15 GBP = 17.40 EUR       15 EUR = 12.93 GBP

16 GBP = 18.56 EUR       16 EUR = 13.79 GBP

17 GBP = 19.73 EUR       17 EUR = 14.65 GBP

18 GBP = 20.89 EUR       18 EUR = 15.51 GBP

19 GBP = 22.05 EUR       19 EUR = 16.38 GBP

20 GBP = 23.13 EUR       20 EUR = 17.30 GBP

从这里开始,您可以将此扩展到您的 HA 设置中,方法是使用“我花了这个”按钮将数据写入您家庭服务器上的网页,以跟踪您在国外花了多少钱。或者加上一句“我借钱给……”按钮,连接到您的联系人列表,这样你们可以在以后用本国货币结算。作为一个工具,它并不比你可能找到的任何其他转换应用程序或网站更好,但当它能够连接到同一台服务器上的待办事项列表,提醒你还钱或重新访问兑换局时,好处就变得显而易见了。

在所有情况下,您都将当前数据写入定期更新的日志文件中,就像您对天气状态所做的那样,原因是相同的——也就是说,防止不断滥用他人的服务器。然而,随着金融市场的变化越来越快,您可能希望一天更新该文件几次。

其他公共来源

许多其他组织向公众提供数据服务;事实上,太多了,不可能在这里一一列举。谷歌、亚马逊和 bit.ly 都向公众提供内容。虽然很多数据很有趣,比如欧洲燃油价格的比较,但大多数数据在智能家居环境中的应用有限。

典型的起点包括:

http://www.google.co.uk/publicdata

http://aws.amazon.com/publicdatasets/

https://bitly.com/bundles/hmason/1

随着第三方数据源抓取器和共享器寻求成为一个独立的生态系统,难怪人们一直在考虑将其标准化,以便不同的抓取器可以与一个共享的元级 API 交互。第一次尝试是通过:

http://import.io

这是一项新技术,到本书出版时,公众应该可以使用,因此希望它能为那些希望发现和利用更多家庭自动化数据集的人提供帮助。

私人数据

我们中的大多数人都在不归我们所有或控制的电脑上存有个人数据。即使我们中更关心的人试图在每一次行动中尽量减少这种情况,但这样做通常是不可能或不方便的。此外,(现在)有许多临时的 Linux 用户,他们完全基于桌面,对运行他们自己的远程服务器不感兴趣,并且乐意将他们的联系信息、日记和电子邮件存储在另一台计算机上。便利性是不可否认的——让你的数据可以从世界上任何一台机器上获得(通过网络连接),提供了一种真正的无位置限制的数字生活方式。但是一般来说,你的家不是没有位置的。因此,你需要考虑什么类型的关于你自己的有用信息被保存在其他计算机上,以及如何访问它。

日历

群件应用程序是 Linux 桌面软件特别薄弱的领域之一。谷歌凭借自己的解决方案谷歌日历(Google Calendar)进入了这个领域,谷歌日历可以链接到你的电子邮件,允许将每日提醒发送到你的收件箱以及其他人和团体的日历上。

未来 24 小时内发生的日历事件也可以通过短信查询,通过向 GVENT (48368)发送消息可以添加新的事件。目前,此功能仅适用于美国用户,但对于受其影响的用户来说是一项免费的 HA 功能。

日历中的信息是您的,可以通过几种不同的方式获得。首先,也是最简单的,它可以作为 iframe 嵌入到任何网页中:

<iframe src=" http://www.google.com/calendar/embed?src=my_email_address

%40gmail.com&ctz=Europe/London" style="border: 0" width="800" height="600"

frameborder="0" scrolling="no"></iframe>

这将显示当前日历,并允许您编辑现有事件。但是,您需要手动刷新页面才能看到编辑内容,如果不进入 Google 日历页面,就无法添加新活动。

这个公开网址打开的明显的安全漏洞被避免了,因为你必须已经登录到你的谷歌帐户才能工作;否则,将显示登录页面。

或者,如果您想在不登录 Google 帐户的情况下看到您的日历,那么您可以生成一个私钥,让知道此密钥的任何人都可以使用您的日历数据。密钥以秘密 URL 的形式出现。

要找到此 URL,请转到 Google 日历帐户右上角的设置链接,然后选择日历。这将打开您可以编辑和不可以编辑的日历列表。自然,你不能选择暴露只读变量的细节。因此,选择你自己的个人日历,向下滚动到标题为私人地址的部分。右侧的三个图标分别标记为 XML、ICAL 和 HTML,它们提供了一个 URL 来检索指定格式的日历数据。典型的 HTML 链接如下所示:

http://www.google.com/calendar/embed?src=my_email_address ←中

%40gmail.com&ctz=Europe/London&pvttk=5f93e4d926ce3dd2a91669da470e98c5

XML 版本如下所示:

http://www.google.com/calendar/feeds/my_email_address ←中

%40gmail.com/private-5f93e4d926ce3dd2a91669da470e98c5/basic

ICAL 版本使用的格式略有不同:

http://www.google.com/calendar/ical/my_email_address ←中

%40gmail.com/private-5f93e4d926ce3dd2a91669da470e98c5/basic.ics

后两个对我们更有用,因为它们可以在你选择的任何软件中查看(但不能编辑)。

如果您不习惯 XML 处理语言 XSLT,那么可以编写一个简单的 PHP 循环来解析 ICAL 文件,如下所示:

$regex = "/BEGIN:VEVENT.*?DTSTART:[^:]*:([^\s]*).*?SUMMARY:([^\n]*)

.*?END:VEVENT/is";

preg_match_all($regex, $contents, $matches, PREG_SET_ORDER);

for($i=0;$i<sizeof($matches);++$i) {

// $matches[$i][1] holds the entire ICAL event

// $matches[$i][1] holds the time

// $matches[$i][2] holds the summary

}

ICAL 中的日期格式可以存储为以下三种格式之一:

  • 当地时间
  • 带时区的当地时间
  • UTC 时间

您不必担心使用哪个版本,因为您可以使用现有的 PHP 库函数,例如:

$prettyDate = strftime("%A %d %b %Y.", strtotime($matches[$i][1]));

Note

请注意,数据的 XML 版本包含对日历的反向引用,其中包含您的私钥。

当然,其他在线日历应用程序也存在,提供类似的功能。此版本作为指南包含在内。但是在你自己的机器上获得数据后,你可以触发你自己的电子邮件通知,向谷歌目前不支持的国家发送短信,或者在出现“奶奶”和“生日”字样时自动加载当地花店的网页。

通过 POP3 访问网络邮件

当今的大多数员工认为移动电子邮件是办公室生活的一个标准特征。但是对于家庭用户来说,电子邮件属于两种类型之一:

  • 它是发送到他们的机器并由他们的本地客户端(通常是 Outlook Express 的旧版本)收集的东西;因此,它在其他地方是不可用的。
  • 这是一个基于网络的工具,由雅虎提供!、Hotmail 或 Google,只能通过网络浏览器访问。

虽然这两种说法都是(部分)正确的,但它确实隐藏了可以非常便宜地提供的额外功能。在第一种情况下,你可以提供你自己的电子邮件服务器(正如我在第五章第一节中提到的),并使用 AtMail 等软件添加一个网络邮件组件。这允许你的家用机器继续掌管你所有的邮件,除了你不需要在家使用它。

或者,您可以使用getmail通过替代(即非 web)协议接收您的 webmail 消息。首先,您需要确保您的网络邮件提供商支持 POP3 访问。这并不总是容易找到或确定,因为使用 POP3 意味着你将不再看到他们网页上的广告。但是当它可用时,通常可以在服务的设置部分找到。所有的大公司都提供这项服务,尽管不是所有的都是免费的。

  • Hotmail 默认提供 POP3 访问,这样就不需要打开了,而且在多年只在其订阅服务中提供这一功能后,现在 Hotmail 免费提供了。服务器目前在 pop3.live.com
  • Google Mail 是第一个提供免费 POP3 访问电子邮件的,从 pop.gmail.com 。虽然现在大多数帐户默认情况下都是启用的,但一些旧的帐户没有启用。因此,您需要选择设置和转发以及 POP/IMAP。在这里,您可以为所有邮件或任何新收到的邮件启用它。
  • 雅虎!仅通过其 Yahoo!外加付费服务。一些服务上有作弊软件(虽然不是雅虎!)将所有邮件转发到另一个提供免费 POP 服务的服务(如 Hotmail 或 Gmail)上!

之前有一个项目是直接处理 HTML 邮件,不需要为 POP3 服务付费。这包括现在已经不存在的 http://httpmail.sourceforge.net 。(幸运的是)这些措施已经没有必要了。

一旦你知道了你的邮件所在的服务器,你就可以下载了。这可以用于本地读取、用于备份目的,或者用于处理通过电子邮件发送的命令。虽然大部分邮件软件都可以处理 POP3 服务器,但是我用的是getmail

apt-get install getmail4

我对此进行了配置,以便将每个电子邮件帐户下载到一个单独的文件中。我将用一个例子来演示,从目录结构开始:

mkdir ∼/.getmail

mkdir ∼/externalmail

touch ∼/externalmail/gmail.mbox

touch ∼/externalmail/hotmail.mbox

touch ∼/externalmail/yahoo.mbox

然后为每个名为∼/.getmail/getmail.gmail的服务器创建一个单独的配置文件,内容如下:

[retriever]

type = SimplePOP3SSLRetriever

server = pop.gmail.com

username = my_email_address@gmail.com

password = my_password

[destination]

type = Mboxrd

path = ∼/externalmail/gmail.mbox

[options]

verbose = 2

message_log = ∼/.getmail/error.log

如果您希望它们进入传统的 Linux 邮箱,那么您可以将path更改为以下内容:

path = /var/mail/steev

然后,您可以像这样检索它们,并观看系统下载电子邮件:

getmail -r getmail.gmail

一些服务,特别是谷歌邮件,如果你有很多邮件,就不允许你一次下载所有的邮件。因此,您需要重新调用该命令。这有助于支持两台机器的带宽。

Tip

如果您只有一个外部电子邮件帐户,那么调用您的配置文件getmailrc允许您省略文件名参数。

然后,您可以在自己选择的客户端查看这些邮件。这里有一个例子:

mutt -f ∼/externalmail/gmail.mbox

确保您让getmail完成检索电子邮件;否则,您的收件箱中每封邮件都会有两份副本。

如果你打算用procmail处理这些电子邮件,正如你在第五章中看到的,那么你需要把收到的电子邮件写到procmail本身而不是收件箱。这是通过这样配置目的地来实现的:

[destination]

type = MDA_external

path = /usr/bin/procmail

unixfrom = True

推特

Twitter 这一现象让普通大众变成了自封的微型社区,因为他们接受了一种从一个人到许多“追随者”的简单广播通信机制。尽管通信通常是公开的,但还是可以创建一个用户列表,以便同一个家庭的成员可以私下相互跟踪。这可以通过在账户设置页面选择“保护我的推文”来实现。

Twitter 比大多数社交网站做得更好的一点是,它没有偏离其最初的微博理想,这意味着查询和控制提要的 API 保持一致。这使得你(或你的房子)很容易将信息发布到你的 feeds,或者让房子处理它们并根据它们采取某种行动。然而,在任何情况下,你都必须代表你的房子手动注册一个账户。过去几年中唯一的变化是通过要求使用 OAuth 来加强安全性。

用 OAuth 发布推文

Twitter API 使用 HTTP 请求来上传新的 tweet,主要实现是通过TwitterOAuth,来自 https://github.com/abraham/twitteroauth 的库。

$auth = getTwitterDetails($user);

$connection = new TwitterOAuth($auth->ckey, $auth->csecret, $auth->oatoken, $auth->oasecret);

$content = $connection->get('account/verify_credentials');

$connection->post('statuses/update', array('status' => $all));

这个例子使用 PHP,但是任何绑定了OAuth的语言都以同样的方式工作。你只需要填写你的登录凭证,你就可以从命令行发微博了。

$auth的结构就像它看起来一样简单,它由配置文件的内容和代码组成,例如:

function getTwitterDetails($user) {

$contents = @file("twitter.conf");

$oauth = new OAuthDetails();

$oauth->ckey = trim($contents[0]);

$oauth->csecret = trim($contents[1]);

$oauth->oatoken = trim($contents[2]);

$oauth->oasecret = trim($contents[3]);

return $oauth;

}

唯一复杂的是获取这些秘密值和令牌值。幸运的是,这是标准的做法,如果你以前和 OAuth 一起工作过,就不会出现警报和意外。如果你没有,请继续阅读…

访问 Twitter API 有几种不同的方式,但是对于我们的目的来说,我们想要的解决方案被称为“只想从您自己的帐户访问 API……”。这在 https://dev.twitter.com/docs/auth/tokens-devtwittercom 有解释。

从这里,您可以创建一个 Twitter 应用程序,这是必要的,因为与 Twitter API 通信的是您的脚本(即应用程序),而不是用户。这为您提供了一个消费者密钥和一个消费者秘密,ckeycsecret。有了这些,你就可以通过 Twitter 的 API 与它对话。

为了能够代表用户发布或阅读消息,他们需要代表 Twitter 向您的应用程序进行身份验证。这需要用户获取oatokenoasecret。在创建应用程序密钥之后,Twitter web 页面上有一个名为“您的访问令牌”的部分,它提供了获取这些数据的一键解决方案。将它添加到配置文件中,以便getTwitterDetails能够解析它,现在您就能够以编程方式发送 tweets 了。

用 OAuth 阅读推文

就像 tweets 可以用简单的 HTTP 请求编写一样,它们也可以被阅读。文档包括检索你的时间线、你的朋友的时间线以及转发等细节的 URL。这些调用返回关于所选 tweets 的所有可用信息,包括发帖人的完整信息(如他们的姓名、图像和关注者数量)、消息和回复数据(包括状态、用户和昵称)。这比您通常需要的要多,但是在 API 设计中尽可能不丢失信息是一个好主意——过滤掉比重新添加容易。你可以使用这个代码在离线时跟踪推文,方法是使用计算机截取适当格式的推文,然后用 SMS 传输代码发送它们。我们在第二章的中看到了一个这样的应用,自动喂狗器。

用 RSS 阅读推文

Twitter 的本质适合现有的 RSS 技术,不需要定制的解析器。用户@apress 的 URL 如下所示:

https://api.twitter.com/1/statuses/user_timeline.rss?screen_name=apress

它可以用 XSLT 检索和处理,或者与来自每个家庭成员的提要合并成一个,显示在房子的布告板上。这里的结果比它们的cURL对应物更简洁,更容易处理,代价是上下文信息更少。

脸谱网

虽然 Twitter 已经采用了广播机制,但脸书继续致力于促进与你共享数据的个人网络。对于 HA 来说,你可能对与朋友分享信息比与陌生人分享更感兴趣,所以这可能是更好的解决方案。然而,编写一个使用脸书的应用程序有较高的门槛,收益相对较少。作为补偿,它确实提供了一个预先存在的登录机制,并且是一个许多人比查看电子邮件更频繁的网站,因此信息可以更快地传播。然而,脸书确实会定期改变它的 API,所以某一天有效的可能第二天就无效了,你必须掌握它。如果你使用脸书作为一种允许几个人控制或查看你的主页状态的方式,使用你自己的主页可能更容易,有一组访问权限,正如你在第五章中看到的。

如果你仍然对脸书感兴趣,那么你应该安装开发者应用程序,并用它创建你自己的应用密钥。这将使您的应用程序能够对使用它的用户进行身份验证,无论是在脸书境内还是通过脸书连接在脸书以外的网站上。(在 www.scribd.com/doc/22257416/Building-with-Facebook-Social-Dev-Camp-Chicago-2009 有很好的基础教程。)要在您的家人之间保密,只需将他们的 ID 添加为开发者即可。然而,如果你想和你的孩子分享信息,让他们接受你是脸书的朋友可能会更困难!在这种情况下,你可能需要说服他们创建第二个账户,专门用于你的利益。脸书不允许你给没有安装该应用的用户(或被列入开发者名单的用户)发送消息,所以这需要谨慎管理。

相比之下,技术部分要简单得多,因为脸书提供了标准代码,这些代码可以被复制到你的网络服务器上的一个目录中,只要从脸书内部调用你的应用程序,就可以使用这些代码。然后由您来检查使用您的应用程序的用户的 ID,以确定他们有权使用什么功能,并相应地生成网页。你可以在 http://developers.facebook.com 的脸书自己的页面上找到很多有用的入门信息。

自动化

有了这些信息,你就要考虑房子会怎么用。这需要最个性化的发展。毕竟,如果你是轮班工作,那么我根据日出和日落的时间来控制灯光的代码对你来说用处不大。相反,我将提出各种可能性,让您决定如何最好地组合它们。

定时事件

生命受时间控制。因此,有一个机制来影响房子在某些时候是非常可取的。因为计算机的寿命也是由时间控制的,所以已经有现成的程序可以让我们轻松完成这项任务。

Cron 作业的周期性控制

它们的名字来源于类 Unix 操作系统的按时间顺序排列的作业调度程序,该程序在一年中的给定时间自动执行一个命令。有一个名为 crontab 的文件,它对这些作业有精细的粒度控制,每个用户都有单独的文件。您可以使用以下命令编辑这个属于当前用户的文件(如有必要,首先调用export EDITOR=vi):

crontab -e

还有一个–u选项,允许 root 编辑其他用户的 crontab。典型的文件可能以如下开头:

# m  h dom mon dow command

00  7  *  * 1-5 /usr/local/minerva/etc/alarm 1

10,15 7  *  * 1-5 /usr/local/minerva/etc/alarm 2

*/5  *  *  *  *  /usr/local/bin/getmail --quiet

#行是一个注释,作为列的提示;分钟、小时、日期(从 1 到 31)、月份(1 到 12,或以缩写命名)、星期几(0 到 7,星期日为 0 和 7)以及要执行的命令。每一列都支持使用通配符(*表示任意)、包含范围(1–5)、逗号分隔的序列(仅出现在 10 和 15 处)和周期(在本例中,*/5表示每五分钟一次)。当且仅当满足所有条件时,cron 程序才会调用该命令。

典型的用途可能如下:

  • 闹钟、触发信息、天气预报或醒来时的新闻
  • 以不同的速率检索一个或多个帐户的电子邮件
  • 启动本地数据、电子邮件或项目的备份
  • 度假时控制灯光
  • 当醒来时,控制灯逐渐打开
  • 生日、周年纪念日、母亲节等的现实生活提醒

因为这些操作是在 crontab 用户(即所有者)的支持下进行的,所以对于所讨论的命令必须有适当的权限。

Note

如果可能的话,许多用户试图避免以 root 身份运行任何东西。因此,在为您的家庭添加定时任务时,建议您为一个特殊的myhouse用户将它们添加到 crontab,并只为其分配所需的特定权限。

所提供的 crontab 精确到一分钟以内。如果你是极少数需要每秒精确度的人之一,那么有两种方法可以做到。两者都涉及在前一分钟触发事件并等待所需的秒数。第一个变化是将 crontab 更改为如下所示:

00  7  *  * 1-5 sleep 30; /usr/local/minerva/etc/alarm 1

第二种方法是将相同的sleep指令添加到运行的命令中。当以人性化的方式控制灯开关时,这可能是有用的,因为在打开楼上的灯之前花整整 60 秒爬楼梯是罕见的。

对于随机计时,您可以在继续执行命令之前休眠一段随机时间(sleep echo $((RANDOM%60))s``),正如您在第一章中看到的

也有一些情况下,您想暂时忽略 cron 作业,比如在我们度假时禁用闹钟。为此,您可以随时注释掉 crontab 中的行,或者更改以下命令:

/usr/local/minerva/etc/alarm 1

致以下内容:

[ -f ∼/i_am_on_holiday ] || /usr/local/minerva/etc/alarm 1

第一个表达式检查给定文件是否存在,如果存在,则跳过报警调用。因为这可以是位于任何地方的任何文件,所以它不需要属于 crontab 所有者就可以影响任务。一种可能的情况是使用蓝牙来监控接近的移动设备,在特定的目录中为每个用户创建一个文件(当他们超出范围时,即离开房间时,再次删除该文件)。一旦每个人都回家了,一个设置为每分钟检查该目录的 cron 作业可以发送一封电子邮件,提醒你离开计算机并进行社交!

对于更复杂的计时场景,您可以使用 cron 定期运行一个单独的脚本,比如每分钟运行一次。如果您返回到之前的“下一趟列车”脚本,您可以通过从这里检索第一趟合适的列车来赢得在家的每一分钟:

NEXT_TRAIN=whattrain.php 30 35 | head -n 1``

在这种情况下,合适的火车是在 30 到 35 分钟内离开的火车,这给你时间做准备。如果该命令产生输出,那么您可以使用语音合成器来报告它:

if [ echo $NEXT_TRAIN | wc -l -ne 0 ]; then

say default $NEXT_TRAIN

fi

同样的脚本可以用来自动改变你的闹钟的唤醒时间!

在第七章中,你将了解 Minerva 如何根据你是在家、在工作还是在火车上,通过向不同的地方发送状态消息来支持更复杂的动作。

At 时的偶然控制

除了周期性事件之外,您通常还希望调用额外的事件,比如十分钟后提醒检查烹饪情况。同样,Linux 准备了at命令,如下所示:

echo "say default Check on dinner" | at now + 10 minutes

这个语法是必要的,因为默认情况下,at从命令行交互地接受命令(以 Ctrl+D 结束)。每个at事件都进入一个队列,从而能够为多部分事件生成完整的配方。

唉,这个例子在它当前的场景中工作得很好,但是对于需要更细粒度的任务有一个致命的问题,因为调度器只处理整分钟,这意味着“现在+ 1 分钟”的任务实际上意味着“在下一分钟的开始”,这可能只有 5 秒钟的时间!所以,你需要使用“睡眠秒”技巧:

echo "sleep date +%S; say default Check on dinner" | at now + 10 minutes

也可以使用at在特定时间触发事件:

echo "say default Time for CSI" | at 21:00

这总是在下次到达该时间时发生,意味着它可能是在第二天。

错误处理

在任何开发中,报告和处理错误是项目中最耗时的部分。不幸的是,哈也不例外。有些事情对你有利,主要是你控制着房子和(大部分)在机器上运行的其他软件,所以如果有可能出现问题,你可以提前解决。但是如果你给你的视频发一条短信,你就无法知道这个命令是否有效,或者它在哪个环节失败了。这里有三条规则:

  • 始终确认命令和请求
  • 总是使用相同的媒介回复
  • 始终将回复记录到本地文件中,并可以选择通过电子邮件发送它们

第二个可能是不明显的。如果有人通过短信发送命令,那么回复也应该返回到短信,即使它的成本更高。这是因为发件人使用短信是有原因的——可能他们无法访问电子邮件或者网站已经坏了——所以他们只能放心地通过相同的途径发送。当然,消息要求将回复发送到其他地方是可以接受的,但是默认应该采用相同的路线。

这条规则适用于管道的每个阶段。因此,在 SMS 到电子邮件到 IR 的链中,如果 IR 单元出现故障,那么调用它(并正在处理电子邮件)的脚本必须在电子邮件中将错误传回。此时,SMS 到电子邮件网关会发现一个基于电子邮件的错误,并将其作为 SMS 传递给最终用户。

在这里,对 HTTP 中的思想进行修改是很有用的,在这里,您以数字、参数、描述的形式对每个请求采用三部分响应:

  • 数字是描述操作结果的数字代码。使用 200 来表示 OK,也许还可以加上各种错误代码来表示“找不到设备”、“磁盘已满”等等。这意味着在最低带宽的设备上,您将得到一个足以启动诊断的描述性错误。
  • 该参数涵盖了所涉及的特定设备或单元。
  • 该描述包含一个特定于设备的错误,它不应该重复与错误号或设备名称相关的任何信息(因为它们已经存在)。

因为链中的每个人都不知道各种错误消息的大小和格式,所以这种布局确保了系统的统一视图,并意味着自定义格式脚本能够为目标介质准备信息,可能通过包括数字错误代码的完整描述,或者可能会在 SMS 和 tweet 消息上裁剪描述文本。

结论

智能自动化家庭中的数据处理主要有两个阶段。第一种是收集,通常通过屏幕抓取、RSS 提要或 API 访问,在本地机器上提供一些远程数据的副本。这种情况既可能发生在您请求它的时候,如火车出发时间,也可能发生在您提前下载并缓存它的时候,如您在天气预报和电视时间表中看到的那样。第二个阶段是处理,将数据转换成更有用的东西,如简短的口头天气预报或可以点击播放的 CD 曲目列表。您了解了各种不同的数据格式,包括私人日历和公共新闻提要。只要花一点时间,极客们就能得到所有这些。正如我在本章的介绍中提到的,内容是王道,是让你的电脑能够独立思考并改善你的生活的一块巨大的垫脚石。

Footnotes 1

IANAL:我不是律师,所有标准的免责声明在这里都适用!

2

尽管网络是作为一种免费的信息资源而存在的,但有人会为广告空间付费以抵消制作成本。

3

Firebug 是 Firefox 的扩展,它允许 web 开发人员(和好奇的极客)完全访问浏览器中出现的网页的内部工作方式。

4

这是屏幕抓取的 Perl 代码,在您阅读本文时可能已经损坏。本章前面已经介绍了这种方法的相对缺陷和注意事项。

5

然而,有趣的是,我的当地 BBC 广播电台的网站省略了它的传输频率。

6

日本频段的下限为 76MHz。

7

这最初存储在 CDDB,但最近存储在 FreeDB。

8

这种方法有一个主要的未解决的问题。也就是说,如果有两张光盘具有相同的指纹或同一张光盘有两个数据库条目,则不可能自动选择正确的一个。因此,人类需要通过选择其中一个选项来解开混乱。

9

RSS 目前代表真正简单的联合,但它漫长而有趣的历史意味着它并不总是这么简单。

10

“关心”是“偏执狂”的政治正确说法

Logo

2万人民币佣金等你来拿,中德社区发起者X.Lab,联合德国优秀企业对接开发项目,领取项目得佣金!!!

更多推荐