国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

使用Java來開發(fā)物聯(lián)網(wǎng)應(yīng)用

這篇具有很好參考價值的文章主要介紹了使用Java來開發(fā)物聯(lián)網(wǎng)應(yīng)用。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

這是Hello, Lithosphere Tutorials系列教程中的其中一篇。

感覺介紹用C/C++,用Python來開發(fā)物聯(lián)網(wǎng)應(yīng)用的文章比較多,用Java來做物聯(lián)網(wǎng)的文章比較少。

這篇文章,介紹如何使用Java技術(shù)來開發(fā)一個物聯(lián)網(wǎng)的簡單例子。我們從手機App上,遙控硬件板上的LED燈亮燈、熄燈、閃燈。

我們學習如何將樹莓派硬件板連接到服務(wù)器,并使用Java代碼來控制硬件板的GPIO。

當一切連通,我們通過手機App來遙控硬件板LED燈。

我們使用100%的純Java代碼來完成這一切。

以下,為教程的具體內(nèi)容。
?

Hello, Actuator!!!

歡迎進入IoT的世界?。?!讓我們來學習如何讓硬件板上的LED燈閃起來


在這第一篇教程中,讓我們使用一塊樹莓派硬件板,通過GPIO連接LED燈。


然后,我們使用Lithosphere IoT平臺提供的Actuator插件,只需要做簡單的開發(fā),我們就可以用App遙控IoT硬件板設(shè)備來讓LED閃燈了。


?

1 前置條件:

Java = 8(樹莓派端)

Java >= 11(服務(wù)器端)

Granite Lite IoT XMPP Server

點擊這里下載Granite Lite IoT XMPP Server

Raspberry Pi Zero W硬件板

LED模塊

幾顆杜邦線


下圖是這個教程中使用到的硬件。

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言


?

2 概念

這篇教程,會涉及到IoT設(shè)備的硬件控制接口,以及IoT終端設(shè)備的分發(fā)部署。簡單介紹相關(guān)概念如下。


?

2.1 GPIO

GPIO是英文General-Purpose Input/Output的縮寫。


簡單來說,GPIO就是硬件板上一組引針,這些引針可以用來控制電信號輸入輸出。


由于這些引針是可以編程來控制的,從而可以實現(xiàn)和外部的電路模塊板通訊。


下圖是Raspberry Pi Zero W上的GPIO接口。

?

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言





在本教程中,我們使用GPIO來連接外部的LED模塊,從而實現(xiàn)LED小燈的程序控制。


?

2.2 設(shè)備注冊

在真實的IoT應(yīng)用中,當一個IoT設(shè)備從庫房中拿出來時,它并不能接通電源后立馬就開始工作。


基于安全性和利于管理的考慮,IoT設(shè)備要能夠開始工作,需要經(jīng)過一個“設(shè)備注冊”的步驟。


在這個“設(shè)備注冊”的過程中,應(yīng)用一般會:

  • 檢查設(shè)備的合法性
  • 檢查設(shè)備是否在此時被允許進入網(wǎng)絡(luò)
  • 登記設(shè)備相關(guān)信息到系統(tǒng)中
  • 配置設(shè)備 - 例如對設(shè)備進行網(wǎng)絡(luò)配置;發(fā)放安全token等。




在不同的應(yīng)用和不同標準中,“設(shè)備注冊”可能會有不同的術(shù)語和叫法。


例如,在LoRaWAN標準中,“設(shè)備注冊”被叫做"End Device Activation"。官方文檔里,這樣描述End Device Activation:

All end devices that participate in a LoRaWAN network must be activated. There are two methods of activation you can choose: over-the-air activation (OTAA) or activation by personalization (ABP).


Lithosphere IoT Platform基于XMPP通訊協(xié)議。在標準XMPP協(xié)議擴展XEP-0077 (In-Band Registration)里,定義了如何實現(xiàn)IM用戶在線注冊的功能。


遵從XMPP的習慣,Lithosphere IoT平臺里的“設(shè)備注冊”,被稱為IBTR(In-Band Thing Registration),即智能物件在線注冊。


Lithosphere IoT平臺,已經(jīng)內(nèi)置實現(xiàn)了IBTR功能?;诜?wù)器端和客戶端的IBTR插件,可以快速開發(fā)及靈活定制“設(shè)備注冊”功能。


在本篇教程中,我們會看到相關(guān)的內(nèi)容。


?

3 安裝和配置Raspberry Pi

樹莓派Zero W,我在淘寶上買153元RMB,記住要買一個SD卡來插上。


我們需要做的第一件事,是給樹莓派裝上系統(tǒng)。


在沒有監(jiān)視器和鍵盤的情況下,給樹莓派裝上OS。在Raspberry Pi的官方的文檔里,把這叫做Headless Setting Up??梢詤⒖枷旅娴逆溄樱私馊绾巫鯤eadless Setting Up。

官方Headless Setting Up文檔



如果你不想閱讀英文,可以看XDongger這篇關(guān)于樹莓派安裝和配置的文章。

安裝和配置樹莓派
?

4 連接硬件

我們先來看看LED模塊長啥樣。
?

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言


這個LED模塊在淘寶上買,5塊錢一個。



我們可以看到,它有3個引腳:

引腳名 作用
GND 地線
VCC 5V電源
IN LED控制




我們需要將LED模塊,通過樹莓派硬件板上的GPIO接口,連接到硬件板上。



如何對接呢?讓我們我們來看看樹莓派的GPIO接口。
?

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言





我們將LED的VCC接口,接在GPIO的5V Powerd引腳上。
我們將LED的GND接口,接在GPIO的Ground引腳上。
我們將LED的IN接口,接在GPIO 8引腳上。



