2018年7月21日星期六

Sonos One:满足但折中你的每一个愿望

Sonos One

我家里在饭厅和厨房之间放了一个老一代的 Echo,然后在我床头柜上放了一个 Echo Show。因为老一代的 Echo 感觉「听力下降」,整天喊它开电视关灯之类的都听不到,所以就想把它替换掉。正好前几天 Amazon Prime Day,Sonos One 打折到 $150 ,买两个都还是比 Apple HomePod 便宜,所以就赶紧买了两个。我的计划是,把 Sonos One 放到睡房里替换掉 Echo Show,这样我在睡房里播音乐打游戏就有 AirPlay 2 立体声了;然后用 Echo Show 把厨房的 Echo 替换掉解决它听力不足的问题。

第一印象

两个 Sonos One 到了之后,从包装上来看就感觉比 Echo 高级很多。Amazon 硬件包装简单优雅,Sonos 则要豪华和结实。Sonos One 包在一个布袋里面,然后放在厚厚的缓冲纸托盘上,底下还专门有一层纸托盘放电源线和网线。Sonos One 的 Wi-Fi 设置流程比我见过的其它硬件都要简单,因为它调用了 iOS 的外置硬件 Wi-Fi 设置流程,iOS 会自动帮你把 Sonos One 连上家里 Wi-Fi,完全不需要手动输入密码。在设置好两个 Sonos One 后,Sonos 会问你是不是把它们设置为一对立体声音箱,然后用 Trueplay Tuning 来校准它们。

Sonos 跟 Echo 对比

在把 Sonos One 设置好之后就可以把它们加入到 Alexa 设备当中了。Sonos One 说了自己不支持所有 Echo 支持的功能,是时候看看到底什么功能不支持了。

我之前设置了床头柜上的 Echo Show 每天早上播报新闻的,但在换成 Sonos One 之后发现 Alexa Routine 并不能在非 Echo 上执行。Alexa Multi-Room Music 不支持 Sonos One,所以不能让 Echo 和 Sonos 一起播放音乐。由此看来,Sonos One 只能对 Alexa 作出主动请求,而 Echo 能够被动地在 Alexa 的远程操纵下做事情。此外,Sonos One 对于 Alexa 唤醒的响应也没有 Echo 那么自然,喊完「Alexa」后它会响一下表示听到了,这时候我已经在说后面的指令了,这一下响声反而会把我打断。

关于 Echo,还有一件很奇怪的问题:我把老的 Echo 断电后,发现就再也不能通过 Echo 控制家里的 Hue 灯泡了。然而只要我把原来的 Echo 接上去,Hue 就又能用了。(不仅仅那个 Echo 能用,Echo Show 和 Sonos One 都能控制 Hue。)这让我怀疑那个 Echo 是否充当了什么神奇的角色,暂时的解决方案是让它继续保持在线。

Sonos 跟 HomeKit 连接

在配置好 Sonos One 之后,它会提醒你配置 Alexa,但不会提醒你配置 HomeKit。我一开始看到 AirPlay 2 能用了,还忘记要配置 HomeKit 了,想起来之后还查了一下才知道如何配置。(其实很简单,打开 Home 添加一下就可以了。)配置好 HomeKit 之后可以用 Siri 叫 HomeKit 操作 Sonos One,但因为我没有 Apple Music 也不怎么用 Siri,所以对我来说其实没用。

有一件很神奇的事情,那就是我在家里就算连接的不是这些智能硬件所在的 Wi-Fi 网络,我也能在 AirPlay 看到我的 Apple TV,然而却看不到 Sonos One。理论上最新版的 AirPlay 不要求设备都在同一个 Wi-Fi 网络,因为它们可以私下建立一个点对点网络,至少 Apple 的设备是这样做的。显然 Sonos 不支持这一项功能,不知道是硬件上的限制还是软件没有实现。这应该是一个 HomePod 能做好但 Sonos One 没做好的事情。(我没有 HomePod 所以不能确认,但我觉得 Apple TV 能做的事情 HomePod 应该也能做。)

总结

Sonos One 尝试把 Echo 和 HomePod 能做的事情给做了,确实也做到了一部分,但又明显有做得不完美的地方。这就是我标题所说的,满足你的每一个愿望,但每一个都要折中。

如果你喜欢类似的硬件测评文章的话,欢迎通过邮件RSS/Atom 订阅我的博客。

2018年7月1日星期日

Heroku + Node.js + HTTPS

