使用siri控制服务器开关的方案
关于服务器的远程开关,尝试了很多方案,演化大致如下:从开始的WOL,到后来的ipmi,以及本文的homebridge方案。
严格来说,homebridge是一个转接平台,能作为一个主控让无法直接支持homekit的设备接入apple的生态,大致如下图。
+--------+ +------------+ +---------+ | iphone |-----| Homebridge |-----| Homekit | +--------+ +------------+ +---------+
本文并不涉及homekit API以及IPMI协议细节的分析,只分享方案。
插件配置
homebridge对接server的方案需要依赖一个插件 homebridge-http-switch
,当然读者要是有时间,完全可以自己定制。这个插件主要功能就是将power up、power down、power status这3个行为转换为Http请求,无非就是把服务器当做一个开关,相关homebridge的配置如下:
"accessories": [ { "accessory": "HTTP-SWITCH", "name": "服务器", "switchType": "stateful", "statusPattern": "{\"succuess\":true,\"data\":{\"status\":\"on\"}}", "onUrl": "http://10.0.0.3:65123/v1/power/up", "offUrl": "http://10.0.0.3:65123/v1/power/soft", "statusUrl": "http://10.0.0.3:65123/v1/power/status" } ]
如果你想要用siri进行控制,那么建议你把name设置为中文,否则siri的智障会让你崩溃。 statusPattern
主要就是用来判断status API返回的结果是否表示 on
这个状态。
ipmi API服务
读到这里,大家应该已经能够猜到还需要一个API服务控制服务器的开关,具体的思路是将请求转换为ipmi命令。关于API服务,我是用gin开发的,为了节省不必要的时间开销,直接使用了vmware的ipmitool封装—— goipmi
,这个没有文档,大概看下代码就行了,附上我使用的,大致如下:
func doPowerStatus() *IpmiResult { cl, err := ipmi.NewClient(&conn) if err != nil { return newIpmiResult(err) } defer cl.Close() res := &ipmi.ChassisStatusResponse{} req := &ipmi.Request{ NetworkFunction: ipmi.NetworkFunctionChassis, Command: ipmi.CommandChassisStatus, Data: &ipmi.ChassisStatusRequest{}, } err = cl.Send(req, res) if err != nil { return newIpmiResult(err) } power := IpmiPowerStatus {} if res.IsSystemPowerOn() { power.Status = "on" } else { power.Status = "off" } return newIpmiResult(&power) } func doPowerOperator(op string) *IpmiResult { cl, err := ipmi.NewClient(&conn) if err != nil { return newIpmiResult(err) } defer cl.Close() var cmd ipmi.ChassisControl switch op { case "up": cmd = ipmi.ControlPowerUp case "down": cmd = ipmi.ControlPowerDown case "reset": cmd = ipmi.ControlPowerHardReset case "cycle": cmd = ipmi.ControlPowerCycle case "soft": cmd = ipmi.ControlPowerAcpiSoft } res := &ipmi.ChassisControlResponse{} req := &ipmi.Request{ NetworkFunction: ipmi.NetworkFunctionChassis, Command: ipmi.CommandChassisControl, Data: &ipmi.ChassisControlRequest{cmd}, } err = cl.Send(req, res) if err != nil { return newIpmiResult(err) } if res.CompletionCode != ipmi.CommandCompleted { return newIpmiResult( errors.New(res.CompletionCode.Error())) } return newIpmiResult(nil) }
ipmitool power up ipmitool power soft ipmitool power status
ipmitool的使用方法请参考manual。
总结
可以看到,添加设备并重启homebridge后,在home app里面会出现一个开关的图案,由于提供了 power status
请求,因此这个服务是无状态的,每次打开app的时候,均会产生请求获取服务器的电源状态。
接入homekit之后的另一个好处就是,可以使用siri或者homepod进行控制了,真的是懒人必备。目前, goipmi
没有对于 sensor
命令的封装,暂时无法实现更加完善的监控功能,先不折腾了。
对于没有bmc的主板,先别沮丧,我也有方案:
power up power down power status
这套方案的最大缺陷是,开发板是单点,要是挂了,就会无法控制homebridge下挂载的设备。
Enjoy coding!