接好后,看上去是這樣的。

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言


?

5 配置硬件板基礎(chǔ)軟件環(huán)境

在2 安裝和配置Raspberry Pi步驟中,我們只是得到了一個初始化版本的RaspBerry Pi OS操作系統(tǒng)。要想在上面能運行Lithosphere IoT平臺的終端程序,還得做以下的配置。


?

5.1 安裝OpenJDK

登錄到樹莓派硬件板。

ssh pi@192.168.1.180

注:

  • 192.168.1.180是樹莓派板的網(wǎng)絡(luò)地址。請改為你配置樹莓派板時,指定的靜態(tài)IP地址。
  • pi為樹莓派用戶。請改為你配置樹莓派時,初始化創(chuàng)建的用戶名。




執(zhí)行以下指令安裝OpenJDK 8。

sudo apt-get install openjdk-8-jdk

注:

  • 為何要安裝OpenJDK 8版本?

Raspberry Pi OS默認自帶的OpenJDK版本是OpenJDK 11。這意味著,如果你執(zhí)行以下指令。系統(tǒng)會默認安裝OpenJDK 11。

sudo apt-get install default-jdk

這個默認版本的JDK,在Raspberry Pi Zero W上不能正常工作。原因是因為Raspberry Zero W使用ARMv6版本CPU。而Raspberry Pi OS默認帶的OPenJDK 11,僅適用于ARMv7和ARMv8版本的CPU。


當然,有一些其它辦法可以在Raspberry Pi Zero W上來安裝OpenJDK 11。


在這篇教程里,我選擇改裝OpenJDK 8的解決方案??瓷先?,這是一個簡單有效的解決方案。


?

5.2 安裝WiringPi

我們在后續(xù)開發(fā)中,會使用Pi4J庫V1.3版本來控制GPIO。Pi4J是一個開源Java庫,它使用JNI來調(diào)用C程序編寫的WiringPi庫來控制GPIO。



所以,我們需要安裝WiringPi。



Raspberry Pi OS并沒有自帶WiringPi軟件包。我們通過以下指令安裝WiringPi。

wget https://github.com/WiringPi/WiringPi/releases/download/2.61-1/wiringpi-2.61-1-armhf.deb

sudo dpkg -i wiringpi-2.61-1-armhf.deb


?

6 開發(fā)協(xié)議包

為何我們需要單獨開發(fā)一個包含協(xié)議對象的協(xié)議包?


這是因為我們使用叫OXM(Object-XMPP Mapping)的技術(shù)。簡單來說,我們希望在開發(fā)中,能夠屏蔽掉XMPP協(xié)議實現(xiàn)的細節(jié),簡化開發(fā)過程。


關(guān)于OXM,可以參考概念文檔中的OXM章節(jié)



使用OXM,我們會定義的協(xié)議對象,這些協(xié)議對象,在客戶端和服務(wù)器端,都會被使用。協(xié)議對象是可復(fù)用的。


所以,我們最好開發(fā)一個單獨的協(xié)議包,已便于在后面客戶端和服務(wù)器端復(fù)用這些協(xié)議對象。


?

6.1 創(chuàng)建協(xié)議工程

創(chuàng)建hello-actuator-protocol工程,pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://maven.apache.org/POM/4.0.0"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

	<modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>com.thefirstlineofcode.basalt</groupId>
		<artifactId>com.thefirstlineofcode.basalt</artifactId>
		<version>1.1.0-RELEASE</version>
	</parent>

	<groupId>com.thefirstlineofcode.lithosphere.tutorials.helloactuator</groupId>
	<artifactId>hello-actuator-protocol</artifactId>
	<name>Hello actuator protocol</name>
	<version>0.0.1-RELEASE</version>
	
	<dependencies>
		<dependency>
			<groupId>com.thefirstlineofcode.basalt</groupId>
			<artifactId>basalt-oxm</artifactId>
		</dependency>
	</dependencies>
	
	<repositories>
		<repository>
			<id>com.thefirstlineofcode.releases</id>
			<name>TheFirstLineOfCode Repository - Releases</name>
			<url>http://120.25.166.188:9090/repository/maven-releases/</url>
		</repository>
	</repositories>
	
</project>

代碼說明

  • 指定parent為com.thefirstlineofcode.basalt:com.thefirstlineofcode.basalt,這樣可以直接引用basalt parent pom的依賴管理配置。

    ?
  • 因為要使用OXM(Object-XMPP Mapping),所以依賴basalt-oxm庫。

    ?
  • 目前,Lithosphere的開源庫,僅被部署在TheFirstLineOfCode的私有的maven服務(wù)器上。為了構(gòu)建時能夠正確找到開源依賴庫,需要配置com.thefirstlineofcode.releases的repository。
<repositories>
	<repository>
	<id>com.thefirstlineofcode.releases</id>
	<name>TheFirstLineOfCode Repository - Releases</name>
	<url>http://120.25.166.188:9090/repository/maven-releases</url>
	</repository>
</repositories>


?

6.2 定義協(xié)議對象

在Hello,Actuator例子里,我們想用App來遙控IoT設(shè)備上的LED燈。我們希望可以遙控LED執(zhí)行:亮燈、熄燈、閃燈。


為此,我們使用以下3個協(xié)議對象:
TurnOn

@ProtocolObject(namespace="urn:leps:things:simple-light", localName="turn-on")
public class TurnOn {
	public static final Protocol PROTOCOL = new Protocol("urn:leps:things:simple-light", "turn-on");
}




TurnOff

@ProtocolObject(namespace="urn:leps:things:simple-light", localName="turn-off")
public class TurnOff {
	public static final Protocol PROTOCOL = new Protocol("urn:leps:things:simple-light", "turn-off");
}




Flash

