Cloud Of Smart Home
(→Member) |
(→具体产品) |
||
(未显示1个用户的134个中间版本) | |||
第3行: | 第3行: | ||
专为智能家居而生的物联云 | 专为智能家居而生的物联云 | ||
− | + | 服务于各类爱好智能家居的中小厂商、宅男宅女,他们爱动手、爱思考、对隐私和家居安全敏感 | |
+ | |||
+ | |||
+ | ;家居环境: | ||
+ | |||
+ | * Living Room | ||
+ | * Basement | ||
+ | * Bathroom | ||
+ | * Bedroom | ||
+ | * Den | ||
+ | * Dining Room | ||
+ | * Downstairs | ||
+ | * Entryway | ||
+ | * Family Room | ||
+ | * Hallway | ||
+ | * Kids Room | ||
+ | * Kitchen | ||
+ | * Master Bedroom | ||
+ | * Office | ||
+ | * Upstairs | ||
+ | |||
+ | <br><br> | ||
=== HOME === | === HOME === | ||
+ | 远期规划 | ||
+ | |||
+ | <s> | ||
一个 Home 下可有多个设备 (device) 和多个家庭成员 (member) | 一个 Home 下可有多个设备 (device) 和多个家庭成员 (member) | ||
第17行: | 第41行: | ||
<source lang=bash> | <source lang=bash> | ||
− | name, type, up_nodes, down_nodes, state, uuid | + | name, type, up_nodes, down_nodes, state, uuid, meta:{} |
+ | |||
+ | meta: { | ||
+ | mac:"aa:bb:cc:dd", | ||
+ | ip:"123.11.1.1", | ||
+ | activate:1, | ||
+ | } | ||
</source> | </source> | ||
+ | |||
+ | </s> | ||
<br><br> | <br><br> | ||
第26行: | 第58行: | ||
设备是传感器 (sensor) 和 控制器 (controller) 统称。客厅大灯是一个设备,当然他只是一个控制器,因其主要响应用户的控制行为。客厅的温湿度检测也是一个设备,实际他是一个传感器,因其主要负责收集数据。贴于门窗上的门磁也是一个传感器设备。 | 设备是传感器 (sensor) 和 控制器 (controller) 统称。客厅大灯是一个设备,当然他只是一个控制器,因其主要响应用户的控制行为。客厅的温湿度检测也是一个设备,实际他是一个传感器,因其主要负责收集数据。贴于门窗上的门磁也是一个传感器设备。 | ||
− | |||
+ | 传感器的值、控制器的状态都写在 state 域里,方便设备 check 以实现远程控制。每次push 的数据或状态则写在 datapoints 表里,带时间戳,方便呈现和日志检查 | ||
− | + | 同时带有多个感应和多个控制的设备,也用一行描述,当前状态用一个 JSON 结构,写在 state 域里 | |
− | + | ||
− | 同时带有多个感应和多个控制的设备,也用一行描述,当前状态用一个 JSON 结构,写在 | + | |
第38行: | 第68行: | ||
<source lang=bash> | <source lang=bash> | ||
− | name, type, up_nodes, down_nodes, state, uuid | + | 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 | ||
+ | } | ||
</source> | </source> | ||
第45行: | 第98行: | ||
=== Member === | === Member === | ||
+ | 远期规划 | ||
+ | |||
+ | <s> | ||
对于一个家庭成员追踪设备,则各人智能手机为感知端(用户可选择是否定时上传 GPS/GSM 数据),加一些虚拟控制器,比如 weibo 推发器 | 对于一个家庭成员追踪设备,则各人智能手机为感知端(用户可选择是否定时上传 GPS/GSM 数据),加一些虚拟控制器,比如 weibo 推发器 | ||
第57行: | 第113行: | ||
<source lang=bash> | <source lang=bash> | ||
− | name, type, up_nodes, down_nodes, state, {email, password, weixin, weibo, mobile, imsi | + | name, type, up_nodes, down_nodes, state, meta:{email, password, weixin, weibo, mobile, imsi}, uuid, pub_key |
state:{ | state:{ | ||
− | coords:{lat:123, lng:234}, | + | coords:{lat:123, lng:234}, cell:{mcc: 460, mnc: 0, lac: 123, cid: 456} |
− | + | ||
} | } | ||
</source> | </source> | ||
+ | </s> | ||
<br><br> | <br><br> | ||
第69行: | 第125行: | ||
=== Trigger === | === Trigger === | ||
− | 每次 push 一个 | + | 每次 push 一个 state,云端检查一下相关的触发器,条件满足则执行相应的动作 |
注意:作为一个安全的云的必要设计,改控制器状态由家庭设备或家庭成员的手机完成,加密过后的数据,云端无法解读,因为加密在家庭设备端用私钥完成,云端无法解密,也就无法更改控制器状态 | 注意:作为一个安全的云的必要设计,改控制器状态由家庭设备或家庭成员的手机完成,加密过后的数据,云端无法解读,因为加密在家庭设备端用私钥完成,云端无法解密,也就无法更改控制器状态 | ||
第77行: | 第133行: | ||
<source lang=cpp> | <source lang=cpp> | ||
− | + | 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}, | ||
+ | } | ||
+ | </source> | ||
+ | <s> | ||
+ | <source lang=cpp> | ||
+ | trigger: { | ||
+ | "fun":{cond:"x>1 && y>3", action:[{weixin:{}},{controller:""}]} | ||
+ | } | ||
</source> | </source> | ||
− | + | </s> | |
− | + | ||
− | < | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
第136行: | 第179行: | ||
=== Activate === | === Activate === | ||
+ | |||
+ | 激活就是告诉云端:生产的设备已经联网并能正常工作了 | ||
+ | |||
;;CamGo 的设计:(X1) | ;;CamGo 的设计:(X1) | ||
+ | |||
+ | ;;方案一: | ||
每个设备都有一个唯一的串号 SN,写在二维码里 | 每个设备都有一个唯一的串号 SN,写在二维码里 | ||
扫描二维码,APP会获取 SN,APP自动生成一个密钥对,用私钥将 时间戳和SN 加密后,作为调用 Activate API 的一个参数,另一个参数是生成的公钥 x-key | 扫描二维码,APP会获取 SN,APP自动生成一个密钥对,用私钥将 时间戳和SN 加密后,作为调用 Activate API 的一个参数,另一个参数是生成的公钥 x-key | ||
+ | |||
+ | |||
+ | ;;方案二 (实际使用方案): | ||
+ | |||
+ | 设备的串号 SN、KEY 和 MAC 写在 eeprom 里 | ||
+ | |||
+ | update state 时,用 SN + KEY 生成动态 token,云端检查 token 验证合法身份 | ||
+ | |||
+ | 用户关注公众号绑定看门狗后(扫描二维码或手工关注后绑定),视为激活,此过程可从 weixin agent 调用 Activate 接口 | ||
+ | |||
+ | |||
+ | <source lang=bash> | ||
+ | {"weixin":"userid"} | ||
+ | |||
+ | 云端收到后,首先解析设备node_row 的meta->activated域,为1视为激活,再解析 trigger 域, | ||
+ | 有 weixin->root 则视为激活过,此时添加的 weixin 用户,置于 weixin->user 列表里 | ||
+ | </source> | ||
第147行: | 第212行: | ||
;;mini 的设计是这样:(M1) | ;;mini 的设计是这样:(M1) | ||
+ | |||
+ | ;;方案一: | ||
启动 APP,APP自动断开原WiFi的连接,搜索 miniCamGo 的AP,自动连接(内置密码),最好能做到将用户手机里存的AP直接配置给mini | 启动 APP,APP自动断开原WiFi的连接,搜索 miniCamGo 的AP,自动连接(内置密码),最好能做到将用户手机里存的AP直接配置给mini | ||
第153行: | 第220行: | ||
APP 断开和 mini 的连接,用私钥将时间戳和SN 加密后,作为调用 Activate API 的一个参数 Token,另一个参数是生成的公钥 x-key | APP 断开和 mini 的连接,用私钥将时间戳和SN 加密后,作为调用 Activate API 的一个参数 Token,另一个参数是生成的公钥 x-key | ||
+ | |||
+ | |||
+ | ;;方案二: | ||
+ | |||
+ | 用户启动 APP,APP自动断开原WiFi的连接,搜索 miniCamGo 的AP,自动连接(内置密码,可以设计为无密码),将 AP 的 SSID 和密码配给 miniCamgo | ||
+ | |||
+ | miniCamgo 能通过 wifi 第一次访问激活接口,就视为激活 | ||
+ | |||
+ | <source lang=bash> | ||
+ | {"activate":1} | ||
+ | </source> | ||
+ | |||
--- | --- | ||
第162行: | 第241行: | ||
− | + | 激活时以路由的MAC地址为关键字,创建HOME且与SN关联;以用户手机的imsi为关键字,创建USER且与SN关联 | |
+ | |||
+ | |||
+ | <pre> | ||
+ | /v2/node/activate | ||
+ | </pre> | ||
+ | |||
+ | <source lang=bash> | ||
+ | # 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} | ||
+ | </source> | ||
<br><br> | <br><br> | ||
− | == | + | === Node State === |
− | + | <pre> | |
+ | /v2/node/state | ||
+ | </pre> | ||
− | + | ||
+ | Input: | ||
+ | |||
+ | <pre> | ||
+ | {"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}} | ||
+ | </pre> | ||
+ | |||
+ | <source lang=bash> | ||
+ | # 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} | ||
+ | </source> | ||
<br><br> | <br><br> | ||
− | == | + | === Node Beacon === |
− | + | /v2/node/beacon | |
+ | |||
+ | <source lang=bash> | ||
+ | |||
+ | </source> | ||
<br><br> | <br><br> | ||
+ | |||
+ | === Node Trigger === | ||
+ | |||
+ | /v2/node/trigger | ||
+ | |||
+ | <source lang=bash> | ||
+ | |||
+ | 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}} | ||
+ | </source> | ||
+ | |||
<br><br> | <br><br> | ||
+ | |||
+ | === Node CMD === | ||
+ | |||
+ | /v2/node/cmd | ||
+ | |||
+ | <source lang=bash> | ||
+ | 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 } } } | ||
+ | </source> | ||
+ | |||
+ | |||
+ | POST: | ||
+ | |||
+ | <source lang=bash> | ||
+ | |||
+ | { "cmd":"关庭院灯", "action":{"state":{"ch1":0}} } | ||
+ | { "nodid":"XXXXXXXXXX", "cmd":"关庭院灯", "action":{"state":{"ch1":0}} } | ||
+ | </source> | ||
+ | |||
+ | 写入 meta 域,仅仅是个结构描述,不改变设备云端状态。用户在微信文本输入或者语音输入对应的命令字时,命令关键字匹配,进而取得 "cmd":{} 结构中对应的元数据,解析后,写入相应的位置 state/meta->ctrl | ||
+ | |||
+ | |||
+ | GET: | ||
+ | |||
+ | 返回整个 { "cmd":{"开庭院灯":{"state":{"value":3} } } } JSON 结构,用户设置时,选择性呈现给用户,这个域默认不可编辑(可开启编辑),可特定生成 | ||
+ | |||
<br><br> | <br><br> | ||
+ | |||
+ | === ROM Update === | ||
+ | |||
+ | <pre> | ||
+ | /v2/node/rom/version | ||
+ | /v2/node/rom/update?version=xxx | ||
+ | </pre> | ||
+ | |||
<br><br> | <br><br> | ||
+ | |||
+ | === Manufacture === | ||
+ | |||
+ | <pre> | ||
+ | /v2/nodes | ||
+ | </pre> | ||
+ | |||
+ | <source lang=bash> | ||
+ | {"type":"device", "state":"{}", "uuid":"", "auth":{"pubkey":"XOIO1234", "algo":"xx", "seed":"12345" }, "meta":"", "trig":"{}"} | ||
+ | </source> | ||
+ | |||
<br><br> | <br><br> | ||
+ | |||
+ | == 具体产品 == | ||
+ | |||
+ | * [[智能插座]] | ||
+ | * [[庭院监控]] - 360度遥控云台,高分贝警报器,50W LED 射灯,WiFi 720p 摄像头,所有这些都在一 MaiKe WiFi 模块控制下 | ||
<br><br> | <br><br> | ||
+ | |||
+ | == 数据结构 == | ||
+ | |||
+ | === Action Sets === | ||
+ | |||
+ | <source lang=cpp> | ||
+ | id, timestamp, action, processed | ||
+ | |||
+ | action: { | ||
+ | msg: 客厅阳台门开了, | ||
+ | weixin: [u1, u2, u3 ...] | ||
+ | } | ||
+ | </source> | ||
+ | |||
<br><br> | <br><br> | ||
+ | |||
+ | === 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 | ||
+ | |||
+ | |||
+ | |||
+ | |||
<br><br> | <br><br> | ||
+ | |||
+ | == 性能测试 == | ||
+ | |||
+ | === http_load === | ||
+ | |||
+ | 官网:http://www.acme.com/software/http_load/ | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ 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 | ||
+ | </source> | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | === ab === | ||
+ | |||
+ | * ab - Apache HTTP server benchmarking tool | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ 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) | ||
+ | </source> | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | == Reference == | ||
+ | |||
+ | ;;趋势: | ||
+ | |||
+ | * RESTful的CoAP协议: http://segmentfault.com/a/1190000002511350 | ||
+ | * CoAP Spec: http://coap.technology/spec.html https://tools.ietf.org/html/rfc7252#section-3 | ||
+ | * 一步步搭建物联网系统: http://ebook.designiot.cn/#restful的coap协议 | ||
+ | * CoAP 已有实现: http://coap.technology/impls.html | ||
+ | * http://covertness.me/2015/07/26/%E7%89%A9%E8%81%94%E7%BD%91%E7%9A%84RESTful%E5%8D%8F%E8%AE%AE%E2%80%94%E2%80%94CoAP/ | ||
+ | * CoAP 协议及开源实现: http://blog.csdn.net/tulun/article/details/8869241 | ||
+ | * CoAP 格式详解: http://network.chinabyte.com/333/13351333.shtml | ||
+ | |||
+ | * 物联网协议Thread http://ju.outofmemory.cn/entry/110572 | ||
+ | |||
+ | |||
+ | ;;参考: | ||
+ | |||
+ | * https://electricimp.com | ||
+ | * https://www.particle.io | ||
+ | * https://www.aylanetworks.com/platform/platform-components | ||
+ | * http://www.sense-iot.com/api-reference/triggers/ | ||
+ | * http://www.blynk.cc/ | ||
+ | |||
+ | |||
+ | ;;基础: | ||
+ | |||
+ | * [[GitHub的Rails/Git架构]] http://www.ha97.com/1074.html | ||
+ | |||
+ | * Comparison of Erlang Web Frameworks: https://github.com/ChicagoBoss/ChicagoBoss/wiki/Comparison-of-Erlang-Web-Frameworks | ||
+ | |||
+ | |||
+ | * Catalyst: https://metacpan.org/release/Catalyst-Manual | ||
+ | |||
+ | * Catalyst quickstart: http://blogs.perl.org/users/j0e/ | ||
+ | * ResetSet: https://metacpan.org/pod/DBIx::Class::ResultSet | ||
+ | |||
+ | |||
+ | * http://www.catalystframework.org/calendar/ | ||
+ | |||
+ | * web 压力测试工具:http://blog.jobbole.com/22294/ | ||
+ | |||
+ | |||
+ | ;;部署: | ||
+ | |||
+ | * http://blogs.perl.org/users/j0e/2013/05/notes-from-a-newbie-16-deploy.html | ||
+ | |||
+ | * http://wiki.catalystframework.org/wiki/adventcalendararticles/2008/02-catalyst_and_nginx.view | ||
+ | |||
+ | * http://blog.sina.com.cn/s/blog_9f7b5fe70101fpra.html | ||
+ | |||
+ | |||
+ | * https://metacpan.org/pod/HTTP#HTTP-1.1-Status-Codes | ||
+ | |||
+ | * https://metacpan.org/pod/Crypt::RSA | ||
+ | |||
+ | * https://metacpan.org/pod/Crypt::Cipher::DES | ||
+ | |||
+ | * https://metacpan.org/pod/Crypt::Mode::CBC | ||
+ | |||
+ | * HTTPS: http://blog.csdn.net/luocn99/article/details/39777707 | ||
+ | |||
+ | * RSA 原理:http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html | ||
+ | |||
+ | * FastCGI、ModPerl、PHP、普通CGI、SSI性能实测对比 http://www.20cn.net/ns/wz/soft/data/20040225014342.htm | ||
+ | |||
+ | * perl + fastcgi + nginx搭建 http://www.ttlsa.com/nginx/perl-fastcgi-nginx/ | ||
+ | |||
<br><br> | <br><br> | ||
<br><br> | <br><br> |
2020年1月8日 (三) 10:12的最后版本
目录 |
[编辑] 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 具体产品
[编辑] 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
- 趋势:
- RESTful的CoAP协议: http://segmentfault.com/a/1190000002511350
- CoAP Spec: http://coap.technology/spec.html https://tools.ietf.org/html/rfc7252#section-3
- 一步步搭建物联网系统: http://ebook.designiot.cn/#restful的coap协议
- CoAP 已有实现: http://coap.technology/impls.html
- http://covertness.me/2015/07/26/%E7%89%A9%E8%81%94%E7%BD%91%E7%9A%84RESTful%E5%8D%8F%E8%AE%AE%E2%80%94%E2%80%94CoAP/
- CoAP 协议及开源实现: http://blog.csdn.net/tulun/article/details/8869241
- CoAP 格式详解: http://network.chinabyte.com/333/13351333.shtml
- 物联网协议Thread http://ju.outofmemory.cn/entry/110572
- 参考:
- https://electricimp.com
- https://www.particle.io
- https://www.aylanetworks.com/platform/platform-components
- http://www.sense-iot.com/api-reference/triggers/
- http://www.blynk.cc/
- 基础:
- Comparison of Erlang Web Frameworks: https://github.com/ChicagoBoss/ChicagoBoss/wiki/Comparison-of-Erlang-Web-Frameworks
- Catalyst quickstart: http://blogs.perl.org/users/j0e/
- ResetSet: https://metacpan.org/pod/DBIx::Class::ResultSet
- web 压力测试工具:http://blog.jobbole.com/22294/
- 部署:
- FastCGI、ModPerl、PHP、普通CGI、SSI性能实测对比 http://www.20cn.net/ns/wz/soft/data/20040225014342.htm
- perl + fastcgi + nginx搭建 http://www.ttlsa.com/nginx/perl-fastcgi-nginx/