Cloud Of Smart Home

来自Jack's Lab
跳转到: 导航, 搜索

目录

1 概述

专为智能家居而生的物联云

服务于各类爱好智能家居的中小厂商、宅男宅女,他们爱动手、爱思考、对隐私和家居安全敏感


家居环境:
  • Living Room
  • Basement
  • Bathroom
  • Bedroom
  • Den
  • Dining Room
  • Downstairs
  • Entryway
  • Family Room
  • Hallway
  • Kids Room
  • Kitchen
  • Master Bedroom
  • Office
  • Upstairs



1.1 HOME

远期规划

一个 Home 下可有多个设备 (device) 和多个家庭成员 (member)

Home 用一行描述,当前状态用一个 JSON 结构,包含所有member,controller,sensor 的状态,写在 stat 域里

家里新加的传感器、控制器、成员,可在APP里直接选择用 Home 的 UUID push 数据和状态,在参数里,写上name,type,数据等,云端首先遍历下级node列表,识别是否已有同名的设备,没有则为其创建新 node,并加到 node 列表里


家只关心,成员、控制器和传感器的状态,因此都写在 stat 域里即可。各下级node更新状态时要记得更新其在上级node之stat 域中的数据值

name, type, up_nodes, down_nodes, state, uuid, meta:{}

meta: {
    mac:"aa:bb:cc:dd",
    ip:"123.11.1.1",
    activate:1,
}



1.2 Device

设备是传感器 (sensor) 和 控制器 (controller) 统称。客厅大灯是一个设备,当然他只是一个控制器,因其主要响应用户的控制行为。客厅的温湿度检测也是一个设备,实际他是一个传感器,因其主要负责收集数据。贴于门窗上的门磁也是一个传感器设备。


传感器的值、控制器的状态都写在 state 域里,方便设备 check 以实现远程控制。每次push 的数据或状态则写在 datapoints 表里,带时间戳,方便呈现和日志检查

同时带有多个感应和多个控制的设备,也用一行描述,当前状态用一个 JSON 结构,写在 state 域里


设备新加的传感器、控制器,可在APP里直接选择用 Device 的 UUID push 数据和状态,在参数里,写上name,type,数据等,云端首先遍历下级node列表,识别是否已有同名的设备,没有则为其创建新 node,并加到 node 列表里


name, type, up_nodes, down_nodes, state, uuid, auth:{}, meta:{}, trigger:{}

meta: {
    product: "camgo",
    activate: 1,
    rom: {
        version:"1.0.2",
        latest_version: "1.0.5",
        url: "/v2/roms/camgo.1.0.5.bin"
    },
    mac: "XXXXXXXXXXXX"
}

auth:{"pubkey":"XOIO1234", "algo":"xx", "seed":"12345" }

trigger: {
    wexin:{root:wx_user1, users:[wx_user1, wx_user2...]},
    "166745":{msg:"家里大门开了", wexin:{root:wx_user1, users:[wx_user1, wx_user2...]}},
    "139225":{msg:"客厅阳台门开了", weixin:{root:wx_user1, users:[wx_user2, wx_user3...]}}
}

state: {
    value: 55
}



1.3 Member

远期规划

对于一个家庭成员追踪设备,则各人智能手机为感知端(用户可选择是否定时上传 GPS/GSM 数据),加一些虚拟控制器,比如 weibo 推发器


stat 描述有 member 的坐标、体重、心率、运动量等等数据。如新买一血氧的设备,想要关联到 member,可用member的 UUID 生成 Token 来 push 数据,在参数里,写上name,type,数据等。云端会首先向 datapoints 记录一条记录,然后取 member 行(位于 Node 表)的 stat,解析后,将新数据域加入。


微信可以抽象为控制器;微博也可以抽象为控制器

手表/手环的消息提醒,振动提醒等也可以抽象为控制器


name, type, up_nodes, down_nodes, state, meta:{email, password, weixin, weibo, mobile, imsi}, uuid, pub_key

state:{
    coords:{lat:123, lng:234}, cell:{mcc: 460, mnc: 0, lac: 123, cid: 456}
}



1.4 Trigger

每次 push 一个 state,云端检查一下相关的触发器,条件满足则执行相应的动作

注意:作为一个安全的云的必要设计,改控制器状态由家庭设备或家庭成员的手机完成,加密过后的数据,云端无法解读,因为加密在家庭设备端用私钥完成,云端无法解密,也就无法更改控制器状态