@ProtocolObject(namespace="urn:leps:things:simple-light", localName="flash")
public class Flash {
	public static final Protocol PROTOCOL = new Protocol("urn:leps:things:simple-light", "flash");
	
	private int repeat;
	
	public Flash() {
		this(1);
	}
	
	public Flash(int repeat) {
		setRepeat(repeat);
	}
	
	public int getRepeat() {
		return repeat;
	}

	public void setRepeat(int repeat) {
		if (repeat < 1)
			throw new IllegalArgumentException("Attribute repeat must be a non-zero positive integer.");
		
		this.repeat = repeat;
	}
	
	@Override
	public String toString() {
		return String.format("Flash[repeat=%d]", repeat);
	}
}

代碼說明

  • OXM框架會幫我們將Project Object轉(zhuǎn)換成XMPP協(xié)議文檔。當Flash對象的repeat屬性值設(shè)置成5時,會生成下面的XMPP協(xié)議文檔:
<flash xmlns="urn:leps:things:simple-light" repeat=5/>


?

  • 不需要擔心"urn:leps:things:simple-light"字符串太長了,會帶來傳輸效率的低下。在Lithosphere IoT平臺下,如果使用BXMPP技術(shù),ProtocolObject(namespace="urn:leps:things:simple-light", localName="flash")這段協(xié)議頭信息,會被轉(zhuǎn)化成3字節(jié)長度的二進制協(xié)議信息。

    ?
  • TurnOn和TurnOff,表達一個不帶任何參數(shù)的指令,所以它們被設(shè)計成不帶任何實例屬性的空對象。


?

6.3 定義Model Descriptor

讓我們來給要控制的IoT設(shè)備,定義一個Model Descriptor。


為何需要定義Model Descriptor?


這是因為Lithosphere完全基于插件架構(gòu)。在插件架構(gòu)下,系統(tǒng)功能并不是寫死固化的。當一個插件被部署時,它為系統(tǒng)提供了一組應(yīng)用功能。當這個插件被卸載掉后,它所提供的功能就消失了。


正是因為這種插件架構(gòu)的特性,默認系統(tǒng)是不認識任何IoT設(shè)備的,也不能識別任何IoT控制/數(shù)據(jù)協(xié)議。


當我們基于插件技術(shù),使用XMPP擴展協(xié)議,開發(fā)了某種IoT設(shè)備的一組應(yīng)用功能。我們需要使用平臺提供的擴展點,將插件提供的應(yīng)用功能注冊到系統(tǒng)中。我們需要明確的告知系統(tǒng):現(xiàn)在,我們有這些功能了,相關(guān)功能由XXX插件提供。


最好是能有一個從設(shè)備維度專門描述IoT設(shè)備的對象,能夠便利我們將相關(guān)信息提供給系統(tǒng)。


這個事說起來啰嗦,實操起來其實比較簡單。我們需要在協(xié)議包里,定義一個Model Descriptor類。

public class HatModelDescriptor extends SimpleThingModelDescriptor {
	public static final String MODEL_NAME = "HAT";
	public static final String DESCRIPTION = "Hello Acuator Thing";
	
	public HatModelDescriptor() {
		super(MODEL_NAME, DESCRIPTION, false, null, null, createSupportedActions());
	}
	
	private static Map<Protocol, Class<?>> createSupportedActions() {
		Map<Protocol, Class<?>> supportedActions = new HashMap<>();
		supportedActions.put(Flash.PROTOCOL, Flash.class);
		supportedActions.put(TurnOn.PROTOCOL, TurnOn.class);
		supportedActions.put(TurnOff.PROTOCOL, TurnOff.class);
		
		return supportedActions;
	}
}

代碼說明

  • 繼承SimpleThingModelDescriptor,這個基類實現(xiàn)了IThingModelDescriptor接口,提供了一些復(fù)用代碼,可以讓我們編寫Model Descriptor時更省事。

    ?
  • IoT設(shè)備的型號名。在這里,我們把這個被遙控閃燈的IoT設(shè)備型號叫做HAT,Hello Actuator Thing的縮寫。

    ?
  • 這個IoT設(shè)備是一個Actuator(執(zhí)行器)設(shè)備,它接受Action指令,然后執(zhí)行指令對應(yīng)的操作。它不是Sensor,不需要上報數(shù)據(jù)。它也不觸發(fā)事件,不需要事件通知功能。所以構(gòu)造器里的參數(shù)都是false,null。只有最后一個構(gòu)造器參數(shù),我們用createSupportedActions(),將這個Actuator設(shè)備支持的Action都登記到Model Descriptor中。當然,在這個例子里,IoT設(shè)備只支持3個指令,TurnOn,TurnOff,F(xiàn)lash。


?

6.4 構(gòu)建安裝協(xié)議包

因為需要在后續(xù)開發(fā)客戶端和服務(wù)器端插件包時,引用協(xié)議包,所以我們在hello-actuator-protocol工程里,執(zhí)行構(gòu)建安裝指令,把協(xié)議包安裝到本地maven倉庫。

cd hello-actuator-protocol
mvn clean install




協(xié)議包已經(jīng)開發(fā)完成,你可以參考官方開源倉庫代碼hello-actuator-protocol協(xié)議包工程源碼


?

7 開發(fā)服務(wù)器端插件

7.1 服務(wù)器端插件工程

