本文由
玉剛說寫作平臺
提供寫作贊助原作者:
AndroFarmer
版權宣告:本文版權歸微信公眾號
玉剛說
所有,未經許可,不得以任何形式轉載
Android Tings 是什麼
Android things(後面正文內容簡稱ats)是一個物聯網平臺,他基於Android,並做了相當多的改造以適合在一些低配置的物聯網裝置上執行,同時它又是安卓,因為其保留了絕大部分Android framework的功能。因此藉助ats平臺我們不需要了解嵌入式(準確的說還是需要了解一些的)相關的知識就可以開發出一系列智慧硬體產品。
Android Tings 能做什麼
要說明這個問題,我們不如從反面說明,ats不能做什麼。
先看張ats的框架圖:
從圖上可以看出,ats是在標準安卓的framework層上增加了things support library,同時為了保證嵌入式效能以及根據嵌入式裝置的特點的需要,精簡和修改了部分標準framework層的東西。 那麼具體ats不能做什麼,除了下圖中的這些標準android的特性不支援外,其他都支援(gms除外,因為ats的gms框架是定製的跟標準android不通用): 可以看出ats對標準android framework的支援還是挺多的,這也就保證了app開發者們可以很輕鬆的做ats的開發。
開發Android Tings的硬體條件
由於android studio 並未有提供ats的模擬器,所以我們必須要有一個能刷ats系統的硬體(比如樹莓派)才行,同時為了還需要一些感測器、電阻、電子按鈕、麵包板、led燈等一些列配套外設,因為iot(物聯網)的開發很多時候都是對硬體的操作,有了這些外設才能更好的去實驗一些demo。
下面貼出我購買的硬體全家桶套裝:
樹莓派針腳說明
ats的開發很多時候都是操作硬體,所以我們就有必要去研究,如何去操作外設裝置,一個很重要的方法就是通過外設介面去操作。
看下圖:
何為匯流排
匯流排,匯流排,就是總讓你陷進去
請原諒我不會搞笑還胡說的壞毛病。
樹莓派支援的匯流排型別: GPIO,I2C,I2S,SPI,PWM,UART
關於匯流排我也不是專業的。以我的理解就是為了控制不同的硬體裝置,而對電訊號做不同的處理而劃分的標準。這裡我們先混個臉熟,後面用的最多的是GPIO,也就是以名稱BCM開通的針腳,後面我們會通過名稱去控制這個針腳上的裝置。 關於匯流排詳細的介紹,大家可以參考下這篇文章: https://blog.csdn.net/haima1998/article/details/18729929
如何刷寫ats到樹莓派開發板上
關於這方面的介紹,網上還是挺多的,我搜了一下最不缺的就是這類文章,所以這裡就不做詳細介紹了,簡單介紹下 步驟:
- 進入android things console,建立屬於自己硬體的rom,這是google的雲管理平臺(在這裡可以建立硬體裝置的rom,釋出ota更新等) 地址為: https://partner.android.com/things/console/
- 這裡推薦另一種更簡便的方式:使用官方提供工具的:android-things-setup-utility 下載地址: https://partner.android.com/things/console/#/tools 解壓完了以後如圖:可以根據自己的平臺選擇操作。
如何操作Android Things
由於物聯網設配的特殊性,我們沒有像安卓一樣的觸控式螢幕和按鍵等外設來操作裝置,所以我們需要通過如下兩種方式去連線裝置。
1.通過usb轉ttl裝置直接連線
具體如何操作,可以自行百度2.通過區域網連線(推薦方式) 先讓ats裝置連線到路由器,這裡推薦連線顯示器滑鼠鍵盤視覺化操作連線網路等操作,連線上顯示器如下圖:
常用的adb 命令
通過這些命令我們可以更好的管理和使用ats
- 連線AndroidThings adb connect
- 斷開AndroidThings adb disconnect
- 關機 adb shell reboot -p 4.解除安裝應用 adb shell uninstall 使用adb connect 命令連線到ats裝置後就可以像開發app一樣用android studio去開發部署和除錯了。
Demo展示及硬體搭建-light
這是一個操作LED讓其閃爍的demo, 我們通過這個demo來介紹基本的操作硬體的方法 先看下最終效果:
硬體搭建步驟:
- 通過麵包板串聯一個電阻和一個LED燈並連線到麵包板的正極
- 麵包板的正極連線到樹莓派一個GPIO匯流排埠
- LED另一個針腳通過跳線連線到樹莓派的GROUND針腳上 附上我的連線圖:
更直觀一點的參考如下官方圖片:
這裡需要著重說明是:Ground為地線,用來模擬零電壓線,GPIO匯流排埠可以根據所加的電阻以及LED選擇不同的電壓,我這裡選擇的是電壓3.3v名為BCM2的埠light程式碼分析
public class LightActivity extends Activity {
Handler mHandler;
PeripheralManager mPeripheralManager;
Gpio mLightGpio;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_light);
mHandler = new Handler();
mPeripheralManager = PeripheralManager.getInstance();
try {
mLightGpio = mPeripheralManager.openGpio("BCM2");
mLightGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
mHandler.post(mBlinkRunnable);
} catch (IOException e) {
e.printStackTrace();
}
}
private Runnable mBlinkRunnable = new Runnable() {
@Override
public void run() {
try {
if (mLightGpio == null)
return;
mLightGpio.setValue(!mLightGpio.getValue());
mHandler.postDelayed(mBlinkRunnable, 1000);
} catch (IOException e) {
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
if (mLightGpio != null) {
try {
mLightGpio.close();
mLightGpio = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
複製程式碼
程式碼不多,就全貼上去了,下面我們分析下程式碼。
mPeripheralManager=PeripheralManager.getInstance();
mLightGpio= mPeripheralManager.openGpio("BCM2");
複製程式碼
我們通過PeripheralManager單例後呼叫openGpio方法,傳入的引數為GPIO埠對應的名稱,這樣就拿到這個埠控制物件Gpio的一個例項mLightGpio。
mLightGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH);
複製程式碼
這句話程式碼有兩個作用:1.設定電平方向為輸出方向;2設定初始電平為高電平並立即啟用。 這句程式碼執行後,LED會變為常亮狀態。 我們還可以通過以下三行程式碼實現跟上面一句同樣的效果:
//設定電平方向為輸出方向,設定初始電平為低電平並立即啟用
mLightGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
//設定啟用狀態為高電平
mLightGpio.setActiveType(Gpio.ACTIVE_HIGH)
//進行啟用
mLightGpio.setValue(true);
複製程式碼
在mBlinkRunnable中通過 mLightGpio.setValue(!mLightGpio.getValue()) 來迴圈改變電平的啟用狀態來實現LED的閃爍,至此LED就可以blingbling的閃了。
最後看下ats專案和標準安卓有和區別 主要區別有兩點:
- ats專案許可權不需要使用者動態授權,直接在manifest中聲名即可,如訪問GPIO匯流排埠以及下面需要講到的註冊使用者驅動所需要的許可權
<uses-permission android:name="com.google.android.things.permission.USE_PERIPHERAL_IO"/>
<uses-permission android:name="com.google.android.things.permission.MANAGE_INPUT_DRIVERS" />
複製程式碼
- ats專案部署到硬體後可以設定其意外關閉重啟和開機自啟動,這樣可以保證物聯網裝置的高可用狀態,不至於程式崩潰導致裝置無法使用 具體步驟只需要在入口Activity加入如下intent-filter:
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
複製程式碼
使用者驅動-userdriver
所謂使用者驅動就是ats允許你把相應的硬體的電訊號轉化成系統事件,比如按鈕的點按事件註冊成系統的鍵盤按鍵事件,溫度感應器的電訊號註冊成系統已存在的感應器事件,這樣各個元件都可以很方便的使用標準的framework api去操作硬體了。
舉個栗子
本例展現的內容是把按鈕的點按事件電訊號註冊成鍵盤的key事件,這樣按鈕就變成一個鍵盤了,可以點選和長按。註冊成系統事件後可以在應用程式的各個元件中進行使用了。 演示效果:
硬體安裝圖:
看下程式碼:
package com.androfarmer.button;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.view.KeyEvent;
import com.google.android.things.pio.Gpio;
import com.google.android.things.pio.GpioCallback;
import com.google.android.things.pio.PeripheralManager;
import com.google.android.things.userdriver.UserDriverManager;
import com.google.android.things.userdriver.input.InputDriver;
import com.google.android.things.userdriver.input.InputDriverEvent;
import java.io.IOException;
public class KeyCodeDriverService extends Service {
private InputDriver mDriver;
private Gpio mButtonGpio;
private static final int KEY_CODE = KeyEvent.KEYCODE_A;
@Override
public void onCreate() {
super.onCreate();
//建立輸入驅動,並設定驅動的基本資訊
mDriver = new InputDriver.Builder()
.setName("Button2Keyboard")
.setSupportedKeys(new int[]{KEY_CODE})
.build();
// 通過 UserDriverManager註冊上面建立的驅動
UserDriverManager manager = UserDriverManager.getInstance();
manager.registerInputDriver(mDriver);
PeripheralManager peripheralManager = PeripheralManager.getInstance();
try {
mButtonGpio = peripheralManager.openGpio("BCM21");
//設定電平方向為輸入
mButtonGpio.setDirection(Gpio.DIRECTION_IN);
//設定啟用型別
mButtonGpio.setActiveType(Gpio.ACTIVE_LOW);
//設定監聽事件為:電平中斷變化事件,Gpio.EDGE_BOTH
//意味著電平從低到高中斷以及從高到低中斷都會觸發回撥
mButtonGpio.setEdgeTriggerType(Gpio.EDGE_BOTH);
//設定電平變化的監聽器
mButtonGpio.registerGpioCallback(new GpioCallback() {
@Override
public boolean onGpioEdge(Gpio gpio) {
try {
Log.d("-------------button",gpio.getValue()+"");
boolean pressed=gpio.getValue();
InputDriverEvent event = new InputDriverEvent();
event.setKeyPressed(KEY_CODE, pressed);
mDriver.emit(event);
} catch (IOException e) {
e.printStackTrace();
}
//返回true代表一直監聽,false代表監聽一次
return true;
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
super.onDestroy();
//接觸註冊
UserDriverManager manager = UserDriverManager.getInstance();
manager.unregisterInputDriver(mDriver);
//關閉gpio埠
try {
mButtonGpio.close();
mButtonGpio = null;
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
複製程式碼
程式碼的註釋寫的已經很詳細了,就不過多解釋了。 這裡簡要介紹下步驟
- 通過InputDriver建立驅動基本資訊物件
- 通過UserDriverManager註冊驅動
- PeripheralManager處理具體外設硬體的電訊號
- 通過InputDriver的emit方法將InputDriverEvent事件發射出去,這樣系統各個元件就能相應這個事件了
- 別忘了不再使用時解除註冊和關閉埠
使用者驅動型別
主要分為四類:
- Location 位置驅動
- Input 使用者輸入事件驅動
- Sensor 感測器驅動
- LoWPAN
對使用者驅動的進一步說明
ats的很多場景我們可以像開發app一樣,對於做過android開發的同學們來說這很easy,但是使用者驅動這個概念我們可能第一次聽說。ats的設計是模組化的,一個ats硬體板只會包含基礎的硬體模組如:網路模組,cpu,記憶體等。我們拿到這個執行ats系統的基礎板後,如果要開發成具體的物聯網產品,可能需要接外設感測器去實現具體功能:比如溫度感測器,煙霧報警器等。
市面上感測器門類複雜,如果我們開發時將業務邏輯與硬體感測器的操作雜糅在一起,很顯然這樣的話我們的程式碼很脆弱並且不具備可移植性,換個同類別的其他型號感測器就無法使用了。因此使用者驅動的出現很好的解決了這個問題,不管外設硬體同類別的型號有多少種,我們只需要寫相應的使用者驅動將其註冊成framework已經實現的感測器事件,這樣業務邏輯只需要跟標準的framework api打交道,而不用管具體用了哪一種感測器。
附上一個開源專案,這裡面實現了很多市面上普遍使用的硬體的使用者驅動 https://github.com/androidthings/contrib-drivers 有興趣的同學可以去研究下不同型別的使用者驅動是如何編寫
ps:本文很多內容和案例來自於官網,更多案例請檢視 https://developer.android.com/samples/?technology=iot&language=java