# 樂活 Firmware 開發規格說明 與 電路板 相關要求
#### Release Ver. 1.1.1
###### Release note :
* 補充Curl
* 補充 Mqtt get cmd .
* 補充 Mqtt ~~update cmd 目前不需要實作, 但需記錄~~
## Doucument Version 說明
Version number : {A.B.C}
A: 重大改變
B: 雙方共識
C: 小幅改變
## Document History
| Date | Release note. | Version |
| ---------- | --------------------------- | ------- |
| 2020/02/04 | Init Release | 0.01 |
| 2020/02/06 | 增加Release History | 0.0.2 |
| | 增加 Mqtt 完整 說明 | |
| | 增加 主板 考量條件 | |
| 2/12 | 增加流程圖 | 1.0.0 |
| | 增加資料時間限制 | |
| | 增加Device I/O 需求list | |
| 2/13 | 修正文件中掉圖 | 1.1.0 |
| | 增加主板選擇最低要求 | |
| | 經過全部會議共識 | |
| | 增加 Doucument Version 說明 | |
| | | |
| | | |
| | | |
## 開發主板考量條件:
#### 主板必要規格:
* Wifi 2.4G/802.11n .
* Bluetooth 4.1
* RAM 大於 256M . TBD
* Storage : 大於 ( Embedded linux system + 程式 + 256M bytes) TBD
* 必須是 Embedded linux , 可以 ssh 連線 console. TBD
* 主板的選擇 有考慮到量產生產 相關考量 (交貨時間,價格).
#### 建議方向:
1. 考慮Raspberry pi zero w . 但價格與交期要確定.
2. 希望可以 相容 Raspberry pi 系統
### 開發與主板最低要求
1. 滿足必要的通訊定義 (Bluetooth/MQTTs)
2. 滿足必要的功能定義 (control/info responsd)
3. 滿足必要的反應時間限定
4. Storage: 32K
## Connection
有3部分 ,
* cloud server--> Device : sever 下指令action 給 device . 使用 Mqtts
* device --> cloud server : 回報 sensor 資訊 到 Server . 使用 Mqtts
* Device <--> mobile App : 做裝置與手機配對用. 使用Bluetooth 4.1
## Device I/O 需求list
- 按鈕x1:有支援長壓短壓辨識,作為電源開關與進入配對模式用
- LEDx1 : RGB 256色
- 需取得資訊:
- - 溫濕度
- PM2.5 : 單位體積內空氣中不同粒徑的懸浮顆粒物個數
- 濾網的門定位:確認濾網的門確定是否關閉定位.(ex:微動開關),當門打開時馬達需停止作動
- PIR 紅外線 : 確認前方有無人
- VOC 感測器
- 風壓偵測x2:判斷出風速度推斷濾材使用率 ,兩邊濾網進風所以兩個
- 機器過熱感測:預防過熱,馬達或板子有可能過熱的一切.
- 馬達轉速:回報馬達轉速
## 資料與規範
* 手機與裝置藍芽資料
```
{
SSID:"String"
Password:"String"
PSK:"String"
}
```
* device 回報 Sensor 資料
```
Event example:
{
"ambiance":{
"infrared":"1",
"temp":16.0,
"hum":60.0,
"pm":"0.5",
"hepa":"1",
"voc":"0.5"
},
"status":{
"productId":"2S45N5X8J1",
"deviceName":"000001",
"motor":{
RPM:"string"
tempture:"String"
}
"filter":{
"left":"left",
"right":"right"
},
"createdAt":"0001-01-01T00:00:00Z"
}
}
```
* Server To device data
```
"desired": {
"airflow": 76,
"auto": false,
"light": true,
"on": true,
"safetyLock": true,
"speaker": false
}
```
## 資料取得時間限制
* Device 計算 Mqtts username password , sha256 時間不得超過 1秒
* 當雲端控制馬達指令送達device 後 開始計時到馬達相對運作, 時間不得超過1秒
* Device 在取得WIFI SSID/密碼後 建立連線WIFI 時間 不超過 10 秒
* Device 成功連線 wifi 後, 確認 Internet 是否存在,不超過 5秒.
## 生產時相關資訊
### 需要燒錄的資料
* ProductID : Batch ID 一批一批會不同.
* Device Name : Device ID 裝置識別碼.目前是 000000 六個數字 . 生產時 依序遞增
* ProductID + DeviceID 是unique 唯一值.
###其他:開發時需考慮到生產工具.
## 整體流程圖