創(chuàng)建hello-actuator-server目錄,添加pom.xml文件。

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://maven.apache.org/POM/4.0.0"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	
	<parent>
		<groupId>com.thefirstlineofcode.sand</groupId>
		<artifactId>sand-server</artifactId>
		<version>1.0.0-BETA3</version>
	</parent>

	<groupId>com.thefirstlineofcode.lithosphere.tutorials.helloactuator</groupId>
	<artifactId>hello-actuator-server</artifactId>
	<version>0.0.1-RELEASE</version>
	<name>Hello actuator server plugin</name>

	<dependencies>
		<dependency>
			<groupId>com.thefirstlineofcode.sand.server</groupId>
			<artifactId>sand-server-things</artifactId>
		</dependency>
		<dependency>
			<groupId>com.thefirstlineofcode.lithosphere.tutorials.helloactuator</groupId>
			<artifactId>hello-actuator-protocol</artifactId>
			<version>0.0.1-RELEASE</version>
		</dependency>
	</dependencies>
	
	<repositories>
		<repository>
			<id>com.thefirstlineofcode.releases</id>
			<name>TheFirstLineOfCode Repository - Releases</name>
			<url>http://120.25.166.188:9090/repository/maven-releases/</url>
		</repository>
	</repositories>
</project>

代碼說明

  • parent設(shè)置為com.thefirstlineofcode.sand:sand-server,可引用parent POM里的以來配置管理。

    ?
  • 依賴com.thefirstlineofcode.sand.server:sand-server-things庫,因為我們要使用這個庫里的接口IThingProvider和IThingRegistrationCustomizer來實現(xiàn)相關(guān)功能。
  • 依賴hello-actuator-protocol協(xié)議包。


?

7.2 實現(xiàn)IThingProvider

@Extension
public class ThingModelsProvider implements IThingModelsProvider {

	@Override
	public IThingModelDescriptor[] provide() {
		return new IThingModelDescriptor[] {
			new HatModelDescriptor()
		};
	}

}

代碼說明

  • 實現(xiàn)IThingProvider接口,在接口方法里,我們將前面開發(fā)的HatModelDescripotor登記到服務(wù)器中。

    ?
  • 請注意@Extension標注,它申明了這個類是PF4J的插件擴展。


?

7.3 實現(xiàn)IThingRegistrationCustomizer

在這篇教程的前面章節(jié),我們提到了“設(shè)備注冊”。在Lithosphere平臺里,“設(shè)備注冊”被實現(xiàn)為IBTR(In-Band Thing Registration)協(xié)議。



Lithosphere IoT平臺,提供一個IThingRegistrationCustomizer的接口,來允許開發(fā)人員定制設(shè)備注冊的過程。


下面,我們來看看怎么使用IThingRegistrationCustomizer。

@Extension
public class ThingRegistrationCustomizer extends ThingRegistrationCustomizerAdapter {
	private static final String HARD_CODED_REGISTRATION_CODE = "abcdefghijkl";
	
	@Override
	public boolean isUnregisteredThing(String thingId, String registrationCode) {
		if (!super.isUnregisteredThing(thingId, registrationCode))
			return false;
		
		return HARD_CODED_REGISTRATION_CODE.equals(registrationCode);
	}

	@Override
	public boolean isAuthorizationRequired() {
		return false;
	}
}

代碼說明

  • 繼承ThingRegistrationCustomizerAdapter,這個類提供了IThingRegistrationCustomizer接口的默認實現(xiàn)。

    ?
  • 重載了isUnregisteredThing方法,這個方法檢查IoT設(shè)備的 Thing ID和Registration Code的合法性。我們看到,實現(xiàn)檢查一個硬編碼寫死的Registration Code。

    ?
  • isAuthorizationRequired(),返回false。我們在這個例子中,只檢查Thing ID和Registration Code的合法性。不做人工的設(shè)備注冊授權(quán)。所以我們關(guān)掉Authorization功能。

    ?
  • @Extension標注申明這個類是PF4J的插件擴展。


?

7.4 編寫插件配置文件

在src/main/resources目錄下,創(chuàng)建plugin.properties。

plugin.id=hello-actuator-server
plugin.provider=TheFirstLineOfCode
plugin.version=0.0.1-RELEASE
plugin.dependencies=sand-server-things
non-plugin.dependencies=hello-actuator-protocol

代碼說明

  • plugin.dependencies,依賴sand-server-things插件。

    ?
  • non-plugin.dependencies,依賴hello-actuator-protocol協(xié)議包(非插件格式j(luò)ar)。


?

7.5 構(gòu)建部署服務(wù)器端插件

構(gòu)建hello-actuator-server插件包

cd hello-actuator-server
mvn clean package




將hello-actuator-server插件包和它依賴的hello-actuator-protocol包,把這兩個jar包,copy到服務(wù)器的plugins目錄下。

cp hello-actuator-protocol/target/hello-actuator-protocol-0.0.1-RELEASE.jar granite-lite-iot-1.0.4-RELEASE/plugins

cp hello-actuator-server/target/hello-actuator-server-0.0.1-RELEASE.jar granite-lite-iot-1.0.4-RELEASE/plugins




服務(wù)器端插件已經(jīng)開發(fā)完成,你可以參考官方開源倉庫代碼hello-actuator-server服務(wù)器端插件包工程源碼


?

7.6 檢查Granite Lite XMPP Server狀態(tài)

啟動Granite Lite XMPP Server

cd granite-lite-iot-1.0.4
java -jar granite-server-1.0.4-RELEASE.jar -console

帶-console參數(shù)啟動Granite Lite XMPP Server之后,能夠看到Granite Server Console的界面。

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言




我們可以在Console輸入services命令來檢查Granite XMPP Server的狀態(tài)。

$services

如果能看到所有的services的狀態(tài)都是available,說明granite lite server已經(jīng)被正常的啟動了。
?

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言





可以用plugins命令,來檢查可用的plugins。

$plugins

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言




我們可以看到,hello-actuator-server插件已經(jīng)被部署。
?

7.7 創(chuàng)建測試用戶

