Android Things 開發入門

本文由玉剛說寫做平臺提供寫做贊助java

原做者:AndroFarmerandroid

版權聲明:本文版權歸微信公衆號 玉剛說 全部,未經許可,不得以任何形式轉載git

Android Tings 是什麼

Android things(後面正文內容簡稱ats)是一個物聯網平臺,他基於Android,並作了至關多的改造以適合在一些低配置的物聯網設備上運行,同時它又是安卓,由於其保留了絕大部分Android framework的功能。所以藉助ats平臺咱們不須要了解嵌入式(準確的說仍是須要了解一些的)相關的知識就能夠開發出一系列智能硬件產品。github

Android Tings 能作什麼

要說明這個問題,咱們不如從反面說明,ats不能作什麼。
先看張ats的框架圖:
shell


從圖上能夠看出,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。
下面貼出我購買的硬件全家桶套裝: api

樹莓派針腳說明

ats的開發不少時候都是操做硬件,因此咱們就有必要去研究,如何去操做外設設備,一個很重要的方法就是經過外設接口去操做。 看下圖:
bash

第一張圖畫紅線的地方,按照針腳一對一的順序分別對應下面的這張圖說明。 看到這可能有些暈,這這是什麼鬼,固然電子工程相關專業的應該一看就懂,沒錯這就是總線。

何爲總線

總線,總線,就是總讓你陷進去微信


請原諒我不會搞笑還胡說的壞毛病。

樹莓派支持的總線類型: GPIO,I2C,I2S,SPI,PWM,UART網絡

關於總線我也不是專業的。以個人理解就是爲了控制不一樣的硬件設備,而對電信號作不一樣的處理而劃分的標準。這裏咱們先混個臉熟,後面用的最多的是GPIO,也就是以名稱BCM開通的針腳,後面咱們會經過名稱去控制這個針腳上的設備。 關於總線詳細的介紹,你們能夠參考下這篇文章: https://blog.csdn.net/haima1998/article/details/18729929app

如何刷寫ats到樹莓派開發板上

關於這方面的介紹,網上仍是挺多的,我搜了一下最不缺的就是這類文章,因此這裏就不作詳細介紹了,簡單介紹下 步驟:

  1. 進入android things console,建立屬於本身硬件的rom,這是google的雲管理平臺(在這裏能夠建立硬件設備的rom,發佈ota更新等) 地址爲: https://partner.android.com/things/console/

2. 經過軟件刷寫rom到內存卡上,這裏推薦使用Etcher這個軟件
這個軟件的使用仍是很簡單的,一鍵式的。 3. 刷寫完成後通電,插入顯示器,不出什麼意外就能夠正常開機了 至此刷寫rom的工做就完成了

  1. 這裏推薦另外一種更簡便的方式:使用官方提供工具的:android-things-setup-utility 下載地址: https://partner.android.com/things/console/#/tools 解壓完了之後如圖:
    能夠根據本身的平臺選擇操做。

如何操做Android Things

因爲物聯網設配的特殊性,咱們沒有像安卓同樣的觸摸屏和按鍵等外設來操做設備,因此咱們須要經過以下兩種方式去鏈接設備。

1.經過usb轉ttl設備直接鏈接

具體如何操做,能夠自行百度

2.經過局域網鏈接(推薦方式) 先讓ats設備鏈接到路由器,這裏推薦鏈接顯示器鼠標鍵盤可視化操做鏈接網絡等操做,鏈接上顯示器以下圖:

WechatIMG16.jpeg

經常使用的adb 命令

經過這些命令咱們能夠更好的管理和使用ats

  1. 鏈接AndroidThings adb connect
  2. 斷開AndroidThings adb disconnect
  3. 關機 adb shell reboot -p 4.卸載應用 adb shell uninstall 使用adb connect 命令鏈接到ats設備後就能夠像開發app同樣用android studio去開發部署和調試了。

Demo展現及硬件搭建-light

這是一個操做LED讓其閃爍的demo, 咱們經過這個demo來介紹基本的操做硬件的方法 先看下最終效果:

硬件搭建步驟:

  1. 經過麪包板串聯一個電阻和一個LED燈並鏈接到麪包板的正極
  2. 麪包板的正極鏈接到樹莓派一個GPIO總線端口
  3. 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項目和標準安卓有和區別 主要區別有兩點:

  1. 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" />
複製代碼
  1. 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;
    }
}

複製代碼

代碼的註釋寫的已經很詳細了,就不過多解釋了。 這裏簡要介紹下步驟

  1. 經過InputDriver建立驅動基本信息對象
  2. 經過UserDriverManager註冊驅動
  3. PeripheralManager處理具體外設硬件的電信號
  4. 經過InputDriver的emit方法將InputDriverEvent事件發射出去,這樣系統各個組件就能相應這個事件了
  5. 別忘了再也不使用時解除註冊和關閉端口

用戶驅動類型

主要分爲四類:

  1. Location 位置驅動
  2. Input 用戶輸入事件驅動
  3. Sensor 傳感器驅動
  4. 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

歡迎關注微信公衆號,接收第一手技術乾貨
相關文章
相關標籤/搜索