一个 Trigger 描述为:

trigger: {
    "default":{msg:"默认消息", wexin:{root:wx_user1, users:[wx_user1, wx_user2...]}, alarm: 1},
    "166745":{msg:"家里大门开了"},
    "139225":{msg:"私房们开了", weixin:{root:wx_user2, users:[wx_user3]}, alarm: 1},
}

trigger: {
    "fun":{cond:"x>1 && y>3", action:[{weixin:{}},{controller:""}]}
}




2 框架

首先在 Web UI 下创建 Home,生成密钥对(界面自动生成一对,也可本机开源工具生成,然后将公钥填入Web UI,此为社交需求,可授权云端解密给家庭信任的用户,也可不上传公钥,这样云端永远无法知道家庭的状态)


云端只存储家庭成员加密过的控制器状态、传感器值(可加密可不加密)和家庭成员定义的任务事件(触发器,外网相关,比如发微博,发微信,发邮件,发短信等。改控制器状态由家庭设备或家庭成员手机完成),加密过后的数据,云端无法解读,因为加密在家庭设备端完成,云端无法解密,也就无法更改控制器状态

家庭私钥只有用户自己保存,私钥不在公开的网络上传输,云端也不存储。没有私钥就不能产生加密的状态值,控制器也就无法改变状态


控制器设备只要每 1s 去取一下云端的控制器状态值,回来解密,检查是否需要响应家庭成员的要求


---

设备、感知端、控制端 之间的关系为松耦合,即:一个设备可以只有一个感知端(只作数据呈现),或者只有一个控制端(只接受控制指令);一个感知端可用于多个设备,一个控制端也可为多个设备所用


简单如一个体重称,可作为只有一个传感器的设备

一个家庭灯光设备,可以有多个环境光强传感器,声控传感器(亦可作为其他设备的输入,比如窗帘控制设备),甚至手势传感器,控制器则对应各房间灯的开关




3 Open API

3.1 Activate

激活就是告诉云端:生产的设备已经联网并能正常工作了


CamGo 的设计:(X1)
方案一:

每个设备都有一个唯一的串号 SN,写在二维码里

扫描二维码,APP会获取 SN,APP自动生成一个密钥对,用私钥将 时间戳和SN 加密后,作为调用 Activate API 的一个参数,另一个参数是生成的公钥 x-key


方案二 (实际使用方案):

设备的串号 SN、KEY 和 MAC 写在 eeprom 里

update state 时,用 SN + KEY 生成动态 token,云端检查 token 验证合法身份

用户关注公众号绑定看门狗后(扫描二维码或手工关注后绑定),视为激活,此过程可从 weixin agent 调用 Activate 接口


{"weixin":"userid"}

云端收到后,首先解析设备node_row 的meta->activated域,为1视为激活,再解析 trigger 域,
有 weixin->root 则视为激活过,此时添加的 weixin 用户,置于 weixin->user 列表里


---

mini 的设计是这样:(M1)
方案一:

启动 APP,APP自动断开原WiFi的连接,搜索 miniCamGo 的AP,自动连接(内置密码),最好能做到将用户手机里存的AP直接配置给mini

配好后,APP自动生成一个密钥对,发给 mini,mini 收到后,保存,向用户返回 SN,APP用此生成一个微信二维码,供用户向家人分享

APP 断开和 mini 的连接,用私钥将时间戳和SN 加密后,作为调用 Activate API 的一个参数 Token,另一个参数是生成的公钥 x-key


方案二:

用户启动 APP,APP自动断开原WiFi的连接,搜索 miniCamGo 的AP,自动连接(内置密码,可以设计为无密码),将 AP 的 SSID 和密码配给 miniCamgo

miniCamgo 能通过 wifi 第一次访问激活接口,就视为激活

{"activate":1}


---


首次调用activate接口的,拥有设备的最高权限,用户设置一个分享码(不设系统默认生成)

随后扫描的,需输入分享码,才能拥有这个设备的使用权(APP 如检测到其和拥有者使用相同的 AP 热点,可不用输入分享码)


激活时以路由的MAC地址为关键字,创建HOME且与SN关联;以用户手机的imsi为关键字,创建USER且与SN关联