在這里,我們還需要解決一個問題。
?

我們想使用手機App來遙控IoT設(shè)備閃燈,我們使用XMPP技術(shù)來做這件事情。
?

在XMPP標準里,要在XMPP網(wǎng)絡(luò)里進行通訊,你需要一個XMPP賬戶。無論你是人還是物,你都需要一個賬戶。你是人,需要一個User賬戶。你是物,你需要一個Thing(IoT)賬戶。


我們需要一個User賬戶,這樣,我們才能夠從手機App,連接到XMPP網(wǎng)絡(luò)中,這才有可能通過XMPP網(wǎng)絡(luò)去遙控IoT設(shè)備。


有一個簡單的辦法,可以創(chuàng)建User用戶。


我們在Granite Lite IoT XMPP Server里,默認部署了sand-demo-server插件。這個插件用來支撐完整的sand-demo演示程序。使用plugins指令,可以看到Granite Lite IoT XMPP Server部署了sand-demo-server插件。
?

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言





sand-demo-server插件,在Granite Server Console里提供了一個創(chuàng)建測試用戶的指令,我們可以用它來創(chuàng)建測試用戶。在Granite Server Console里,我們執(zhí)行以下指令。

sand-demo create-test-users




我們會看到,測試用戶已經(jīng)被創(chuàng)建。

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言




我們在這個教程后面,會使用測試用戶sand-demo來登錄手機App,進行遙控閃燈操作。




使用exit指令,可以退出Granite Server Console,并關(guān)閉Granite XMPP Server。

$exit

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言


?

8 開發(fā)設(shè)備端程序

8.1 設(shè)備端工程

創(chuàng)建hello-actuator-thing目錄,添加pom.xml文件。

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://maven.apache.org/POM/4.0.0"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	
	<parent>
		<groupId>com.thefirstlineofcode.sand</groupId>
		<artifactId>sand-client</artifactId>
		<version>1.0.0-BETA3</version>
	</parent>

	<groupId>com.thefirstlineofcode.lithosphere.tutorials.helloactuator</groupId>
	<artifactId>hello-actuator-thing</artifactId>
	<version>0.0.1-RELEASE</version>
	<name>Hello actuator thing</name>

	<dependencies>
		<dependency>
			<groupId>com.thefirstlineofcode.sand.client</groupId>
			<artifactId>sand-client-edge</artifactId>
		</dependency>
		<dependency>
			<groupId>com.pi4j</groupId>
			<artifactId>pi4j-core</artifactId>
			<version>1.3</version>
		</dependency>
		<dependency>
			<groupId>com.thefirstlineofcode.lithosphere.tutorials.helloactuator</groupId>
			<artifactId>hello-actuator-protocol</artifactId>
			<version>0.0.1-RELEASE</version>
		</dependency>
	</dependencies>
	
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<version>2.4</version>
				<configuration>
					<archive>
						<manifest>
							<addClasspath>true</addClasspath>
							<classpathPrefix>libs/</classpathPrefix>
							<mainClass>com.thefirstlineofcode.lithosphere.tutorials.helloactuator.thing.Main</mainClass>
						</manifest>
					</archive>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-assembly-plugin</artifactId>
				<version>3.0.0</version>
				<configuration>
					<appendAssemblyId>false</appendAssemblyId>
					<descriptors>
						<descriptor>src/assembly/descriptor.xml</descriptor>
					</descriptors>
				</configuration>
				<executions>
					<execution>
						<id>make-assembly</id>
						<phase>package</phase>
						<goals>
							<goal>single</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
	
	<repositories>
		<repository>
			<id>com.thefirstlineofcode.releases</id>
			<name>TheFirstLineOfCode Repository - Releases</name>
			<url>http://120.25.166.188:9090/repository/maven-releases/</url>
		</repository>
	</repositories>
</project>

代碼說明

  • POM繼承com.thefirstlineofcode.sand:sand-client,以便復(fù)用父POM里的依賴配置管理。

    ?
  • hello-actuator-thing是一個獨立運行的Java程序。我們使用maven-assembly-plugin和maven-jar-plugin來打包和配置可這個可運行程序。

    ?
  • 依賴com.thefirstlineofcode.sand.client:sand-client-edge庫,我們使用Edge庫來幫助終端設(shè)備進行設(shè)備注冊和連接服務(wù)器。
<dependency>
	<groupId>com.thefirstlineofcode.sand.client</groupId>
	<artifactId>sand-client-edge</artifactId>
</dependency>


?

  • 依賴pi4j-core庫。我們用Pi4J庫來訪問控制硬件板的GPIO接口。
<dependency>
	<groupId>com.pi4j</groupId>
	<artifactId>pi4j-core</artifactId>
	<version>1.3</version>
</dependency>

注:我們使用1.3版本Pi4J。因為Pi4J v1.4和Pi4J v2.x需要JDK 11。而我們在樹莓派Zero W上,只安裝了JDK 8。所以,我們使用Pi4J v1.3。

  • 依賴hello-actautor-protocol協(xié)議包。
<dependency>
	<groupId>com.thefirstlineofcode.lithosphere.tutorials.helloactuator</groupId>
	<artifactId>hello-actuator-protocol</artifactId>
	<version>0.0.1-RELEASE</version>
</dependency>


?

8.2 硬件控制

程序設(shè)計一個重要原則,責任原則。簡單來說,我們將不同的責任劃分到不同的接口和實現(xiàn)中,讓它們各行其事。


在這里,我們也來劃分責任。


我們先來關(guān)注硬件控制部分,我們想要控制IoT設(shè)備做亮燈、熄燈、閃燈。


Ok,先不管其它,我們來定義這個IoT設(shè)備的硬件控制的接口。
?

