使用Android Things開發(fā)簡單的智(diǎo)能(sī)臺燈

原文鏈接

前幾日和朋友說起小米的智能電飯煲宏胯,能在回家前把粥煮好,簡單的理解就是定時接通電源或遠程接通電源開始煮粥本姥,于是本人就想的寫一個遠程控制電源的臺燈肩袍,來一個初步實現(xiàn)。先來上一個圖婚惫。


MQTT

分為軟件和硬件兩個部分來記錄氛赐。

軟件

控制端和被控制端都是用的Android來開發(fā)的魂爪。兩個終端使用MQTT協(xié)議進行關聯(lián)的。因為關于MQTT的內(nèi)容太多鹰祸,這個就不贅述了甫窟。分享一個不錯的鏈接MQTT

效果圖

手機控制端

MainActivity.class
用一個Button發(fā)送指令,EventBus通知MQTTService發(fā)出開關的指令

 btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.e("info", "content  " + editText.getText().toString().trim());
                if (key) {               EventBus.getDefault().post(OFF);
                    key = false;
                } else {        EventBus.getDefault().post(ON);
                    key = true;
                }
            }
        });

MQTTService.class

public class MQTTService extends Service {
    private ServerMQTT serverMQTT;
    @Override
    public void onCreate() {
        super.onCreate();
        EventBus.getDefault().register(this);
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        try {
            initMqtt();
            if (serverMQTT != null) {
                serverMQTT.connect();
            }
        } catch (MqttException e) {
            e.printStackTrace();
        }

        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void getData(Integer s) {
        try {

            serverMQTT.mqttMessage.setPayload(String.valueOf(s).getBytes());
            serverMQTT.publish(serverMQTT.topic, serverMQTT.mqttMessage);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }

    private void initMqtt() throws MqttException {
        serverMQTT = new ServerMQTT();
        serverMQTT.mqttMessage = new MqttMessage();
        //保證消息能到達一次 QoS 0(At most once)“至多一次”  QoS 1(At least once)“至少一次” QoS 2(Exactly once)“只有一次”
        serverMQTT.mqttMessage.setQos(1);
        serverMQTT.mqttMessage.setRetained(false);
        serverMQTT.mqttMessage.setPayload("hello,topic11".getBytes());
        serverMQTT.publish(serverMQTT.topic, serverMQTT.mqttMessage);
        Log.e("info", serverMQTT.mqttMessage.isRetained() + "------ratained狀態(tài)");
    }
}

ServerMQTT.class

public class ServerMQTT {
    //MQTT服務端的地址蛙婴,使用tcp的協(xié)議
    protected static final String HOST = "";
    //定義一個主題粗井,關于主題請看上文推薦的鏈接
    protected static final String TOPIC = "";
    //定義MQTT的ID,這個將在MQTT的服務器上顯示
    protected static final String CLIENTID = "";
    private MqttClient mqttClient;
    protected MqttTopic topic;
    protected String userName = "";
    protected String password = "";
    protected MqttMessage mqttMessage;

    public ServerMQTT() throws MqttException {
        // MemoryPersistence設置clientid的保存形式街图,默認為以內(nèi)存保存
        mqttClient = new MqttClient(HOST, CLIENTID, new MemoryPersistence());
        connect();
    }

    /**
     * 連接MQTT服務器
     */
    public void connect() {
        MqttConnectOptions options = new MqttConnectOptions();
        options.setCleanSession(false);
        options.setUserName(userName);
        options.setPassword(password.toCharArray());
        //設置超時時間
        options.setConnectionTimeout(10);
        //設置會話心跳時間
        options.setKeepAliveInterval(20);
        try {
            mqttClient.setCallback(new PushCallback());
            mqttClient.connect(options);
            topic = mqttClient.getTopic(TOPIC);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    public void publish(MqttTopic topic, MqttMessage message) throws MqttException {
        MqttDeliveryToken token = topic.publish(message);
        token.waitForCompletion();
        Log.e("message is published completely! " + token.isComplete());
    }


}

樹莓派端

MainActivity.class

public class MainActivity extends Activity {
    private static final String TAG = MainActivity.class.getSimpleName();
    TextView tvMsg;
    //    private Gpio gpioButton;
    private Gpio gpioLED;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getDefault().register(this);
        setContentView(R.layout.activity_main);
        tvMsg = findViewById(R.id.tv_msg);
        //提前啟動Service浇衬,因為下一個方法要使用EventBus給ClientMQTTService發(fā)送信息
        startService(new Intent(this, ClientMQTTService.class));
        ledController();

    }

    private void ledController() {
        PeripheralManager manager = PeripheralManager.getInstance();
        try {
            gpioLED = manager.openGpio("BCM4");
            gpioLED.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
            //將LED的狀態(tài)(亮,滅)發(fā)送給MQTT服務器
            ClientMQTTServiceEventBean eventBean = new ClientMQTTServiceEventBean();
            eventBean.setWhat(0x100);
            Bundle data = new Bundle();
            data.putBoolean("isLight", gpioLED.getValue());
            eventBean.setData(data);
            EventBus.getDefault().post(eventBean);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void setLedValue(boolean value) {
        try {
            gpioLED.setValue(value);
        } catch (IOException e) {
            Log.e(TAG, "Error updating GPIO value", e);
        }
    }

    private boolean getLedValue() {
        try {
            return gpioLED.getValue();
        } catch (IOException e) {
            Log.e(TAG, "Error updating GPIO value", e);
        }
        return false;
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void getData(String s) {
        if (!TextUtils.isEmpty(s) && s.length() == 1) {
            int i = Integer.valueOf(s);
            if (i == 0) {
                setLedValue(false);
            } else if (i == 1) {
                setLedValue(true);
            }
        }
    }

    @Override
    protected void onDestroy() {
        EventBus.getDefault().unregister(this);
        //銷毀LED的引用
        if (gpioLED != null) {
            try {
                gpioLED.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                gpioLED = null;
            }
        }
        super.onDestroy();
    }

ClientMQTTService.class

public class ClientMQTTService extends Service {
    public static final String HOST = "";
    public static final String TOPIC = "";
    public static final String TOPIC1 ="";
    private static final String clientid = "";
    private MqttClient client;
    private MqttConnectOptions options;
    private String userName = "";
    private String passWord = "";
    @Override
    public void onCreate() {
        super.onCreate();
        EventBus.getDefault().register(this);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        start();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    private void start() {
        try {
            // host為主機名餐济,clientid即連接MQTT的客戶端ID耘擂,一般以唯一標識符表示,MemoryPersistence設置clientid的保存形式絮姆,默認為以內(nèi)存保存
            client = new MqttClient(HOST, clientid, new MemoryPersistence());
            // MQTT的連接設置
            options = new MqttConnectOptions();
            // 設置是否清空session,這里如果設置為false表示服務器會保留客戶端的連接記錄醉冤,這里設置為true表示每次連接到服務器都以新的身份連接
            options.setCleanSession(true);
            // 設置連接的用戶名
            options.setUserName(userName);
            // 設置連接的密碼
            options.setPassword(passWord.toCharArray());
            // 設置超時時間 單位為秒
            options.setConnectionTimeout(10);
            // 設置會話心跳時間 單位為秒 服務器會每隔1.5*20秒的時間向客戶端發(fā)送個消息判斷客戶端是否在線,但這個方法并沒有重連的機制
            options.setKeepAliveInterval(20);
            // 設置回調(diào)
            client.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable throwable) {
                }

                @Override
                public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
                    EventBus.getDefault().post(new String(mqttMessage.getPayload()));
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {

                }
            });
            MqttTopic topic = client.getTopic(TOPIC);
            //setWill方法篙悯,如果項目中需要知道客戶端是否掉線可以調(diào)用該方法蚁阳。設置最終端口的通知消息
            options.setWill(topic, "close".getBytes(), 2, true);
            client.connect(options);
            //訂閱消息 qoS 0(At most once)“至多一次”  QqoS 1(At least once)“至少一次” QqoS 2(Exactly once)“只有一次”
            int[] Qos = {1};
            String[] topic1 = {TOPIC, TOPIC1};
            client.subscribe(topic1, Qos);


        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {

        EventBus.getDefault().unregister(this);
        if (client != null) {
            if (client.isConnected()) {
                try {
                    client.disconnect();
                } catch (MqttException e) {
                    e.printStackTrace();
                } finally {
                    client = null;
                    options = null;
                }
            }
        }
        super.onDestroy();
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void getData(ClientMQTTServiceEventBean bean) {
        switch (bean.getWhat()) {
            case 0x100:
                //獲取燈目前的狀態(tài)
                boolean isLight = bean.getData().getBoolean("isLight");
                MqttMessage mqttMsg = new MqttMessage();

                try {
                    if (isLight) {
                        mqttMsg.setPayload(String.valueOf(1).getBytes());
                        client.publish(TOPIC, mqttMsg);
                    } else {
                        mqttMsg.setPayload(String.valueOf(0).getBytes());
                        client.publish(TOPIC, mqttMsg);
                    }
                } catch (MqttException e) {
                    e.printStackTrace();

                }
                break;
        }

    }
}

硬件

使用的是樹莓派3,刷的是Android Things鸽照。關于Raspberry怎么刷Android Things網(wǎng)上有很多教程螺捐,就略過了。硬件嘛矮燎,主要是繼電器的接線定血。整理自己在接線中遇到的問題。按照輸入到輸出的順序記錄诞外。

1. 繼電器澜沟。

繼電器

1.1 輸入電源

不要使用樹莓派提供的電壓。如果連接Raspberry的電源只有一個還可以峡谊,如果太多倔喂,負載太大,容易把Raspberry燒了靖苇,畢竟一個Raspberry也有500多,能省則省班缰。

我買的繼電器要求輸入電壓是5V的贤壁,我找了半天,發(fā)現(xiàn)手機的充電器提供的就是5V的電壓埠忘,于是找了一個USB的數(shù)據(jù)線脾拆,將連接手機端的接口拆開馒索,發(fā)現(xiàn)有4條線(紅白綠黑)。紅色和黑色是電線名船,白綠是數(shù)據(jù)線绰上。先百度然后用萬能表測一下就知道了。紅色是正極渠驼,黑色是負極蜈块。紅色接DC+,黑色接DC-迷扇。IN的接觸點連接Raspberry百揭。當IN接入高電平的時候,會聽見繼電器有“咔”的一聲蜓席,同時繼電器模塊上的小燈也會亮起器一。這就是初中物理的電磁鐵吸合的聲音。如果你和我一樣厨内,以為這樣就可以咔的一聲的話祈秕,就錯了!3浮请毛!還需要將 DC- 與Raspberry的GND連接起來

1.2 輸出電源

好了丑掺,繼電器的輸入完了获印,現(xiàn)在開始說繼電器的輸出。
Emmmmmmm街州,不知道怎么說兼丰,來個很傻很直白的圖。然后插座常開接一個臺燈就OK了唆缴。


繼電器接線
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鳍征,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子面徽,更是在濱河造成了極大的恐慌艳丛,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趟紊,死亡現(xiàn)場離奇詭異氮双,居然都是意外死亡,警方通過查閱死者的電腦和手機霎匈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門戴差,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人铛嘱,你說我怎么就攤上這事暖释∠В” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵球匕,是天一觀的道長纹磺。 經(jīng)常有香客問我,道長亮曹,這世上最難降的妖魔是什么橄杨? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮乾忱,結果婚禮上讥珍,老公的妹妹穿的比我還像新娘。我一直安慰自己窄瘟,他們只是感情好衷佃,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蹄葱,像睡著了一般氏义。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上图云,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天惯悠,我揣著相機與錄音,去河邊找鬼竣况。 笑死克婶,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的丹泉。 我是一名探鬼主播情萤,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼摹恨!你這毒婦竟也來了筋岛?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤晒哄,失蹤者是張志新(化名)和其女友劉穎睁宰,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寝凌,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡柒傻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了较木。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诅愚。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出违孝,到底是詐尸還是另有隱情,我是刑警寧澤泳赋,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布雌桑,位于F島的核電站,受9級特大地震影響祖今,放射性物質(zhì)發(fā)生泄漏校坑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一千诬、第九天 我趴在偏房一處隱蔽的房頂上張望歪沃。 院中可真熱鬧踊东,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽隔心。三九已至掠剑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盘榨,已是汗流浹背喻粹。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留草巡,地道東北人守呜。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像山憨,于是被迫代替她去往敵國和親查乒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 選擇題部分 1.(),只有在發(fā)生短路事故時或者在負荷電流較大時,變流器中才會有足夠的二次電流作為繼電保護跳閘之用萍歉。...
    skystarwuwei閱讀 12,836評論 0 7
  • 先介紹情況: 1總電源5V侣颂,由一個AC-DC電源模塊供電,單片機電源3.3V枪孩,由一個LDO供電憔晒;2單片機IO直接驅(qū)...
    阿城繼閱讀 306評論 0 0
  • 今天我讀了瘋狂的土豆系列里的《小雞,別怕》蔑舞,第二章屎殼郎小姐的嫁妝拒担,講的是:小土豆一邊胡思亂想,一邊低頭回...
    丁子涵閱讀 237評論 0 0
  • 今天我休息本來想可以在家好好補補覺攻询,中午放學的時候班主任打電話來說孩子在學写雍常磕著了,其實一聽到兒子受傷了钧栖,先是心疼...
    瑞寶麻麻閱讀 395評論 0 0
  • 8月14日 星期日 倒吊人 做點不一樣的事情低零,突破舊有模式婆翔,嘗試新的可能性,探索新發(fā)現(xiàn) 讀牌1:不管是自主想被吊起...
    回老家養(yǎng)貓閱讀 427評論 0 0