/v2/node/activate
# cat post-activate1
POST /v2/node/activate HTTP/1.1
Accept: */ *
nodid: BFEB5E8E2BD9A795222
token: 15F7E14203AD318B0AB05514A6BD5B072830A076267C66E2X
Content-Length: 19
Content-Type: text/html
Connection: close

{"weixin":"comcat"}

# cat post-activate2
POST /v2/node/activate HTTP/1.1
Accept: */ *
nodid: BFEB5E8E2BD9A795222
token: 15F7E14203AD318B0AB05514A6BD5B072830A076267C66E2X
Content-Length: 17
Content-Type: text/html
Connection: close

{"weixin":"gaga"}

# cat post-activate3
POST /v2/node/activate HTTP/1.1
Accept: */ *
nodid: BFEB5E8E2BD9A795222
token: 15F7E14203AD318B0AB05514A6BD5B072830A076267C66E2X
Content-Length: 14
Content-Type: text/html
Connection: close

{"activate":1}

# cat get-activate
GET /v2/node/activate HTTP/1.1
Accept: */ *
nodid: BFEB5E8E2BD9A795222
token: 15F7E14203AD318B0AB05514A6BD5B072830A076267C66E2X
Content-Length: 0
Content-Type: text/html
Connection: close

# cat post-deactivate
POST /v2/node/activate HTTP/1.1
Accept: */ *
nodid: BFEB5E8E2BD9A795222
token: 15F7E14203AD318B0AB05514A6BD5B072830A076267C66E2X
Content-Length: 14
Content-Type: text/html
Connection: close

{"activate":0}




3.2 Node State

/v2/node/state


Input:

{"value":123}
{"value":{"x": 12, "y": 12, "z": 12, "k": 22, "l": 33}, "deliver_to_device": 0}
{"coords":{"lat":123, "lng":234}, "cell":{"mcc": 460, "mnc": 0, "lac": 123, "cid": 456}}

{"living_room":{"timestamp":"", "illuminance":10, "temperature":20, "humidity": 18}}
# cat get-state
GET /v2/node/state HTTP/1.1
Accept: */ *
x-key: daxuexeprs
nodid: BFEB5E8E2BD9A795222
token: 15F7E14203AD318B0AB05514A6BD5B072830A076267C66E2X
Content-Length: 0
Content-Type: text/html
Connection: close

# cat post-msg
POST /v2/node/state HTTP/1.1
Accept: */ *
x-key: daxuexeprs
nodid: BFEB5E8E2BD9A795222
token: 15F7E14203AD318B0AB05514A6BD5B072830A076267C66E2X
Content-Length: 16
Content-Type: text/html
Connection: close

{"value":139225}



3.3 Node Beacon

  /v2/node/beacon



3.4 Node Trigger

   /v2/node/trigger

    add new trigger:

        {"value":12356,"msg":"door opened"}
        {"value":12356,"msg":"door opened","weixin":"comcat"}

    update trigger:
        {"value":12356,"msg":"doorxx opened","weixin":"gaga"}
        {"value":12356,"weixin":"gaoxiaoduo"}

    user update trigger:
        {"alarm":{"all":1,"unknown":0}}
        {"alarm":{"all":1}}
        {"alarm":{"unknown":0}}



3.5 Node CMD

   /v2/node/cmd