public interface ISimpleLight {	
	void turnOn();
	void turnOff();
	void flash(int repeat) throws ExecutionException;
}

注:
這種控制硬件的接口,在概念里,我們把它叫做Thing Controller,智能物件控制器。



hello-actuator-thing的核心類HelloActuatorThing,我們讓它實現(xiàn)ISimpleLight接口。

public class HelloActuatorThing implements ISimpleLight {
	private GpioController gpio;
	private GpioPinDigitalOutput ledPin;
	
	public HelloActuatorThing() {
		configureGpio();
	}
	
	private void configureGpio() {
		gpio = GpioFactory.getInstance();
		ledPin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_08, "MyLED", PinState.LOW);
		ledPin.setShutdownOptions(true, PinState.LOW);
	}
	
	@Override
	public void turnOn() {
		ledPin.high();
	}

	@Override
	public void turnOff() {
		ledPin.low();
	}

	@Override
	public void flash(int repeat) throws ExecutionException {
		if (repeat <= 0 || repeat > 8)
			throw new ExecutionException(-1);
		
		for (int i = 0; i < repeat; i++) {			
			flash();
			
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				throw new ExecutionException(-2);
			}
		}
	}
	
	private void flash() throws ExecutionException {
		turnOn();
		
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			throw new ExecutionException(-2);
		}
		
		turnOff();
	}	
}

**代碼說明

  • 在configureGpio()方法里,我們使用Pi4J庫對GPIO進行配置。我們配置使用ledPin變量來對LED燈的IN接口進行控制。

    ?
  • 在turnOn方法中,我們調(diào)用ledPin.high(),拉高GPIO引針電壓,這會讓LED燈亮燈。對應(yīng)的,在turnOff方法中,我們調(diào)用ledPin.low()來讓LED燈熄燈。




Ok,現(xiàn)在,我們已經(jīng)實現(xiàn)硬件控制了。


?

8.3 IoT通訊

讓我們來給IoT設(shè)備添加通訊能力。


我們使用sand-client-edge庫,可以簡化設(shè)備端程序的編寫。


讓HelloActuatorThing繼承AbstractEdgeThing。

public class HelloActuatorThing extends AbstractEdgeThing implements ISimpleLight {
	public static final String THING_MODEL = HatModelDescriptor.MODEL_NAME;
	public static final String SOFTWARE_VERSION = "0.0.1-RELEASE";
	
	private IActuator actuator;
	private GpioController gpio;
	private GpioPinDigitalOutput ledPin;
	
	public HelloActuatorThing() {
		super(THING_MODEL, streamConfig, true);
		
		configureGpio();
	}
	
	@Override
	public String getSoftwareVersion() {
		return SOFTWARE_VERSION;
	}
	
	@Override
	protected void registerIotPlugins() {
		chatClient.register(ActuatorPlugin.class);
	}
	
	@Override
	protected void startIotComponents() {
		startActuator();
	}
	
	private void configureGpio() {
		... ...
	}

	private void startActuator() {
		if (actuator == null) {			
			actuator = chatClient.createApi(IActuator.class);
			registerExecutors(actuator);
		}
		
		actuator.start();
	}
	
	private void registerExecutors(IActuator actuator) {
		actuator.registerExecutor(TurnOn.class, TurnOnExecutor.class, this);
		actuator.registerExecutor(TurnOff.class, TurnOffExecutor.class, this);
		actuator.registerExecutorFactory(createFlashExecutorFactory());
	}
	
	private IExecutorFactory<?> createFlashExecutorFactory() {
		return new IExecutorFactory<Flash>() {
			@Override
			public Protocol getProtocol() {
				return Flash.PROTOCOL;
			}
			
			@Override
			public Class<Flash> getActionType() {
				return Flash.class;
			}
			
			@Override
			public IExecutor<Flash> create() {
				return new FlashExecutor(HelloActuatorThing.this);
			}
		};
	}
	
	@Override
	protected void stopIotComponents() {
		if (actuator != null) {			
			actuator.stop();
			actuator = null;
		}
	}
	
	@Override
	public void turnOn() {
		... ...
	}

	@Override
	public void turnOff() {
		... ...
	}

	@Override
	public void flash(int repeat) throws ExecutionException {
		... ...
	}
	
	private void flash() throws ExecutionException {
		... ...
	}
		
	@Override
	protected String loadThingId() {
		return THING_MODEL + "-" + ThingsUtils.generateRandomId(8);
	}
	
	@Override
	protected String loadRegistrationCode() {
		return "abcdefghijkl";
	}
}

代碼說明

  • AbstractEdgeThing留下了一些抽象方法給子類來實現(xiàn)。這些抽象方法名字很直白,我們遵從方法名給出對應(yīng)實現(xiàn)細節(jié)即可。

    ?
  • registerIotPlugins()方法,在這里登記我們要使用的插件。因為這個IoT設(shè)備是一個可執(zhí)行指令的Actuator。所以我們只需要注冊ActuatorPlugin插件。
protected void registerIotPlugins() {
	chatClient.register(ActuatorPlugin.class);
}


?

  • startIotComponents()方法,Edge Thing連接到服務(wù)器后,會調(diào)用這個方法來啟動設(shè)備。在這里,我們需要把Actuator組件啟動起來,Actuator組件來自ActuatorPlugin。

    我們在startActuator()方法里,創(chuàng)建IActuator實例,并注冊Executors,最后調(diào)用Actuator的start()方法。
protected void startIotComponents() {
	startActuator();
}

private void startActuator() {
	if (actuator == null) {			
		actuator = chatClient.createApi(IActuator.class);
		registerExecutors(actuator);
	}
	
	actuator.start();
}