昨天把 biz-to-me 升级到支持 HTTPS 了,为此研究了一下如何让 Heroku 上跑的 Node.js 应用支持 HTTPS。我发现并没有任何文章描述这个具体的流程,只有零碎的信息,所以在此记录一下。

首先,Heroku 应用要支持 HTTPS 必须要是付费的等级,最便宜的是每月 $7 的 Hobby 级别。把应用升级到 Hobby 级别后,我们在应用设置里面添加的域名就能自动获得 SSL 证书,这个过程是全自动的,无需手动操作。(全自动不意味着实时,每次添加新域名都需要等一段时间才会看到「ACM Status」这一栏变成「Ok」的状态。背后实际使用的证书签发机构其实是 Let’s Encrypt。)

Banners_and_Alerts_and_biz-to-me_·_Settings___Heroku

一般 Heroku 应用的「DNS Target」是 app-name.herokuapp.com,需要留意的是一旦升级到支持 SSL 后这一栏的内容会改变,变成 app.example.com.herokudns.com,也就是在 herokudns.com 之前加上应用的整个域名。如果之前 DNS 的 CNAME 指向还是 herokuapp.com,那必须记得更新为 herokudns.com,否则 herokuapp.com 不会使用正确的 SSL 证书提供服务。(herokuapp.com 永远只会用 *.herokuapp.com 的证书提供服务,而 herokudns.com 会根据前缀选择正确的证书。)

在大多数情况下,Heroku 应用升级到支持 HTTPS 后应用代码不需要更新,这是因为 SSL 连接在 Heroku 的负载均衡器那里就种终止了,负载均衡器用明文 HTTP 跟应用连接所以应用本身不需要具备处理 HTTPS 的能力。(Node.js 有 https 模块,但调用时需要访问证书私钥,所以还是用 http 模块比较方便。)如果需要在 Node.js 中判断上游请求是不是 HTTPS,可以通过读取 X-Forwarded-Proto header 来实现,这个 header 的取值可以是 "http""https",例如说在 biz-to-me 中我就通过这一行代码来进行判断。

最后简述一下如何验证配置是否成功。最简单的方法自然是测试一下 HTTPS 服务是否正常工作。biz-to-me 的服务很简单,如果我打开一个 http(s)://*.catchen.biz/* 的 URL,它返回 301 把我重定向到 http(s)://*.catchen.me/*。这篇文章的 URL 是 https://chinese.catchen.me/2018/07/heroku-nodejs-https.html,如果我 curl -i 对应的 catchen.biz URL 能得到正确的 301 重定向那就是成功了。

$ curl -i https://chinese.catchen.biz/2018/07/heroku-nodejs-https.html
HTTP/1.1 301 Moved Permanently
Server: Cowboy
Connection: keep-alive
Location: https://chinese.catchen.me/2018/07/heroku-nodejs-https.html
Date: Sun, 01 Jul 2018 21:29:36 GMT
Transfer-Encoding: chunked
Via: 1.1 vegur

Permanently moved to <a href="https://chinese.catchen.me/2018/07/heroku-nodejs-https.html">https://chinese.catchen.me/2018/07/heroku-nodejs-https.html</a>.

留意 Location header 的值是 HTTPS 开头的而非 HTTP,因为在 Node.js 代码更新到支持 HTTPS 之前我们也能得到类似的 301 响应,只不过 Location 永远都只是 HTTP 的。

如果 curl -i 因为证书不正确而出错的话,可以用 curl --insecure 来忽略证书验证 Node.js 代码。然后再用 curl -v 来查看证书,看看到底为什么证书错误。curl -v 的结果关键看这一段:

* Server certificate:
*  subject: CN=cantonese.catchen.biz
*  start date: Jul  1 04:44:37 2018 GMT
*  expire date: Sep 29 04:44:37 2018 GMT
*  subjectAltName: host "chinese.catchen.biz" matched cert's "chinese.catchen.biz"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.

如果 Heroku 应用只添加了一个域名,subject 那一行的域名必须是这个唯一域名。如果看到 subject 那一行显示的是 *.herokuapp.com,那意味着我们需要把域名 CNAME 改为 herokudns.com,或者是域名变更还没生效。(变更还没在本地 DNS 生效的话,可以用 curl --resolve 在本地强行覆盖。)如果 Heroku 应用有多个域名,subject 会是其中一个,但 subjectAltName 会有多个域名,至少应该找到有一个对的。

最后,如果你喜欢我的文章的话,欢迎通过邮件RSS/Atom 订阅我的博客。