meta: { "cmd":{"开庭院灯":{"state":{"value":1} } } 
meta: { "cmd":{"拉警报":{"state":{"ch2":1} } } }
meta: { "cmd":{"升晾衣架":{"state":{"value":"231080FD020043E2", "meta":"0,4,425,64"} } } }
meta: { "cmd":{"vo":{"ctrl":17 } } }


POST:


{ "cmd":"关庭院灯", "action":{"state":{"ch1":0}} }
{ "nodid":"XXXXXXXXXX", "cmd":"关庭院灯", "action":{"state":{"ch1":0}} }

写入 meta 域,仅仅是个结构描述,不改变设备云端状态。用户在微信文本输入或者语音输入对应的命令字时,命令关键字匹配,进而取得 "cmd":{} 结构中对应的元数据,解析后,写入相应的位置 state/meta->ctrl


GET:

返回整个 { "cmd":{"开庭院灯":{"state":{"value":3} } } } JSON 结构,用户设置时,选择性呈现给用户,这个域默认不可编辑(可开启编辑),可特定生成



3.6 ROM Update

/v2/node/rom/version
/v2/node/rom/update?version=xxx



3.7 Manufacture

/v2/nodes
{"type":"device", "state":"{}", "uuid":"", "auth":{"pubkey":"XOIO1234", "algo":"xx", "seed":"12345" }, "meta":"", "trig":"{}"}



4 具体产品

  • 智能插座
  • 庭院监控 - 360度遥控云台,高分贝警报器,50W LED 射灯,WiFi 720p 摄像头,所有这些都在一 MaiKe WiFi 模块控制下
  • 智能灯



5 数据结构

5.1 Action Sets

id, timestamp, action, processed

action: {
    msg: 客厅阳台门开了,
    weixin: [u1, u2, u3 ...]
}



5.2 Node

HOME, Device, Member 统一编号,皆可抽象为 Node (节点)

每个 Node 都有唯一的 UUID,用来与云端交互

每个 Node 带有 id, name, type, stat, up_node, down_node, uuid, ext1, ext2


Home 类型 为 0x10

Member 类型为 0x20

Sensor 类型为 0x40

Controller 类型为 0x80

Device 类型为 0xC0





6 性能测试

6.1 http_load

官网:http://www.acme.com/software/http_load/

$ http_load -rate 5 -seconds 10 http://t.tt
49 fetches, 2 max parallel, 289884 bytes, in 10.0148 seconds
5916 mean bytes/connection
4.89274 fetches/sec, 28945.5 bytes/sec
msecs/connect: 28.8932 mean, 44.243 max, 24.488 min
msecs/first-response: 63.5362 mean, 81.624 max, 57.803 min
HTTP response codes:
  code 200 -- 49



6.2 ab

  • ab - Apache HTTP server benchmarking tool
$ sudo apt-get install apache2-utils
$ ab -c50 -n3000 -H "nodid: BFEB5E8E2BD" -H "token: 15F7E14203AD318B0AB05514" http://icamgo.com:998/v2/node/state

Server Software:        HTTP::Server::PSGI
Server Hostname:        icamgo.com
Server Port:            998

Document Path:          /v2/node/state
Document Length:        53 bytes

Concurrency Level:      50
Time taken for tests:   29.820 seconds
Complete requests:      3000
Failed requests:        0
Write errors:           0
Total transferred:      654000 bytes
HTML transferred:       159000 bytes
Requests per second:    100.60 [#/sec] (mean)
Time per request:       497.000 [ms] (mean)
Time per request:       9.940 [ms] (mean, across all concurrent requests)
Transfer rate:          21.42 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        4  210 112.3    255     405
Processing:    20  284  39.8    288     418
Waiting:       20  283  39.6    287     418
Total:         80  493 116.3    524     749

Percentage of the requests served within a certain time (ms)
  50%    524
  66%    556
  75%    576
  80%    588
  90%    625
  95%    651
  98%    678
  99%    702
 100%    749 (longest request)

$ ab -c50 -n3000 -p deactivate -H "nodid: BFEB5E8E2BD" -H "token: 15F7E14203AD318B0AB05514" http://icamgo.com:998/v2/node/activate

Benchmarking icamgo.com (be patient)
......
Finished 3000 requests

Server Software:        HTTP::Server::PSGI
Server Hostname:        icamgo.com
Server Port:            998

Document Path:          /v2/node/activate
Document Length:        18 bytes

Concurrency Level:      50
Time taken for tests:   31.158 seconds
Complete requests:      3000
Failed requests:        0
Write errors:           0
Total transferred:      549000 bytes
Total POSTed:           738000
HTML transferred:       54000 bytes
Requests per second:    96.28 [#/sec] (mean)
Time per request:       519.304 [ms] (mean)
Time per request:       10.386 [ms] (mean, across all concurrent requests)
Transfer rate:          17.21 [Kbytes/sec] received
                        23.13 kb/s sent
                        40.34 kb/s total

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        4  188 121.3    253     406
Processing:    26  327  72.9    299     457
Waiting:       25  327  72.9    298     456
Total:        109  516  72.2    523     733

Percentage of the requests served within a certain time (ms)
  50%    523
  66%    552
  75%    568
  80%    578
  90%    600
  95%    623
  98%    655
  99%    680
 100%    733 (longest request)



7 Reference

趋势:


参考:


基础:




部署:






















个人工具
名字空间

变换
操作
导航
工具箱