?

  • 在registerExecutors()方法里,我們給TurnOn,TurnOff,F(xiàn)lash指令,注冊它們對應(yīng)的執(zhí)行器。


    有兩種注冊執(zhí)行器的API。第一種API,我們直接將Action指令類,和Executor指令類,登記到Actuator。


    注:
    這里registerExecutor()方法的最后一個參數(shù),是Thing Controller。


    依據(jù)設(shè)計原則中的責任原則,Thing Controller負責直接控制IoT設(shè)備的硬件接口。在這里,Thing Controller是ISimpleLigh。


    HelloActuatorThing實現(xiàn)了這個接口(ISimpleLight),提供控制硬件的turnOn(),TurnOff(),flash()方法。


    我們把HelloActuatorThing當做第三個參數(shù)傳給Actuator,Thing Controller會被注入給Executor使用。
actuator.registerExecutor(TurnOn.class, TurnOnExecutor.class, this);
actuator.registerExecutor(TurnOff.class, TurnOffExecutor.class, this);


?

  • 第二種API,我們注冊一個Executor Factory,由這個Factory來提供相關(guān)信息以及創(chuàng)建Executor,這樣可以更靈活的處理Executor的創(chuàng)建。我們使用這種API來創(chuàng)建FlashExecutor。
... ...
	actuator.registerExecutorFactory(createFlashExecutorFactory());
... ...

private IExecutorFactory<?> createFlashExecutorFactory() {
	return new IExecutorFactory<Flash>() {
		@Override
		public Protocol getProtocol() {
			return Flash.PROTOCOL;
		}

		@Override
		public Class<Flash> getActionType() {
			return Flash.class;
		}
	
		@Override
		public IExecutor<Flash> create() {
			return new FlashExecutor(HelloActuatorThing.this);
		}
	};
}


?

  • 我們來處理一下設(shè)備注冊的對應(yīng)邏輯。還記得嗎,我們在服務(wù)器端的Registration Customizer里,在檢查Registration Code合法性時,使用的是一個硬編碼的Registration Code。


    所以,在IoT設(shè)備端,我們需要使用這個硬編碼的Registration Code去注冊。


    我們重載loadRegistrationCode()方法,用寫死的"abcdefghijkl"作為Registration Code去進行注冊。
protected String loadRegistrationCode() {
	return "abcdefghijkl";
}


?

8.4 主程序

我們編寫一個主程序來啟動hello-actuator-thing。

public class Main {
	private HelloActuatorThing simpleLight;
	
	public static void main(String[] args) {
		new Main().run(args);
	}

	private void run(String[] args) {
		if (args.length == 1 && args[0].equals("--help")) {
			printUsage();
			
			return;
		}
		
		... ...
		
		try {
			simpleLight = new HelloActuatorThing();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			printUsage();
			
			return;
		}
		
		... ...
		
		simpleLight.start();
	}
	
	... ...
}

代碼說明

  • 很簡單直白的代碼,重要的是調(diào)用HelloActuatorThing的start()方法,將Edge Thing啟動起來。




設(shè)備端程序已經(jīng)開發(fā)完成,你可以參考官方開源倉庫代碼hello-actuator-thing設(shè)備端程序工程源碼


?

8.5 構(gòu)建部署hello-actuator-thing

用maven構(gòu)建hello-actuator-thing

cd hello-actuator-thing
mvn clean package




將構(gòu)建成功的設(shè)備端程序,copy到樹莓派硬件板上。

scp target/hello-actuator-thing-0.0.1-RELEASE.tar.gz pi@192.168.1.180:/home/pi

注:
請將pi用戶名,和樹莓派網(wǎng)絡(luò)ip 192.168.1.180,改為你自己環(huán)境的配置值。


?

8.6 啟動thing程序

登錄到樹莓派上

ssh pi@192.168.1.180




運行thing程序

tar -xzvf hello-actuator-thing-0.0.1-RELEASE.tar.gz
cd hello-actuator-thing-0.0.1-RELEASE
java -jar hello-actuator-thing-0.0.1-RELEASE.jar --host=192.168.1.80

說明

  • 啟動thing程序之前,記得要先啟動Granite XMPP Server。
    ?
  • 第一次運行thing程序時,需要使用--host參數(shù)指定服務(wù)器地址。AbstractEdgeThing會記住程序啟動參數(shù),后續(xù)再啟動thing程序,不需要再指定host。
    ?
  • 程序啟動后,會連接到服務(wù)器進行設(shè)備注冊,注冊成功后,登錄到服務(wù)器


    一切就緒后,可以看到Thing thing has started的提示。

    物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言





    可以使用exit命令來退出hello-actuator-thing程序。


?

9 使用手機App遙控IoT設(shè)備

從頭開發(fā)一個手機App比較繁瑣,我們可以直接用Lithosphere平臺提供的sand-demo App來遙控我們的IoT小燈。



你可以自己來構(gòu)建sand-demo App,這是一個標準的Andriod工程,請用Andriod Studio來打開它。sand-demo App源碼位于sand工程的demo/app-android子目錄下。


你可以直接下載構(gòu)建好的sand-demo App安裝使用。



sand-demo App里大部分是常規(guī)的Android開發(fā)。創(chuàng)建菜單,畫界面... ...



和IoT通訊相關(guān)的部分,是App使用Chalk的remoting插件來遙控IoT設(shè)備。



remoting插件的功能,是可以在遠程設(shè)備上執(zhí)行action指令。



remoting插件的使用較簡單,以下代碼,來自sand-demo App源碼。

... ...
	public void turnOn(JabberId target) {
		logger.info("Turn on light {}.", target);
		controlThing(target, new TurnOn(), "Turn on");
	}
... ...
	private void controlThing(JabberId target, Object action, String actionDescription) {
		IChatClient chatClient = ChatClientSingleton.get(this);
		IRemoting remoting = chatClient.createApi(IRemoting.class);
		remoting.execute(target, action, new RemotingCallback(this, actionDescription));
	}
... ...
private static class RemotingCallback implements IRemoting.Callback {
		private final Activity activity;
		private final String actionDescription;

		public RemotingCallback(Activity activity, String actionDescription) {
			this.activity = activity;
			this.actionDescription = actionDescription;
		}

		@Override
		public void executed(Object xep) {
			activity.runOnUiThread(() -> Toast.makeText(activity,
					actionDescription + " executed.",
					Toast.LENGTH_LONG).show());
		}

		@Override
		public void occurred(StanzaError error) {
			String errorText = actionDescription + " execution error: " +
					(error.getText() == null ? error.toString() : error.getText().getText());
			remotingErrorOccurred(activity, error, errorText);
		}

		@Override
		public void timeout() {
			activity.runOnUiThread(() -> Toast.makeText(activity,
					actionDescription + " execution timeout.",
					Toast.LENGTH_LONG).show());
		}
	}
... ...

代碼說明

  • 用chatClient創(chuàng)建IRemoting實例,然后調(diào)用IRemoting的execute()方法。方法3個參數(shù),第一個參數(shù)是遠程設(shè)備的地址;第二個參數(shù)是要執(zhí)行的action對象(Protocol Object);第三個參數(shù),是RemotingCallback,我們用這個回調(diào)接口來處理遠程指令執(zhí)行結(jié)果。
IChatClient chatClient = ChatClientSingleton.get(this);
IRemoting remoting = chatClient.createApi(IRemoting.class);
remoting.execute(target, action, new RemotingCallback(this, actionDescription));


?

  • 在RemotingCallback里,如果遠程指令正常執(zhí)行,會回調(diào)executed()方法;遠程指令執(zhí)行出錯,會回調(diào)occurred()方法;遠程指令執(zhí)行超時(執(zhí)行端未返回響應(yīng),不能確認指令是否執(zhí)行成功),會調(diào)用timeout()方法。我們在這些回調(diào)方法里,做對應(yīng)的處理。
... ...
@Override
public void executed(Object xep) {
	activity.runOnUiThread(() -> Toast.makeText(activity,
			actionDescription + " executed.",
			Toast.LENGTH_LONG).show());
}

@Override
public void occurred(StanzaError error) {
	String errorText = actionDescription + " execution error: " +
			(error.getText() == null ? error.toString() error.getText().getText());
	remotingErrorOccurred(activity, error, errorText);
}

@Override
public void timeout() {
	activity.runOnUiThread(() -> Toast.makeText(activity,
			actionDescription + " execution timeout.",
			Toast.LENGTH_LONG).show());
}
... ...




如果想了解sand-demo App更多細節(jié),請參考開源倉庫里的sand-demo App程序源碼



將構(gòu)建好或直接下載的sand-demo App安裝到安卓手機上。



啟動sand-demo App。點擊配置傳輸通道鏈接,進入stream配置頁面。

?

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言





在傳輸通道配置頁里,填寫Granite XMPP Server的正確地址。

?

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言





配置好傳輸通道后,回到登錄頁,使用sand-demo用戶名來登錄App。用戶密碼也是"sand-demo"。



登錄后,可以看到注冊成功后hello-actuator-thing。點擊“控制這個智能物件”,會看到下拉菜單里,有Flash,Turn On,Turn Off三個子菜單。

?

物聯(lián)網(wǎng)開發(fā),java,物聯(lián)網(wǎng),開發(fā)語言





現(xiàn)在可以用手機App來控制hello-actuator-thing了。


?

10 總結(jié)

通過這篇教程,我們可以了解到以下的內(nèi)容:文章來源地址http://www.zghlxwxcb.cn/news/detail-770201.html

  • 我們可以通過IoT硬件板上的GPIO接口,來控制IoT設(shè)備的外接硬件模塊。
    ?
  • 開源的Pi4J庫,可以幫助我們使用Java語言來訪問樹莓派上的GPIO接口。
    ?
  • 在IoT的世界里,有不同的通訊協(xié)議可以選擇。在互聯(lián)網(wǎng)端,XMPP協(xié)議是一個很好的選擇。
    ?
  • 如果使用Lithosphere,基于OXM(Object/XMPP Mapping)技術(shù),我們不需要去處理XML,也不需要了解XMPP協(xié)議的細節(jié)。我們簡單的創(chuàng)建Protocol Object來表達通訊指令。
    ?
  • Lithosphere基于插件架構(gòu),我們可以通過創(chuàng)建服務(wù)器端插件,將我們要管理的IoT設(shè)備注冊到系統(tǒng)中。我們還可以定制設(shè)備注冊過程,以應(yīng)對真實項目的需求。
    ?
  • 在IoT設(shè)備端,我們開發(fā)Thing程序。使用Sand的sand-client-edge庫,可以簡化設(shè)備注冊,服務(wù)器連接過程。我們只要注冊需要使用的插件,編寫Thing端處理邏輯。
    ?
  • 對于Actuator(執(zhí)行器)類型的IoT設(shè)備,我們使用actuator插件來簡化開發(fā)。我們登記設(shè)備可執(zhí)行的指令,并且注冊指令所對應(yīng)的Executor(執(zhí)行器)。
    ?
  • 我們在手機App端,使用remoting插件來遠程執(zhí)行指令,遙控IoT設(shè)備。
    ?
  • 這篇教程里的內(nèi)容,全部基于Java平臺,只有Java,不涉及其它編程語言。

到了這里,關(guān)于使用Java來開發(fā)物聯(lián)網(wǎng)應(yīng)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包