## 雲端溝通 與 Protocol
### 溝通架構
Term :
* Cloud Server : 雲端 Server 目前是 騰訊Server
* Device : 樂活空氣清淨機
* Mobile App : 樂活App
Cloud server <---------MQTT------>Device
Device <------------Bluetooth-------> Mobile App
Mobile <-----------Https--------------> Cloud Server
```mermaid
graph LR
S[Cloud Server] ==> P[MQTT] ==> D[Device]
D ==> P ==> S
```
```mermaid
graph LR
D[Device] ==> B[Bluetooth] ==> A[MobileApp]
A ==> B ==> D
```
```mermaid
graph LR
A[MobileApp]==>H[HTTPS]==>S[CloudServer]
```
data type: JSON string
#### 一組MQTT可用資訊:
一組資訊如下 並在後面說明 各個資訊如何取得:
```
設備密鑰PSK
KSqRcN72G+kDSKlQUewn6g==
client id
X5TVRIJ59A000002
mqtt username
X5TVRIJ59A000002;12010126;X23IM;1614971831
mqtt password a33500700acb52097dcc52287bf070c00f7f05b4f99ba93e2d6cc73328696721;hmacsha256
```
#### MQTT 資訊說明
| 名詞 | 說明 | 取得方式 |
| ------------- | ---------------------------------------------------------- | ------------------------------- |
| 設備密鑰PSK | 用於計算Mqtt password用 | 與手機配對時.透過bluetooth 取得 |
| client id | \${productid}${deviceName} | 製造時已儲存在Device 中 |
| mqtt username | \${productid}${devicename};${sdkappid};${connid};${expiry} | 利用規則產出 |
| MQTT password | ${token};hmac簽名方法 | 利用psk 計算取得 |
##### 設備密鑰PSK
在手機與Device 配對的時候取得. 透過Bluetooth
##### Client ID
```
${productid}${deviceName}
```
在生產製造時已存放在主板上. 是唯一值.Unique ID
* productid : 為公司產品類別的區分,
```
例如:
第一代產品
productID : "第一代"
第二代產品:
productID : "第二代"
```
* devicename: 為裝置本身流水號,
ClientID 生產工廠製造時 放入.因此外包商在設計時 要包含 到 與制具銜接的方法.
##### MQTT Username /Password 說明
```
client id :
${productid}${deviceName}
username字段的格式為:
${productid}${devicename};${sdkappid};${connid};${expiry}
注意:${}表示變量,並非特定的拼接符號。
其中各字段含義如下:
productid:產品 ID。
devicename: 設備名稱。
sdkappid:固定填12010126。
connid :一個隨機字符串。
過期時間 :表示簽名的有效期, 從1970年1月1日00:00:00 UTC 時間至今秒數的 UTF8 字符串。
```
用 base64 對設備私鑰進行解碼得到原始密鑰 raw_key。
用第3步生成的 raw_key,通過 HMAC-SHA1 或者 HMAC-SHA256 算法對 username 生成一串摘要,簡稱 token。
password 字段格式為:
```
${token};hmac簽名方法
可選的值有 hmacsha256 和 hmacsha1。
```
下面提供 程式碼 python 範例 ,如何計算出 username./password .
```python
import base64
import hashlib
import hmac
import random
import string
import time
import sys
# 生成指定長度的隨機字符串
def RandomConnid(length):
return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(length))
# 生成接入物聯雲需要的各參數
def IotHmac(productID, devicename, devicePsk):
# 1. 生成connid為一個隨機字符串,方便後台定位問題
connid = RandomConnid(5)
# 2. 生成過期時間,表示簽名的過期時間,從紀元1970年1月1日 00:00:00 UTC 時間至今秒數的 UTF8 字符串
expiry = int(time.time()) + 60 * 60
# 3. 生成MQTT的clientid部分, 格式為${productid}${devicename}
clientid = "{}{}".format(productID, devicename)
# 4. 生成mqtt的username部分, 格式為${clientid};${sdkappid};${connid};${expiry}
username = "{};12010126;{};{}".format(clientid, connid, expiry)
# 5. 對username進行簽名,生成token
token = hmac.new(devicePsk.decode("base64"), username, digestmod=hashlib.sha256).hexdigest()
password = "{};{}".format(token, "hmacsha256")
return {
"clientid" : clientid,
"username" : username,
"password" : password
}
if __name__ == '__main__':
print IotHmac(sys.argv[1], sys.argv[2], sys.argv[3])
```
```shell
python Hmac.py "YOUR_PRODUCTID" "YOUR_DEVICENAME" "YOUR_PSK"
```

### 資料格式
資料格式 在裝置接收與傳送 都是以 JSON type 傳送,
請實際操作所提供的 postman profile.操作. 後面會列出兩個範例 . 一個 是 對風量做調整, 一個是 sensor 值回報.
傳送Sensor 值的Json格式 如下
```
{
"ambiance":{
"infrared":"1",
"temp":18.0,
"hum":20.0,
"pm":"0.5",
"hepa":"1",
"voc":"0.5"
},
"status":{
"productId":"2S45N5X8J1",
"deviceName":"000001",
"motor":{
"tempture": 30.0,
"rpm": 3000
},
"filter":{
"left":"left",
"right":"right"
}
}
}
```
### 範例
展示兩個範例,分別是 控制風量 與 回報Sensor資訊 , 裝置端 使用 MQTT client 替代.
所以有列出mqtt client 的設定內容.
也提供 postman 檔案, 供Import 測試 , postman 環境變數 需額外手動新增, 資訊請參考附圖.
#### Example :APP 對空氣機調整風量
Topic: \$shadow/operation/${productId}/${deviceName}
```
$shadow/operation/result/X5TVRIJ59A/000002
```


#### Example Sensor 回報:
topic name : {productId}/{deviceName}/event/m001
X5TVRIJ59A/000002/event/m001
Publish :
```json
{
"ambiance":{
"infrared":"1",
"temp":18.0,
"hum":20.0,
"pm":"0.5",
"hepa":"1",
"voc":"0.5"
},
"status":{
"productId":"2S45N5X8J1",
"deviceName":"000001",
"motor":{
},
"filter":{
"left":"left",
"right":"right"
}
}
}
```

### 驗證回報結果

##other :
### postman 說明:
import postman profile , json file, posman 環境變數必須另外手動增加. 請參考
host 是 Roehl.com.cn .
postman Env : https: