IoTMakers와 Java SDK로 Android APP 연동

목표


1. IoTMakers와 연동하기 위한 안드로이드 앱 설정

1.1 디바이스 등록

  1. IoTMakers에 접속해서 디바이스를 등록 해 보자.

  2. 센서 등록을 위해서 태그 스트림 생성버튼을 클릭하여 아래와 같이 태그 스트림을 생성하자. 처음엔 다음과 같은 화면이 보인다. 태그 스트림 생성 버튼을 클릭하여 ID와 UNIT을 입력한다.

1.2 Android 앱에 Java SDK 등록

Android Studio에서 JAVA SDK를 이용하여 IoTMakers에 연결 할 Android 앱을 만들어 보자.

  1. 디바이스와 센서 등록이 모두 끝났으니 이제 JAVA SDK를 다운받아 보자.

  2. 안드로이드 프로젝트를 생성하고 생성된 프로젝트를 아래와 같이 우클릭하여 Open Module Settings 메뉴를 선택한다

  3. 화면 상단의 Modules 아래의 + 버튼을 클릭한다.

  4. Import .JAR/.AAR Package 를 선택한 후, Next 버튼 클릭한다.

  5. 다운 받은 JAVA SDK의 dist 폴더의 JAVA_TCP_SDK_2.0.1.jar를 선택하고, Finish버튼을 클릭한다.

  6. 추가된 JAVA SDK 모듈을 안드로이드 프로젝트 앱 모듈 Dependencies에 아래와 같이 추가한다.

  7. 안드로이드 app 모듈에 아래와 같이 IoTMakers SDK Dependencies가 설정되면 SDK를 활용하여 안드로이드 앱 연동 디바이스 개발이 가능하다

  8. JAVA SDK에 의존성을 갖는 외부 라이브러리도 아래와 같이 복사하자. 외부 라이브러리 폴더는 SDK 압축 폴더 내 lib 폴더에 있다.

  9. 의존성 라이브러리 내 중복 파일이 빌드되는 것을 막기 위해 build.gradle 파일에 다음 스크립트를 아래 그림과 같이 추가하자.

    packagingOptions {
        pickFirst 'META-INF/LICENSE'
        pickFirst 'META-INF/LICENSE.txt'
        pickFirst 'META-INF/DEPENDENCIES'
        pickFirst 'META-INF/NOTICE'
        pickFirst 'META-INF/NOTICE.txt'
        pickFirst 'META-INF/ASL2.0'
    }


2. 위치정보를 주기적으로 알려주는 안드로이드 앱

2.1 프로젝트에 Google Play Services 라이브러리 추가

  1. build.gradle (Module:app) 파일 오픈
  2. 새로운 빌드 규칙 추가

    dependencies {
             ...
             implementation 'com.google.android.gms:play-services-location:16.0.0'
    }
    1. 툴바에서 Sync Project with Graddle File 또는 Sync Now 클릭

2.2 Android Manifest 파일에서 권한 설정

  1. 위치 접근에 필요한 권한 설정

    <manifest ...>
        ...
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
        ...
    </manifest>

2.3 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start location update"
        android:id="@+id/device_button_start" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop location update"
        android:id="@+id/device_button_stop" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send location to IoTMakers"
        android:id="@+id/device_button" />


    <TextView
        android:id="@+id/latitude_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginStart="10dp"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/longitude_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginStart="10dp"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/precision_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginStart="10dp"
        android:textSize="16sp" />

</LinearLayout>

2.4 MainActivity.java

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();
    private FusedLocationProviderClient mFusedLocationClient;
    private Location mLastLocation;
    private LocationCallback mLocationCallback;
    final private int REQUEST_PERMISSIONS_FOR_LOCATION_UPDATES = 101;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

        Button start_location_update_button = (Button) findViewById(R.id.device_button_start);
        start_location_update_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startLocationUpdates();
            }
        });

        Button stop_location_update_button = (Button) findViewById(R.id.device_button_stop);
        stop_location_update_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                stopLocationUpdates();
            }
        });

    }

    private void startLocationUpdates() {
        // 1. 위치 요청 (Location Request) 설정
        LocationRequest locRequest = new LocationRequest();
        locRequest.setInterval(10000);
        locRequest.setFastestInterval(5000);
        locRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        // 2. 위치 업데이트 콜백 정의
        mLocationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult);

                mLastLocation  = locationResult.getLastLocation();

                Log.d(TAG, "latitude : " + mLastLocation.getLatitude()+
                                ", longitude : " + mLastLocation.getLongitude());
                updateUI();
            }
        };

        // 3. 위치 접근에 필요한 권한 검사
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != 
                                                PackageManager.PERMISSION_GRANTED &&
            ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != 
                                                PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(
                    MainActivity.this,            // MainActivity 액티비티의 객체 인스턴스를 나타냄
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},        // 요청할 권한 목록을 설정한 String 배열
                    REQUEST_PERMISSIONS_FOR_LOCATION_UPDATES    // 사용자 정의 int 상수. 권한 요청 결과를 받을 때
            );
            return;
        }

        // 4. 위치 업데이트 요청
        mFusedLocationClient.requestLocationUpdates(locRequest,
                mLocationCallback,
                null /* Looper */);
    }

    @Override
    public void onRequestPermissionsResult(
            int requestCode,
            String[] permissions,
            int[] grantResults) {

        switch (requestCode) {
            case REQUEST_PERMISSIONS_FOR_LOCATION_UPDATES: {
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    startLocationUpdates();

                } else {
                    Toast.makeText(this, "Permission required", Toast.LENGTH_SHORT);
                }
            }
        }
    }

    public void stopLocationUpdates() {
        mFusedLocationClient.removeLocationUpdates(mLocationCallback);
    }

    private void updateUI() {
        double latitude = 0.0;
        double longitude = 0.0;
        float precision = 0.0f;

        TextView latitudeTextView = (TextView) findViewById(R.id.latitude_text);
        TextView longitudeTextView = (TextView) findViewById(R.id.longitude_text);
        TextView precisionTextView = (TextView) findViewById(R.id.precision_text);

        if (mLastLocation != null) {
            latitude = mLastLocation.getLatitude();
            longitude = mLastLocation.getLongitude();
            precision = mLastLocation.getAccuracy();
        }
        latitudeTextView.setText("Latitude: " + latitude);
        longitudeTextView.setText("Longitude: " + longitude);
        precisionTextView.setText("Precision: " + precision);
    }
}

3. Java SDK(TCP)를 사용하여 IoTMakers와 안드로이드 앱 연동하기

3.1 Android Manifest 파일에서 권한 설정

  1. 인터넷 연결에 필요한 권한 설정

    <manifest ...>
        ...
        <uses-permission android:name="android.permission.INTERNET"/>
        ...
    </manifest>

3.2 DeviceTask.java

IoTMakers 와 안드로이드 앱을 디바이스 용도로 연동하기 위해서 다음과 같이 AsyncTask를 상속받은 클래스를 만들고, Task를 실행 했을 때 TcpConnector를 통해 데이터를 전송하기 위해 doInBackground 메소드에 아래와 같은 IoTMakers의 디바이스 정보를 업데이트 한다.

    // 디바이스상세정보-> Gateway 연결 ID를 입력한다.
      info.setExtrSysId("OPEN_TCP_001PTL001_xxxxxxxxx");
   // 디바이스상세정보-> 디바이스 아이디를 입력한다.
      info.setDeviceId("yourdeviceidentification");
   // 디바이스상세정보-> 디바이스 패스워드를 입력한다.
      info.setPassword("xxxxxxxxx");
public class DeviceTask extends AsyncTask<Void, Void, Void> {

    private static final String TAG = DeviceTask.class.getSimpleName();

    private Map<String, Double> rows = new HashMap<String, Double>();

    public DeviceTask(Map<String, Double> rows) {
        this.rows = rows;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected Void doInBackground(Void... params) {

        // IoTMakers 연동 설정 정보
        BaseInfo info = new BaseInfo();
        // 접속 IP, Port 설정
        info.setIp("220.90.216.90");
        info.setPort(10020);
        
        
        // 디바이스상세정보-> Gateway 연결 ID를 입력한다.
        info.setExtrSysId("OPEN_TCP_001PTL001_xxxxxxxxx");
        // 디바이스상세정보-> 디바이스 아이디를 입력한다.
        info.setDeviceId("yourdeviceidentification");
        // 디바이스상세정보-> 디바이스 패스워드를 입력한다.
        info.setPassword("xxxxxxxxx");


        // IoTMakers 연동 TCP Connector 생성
        IMTcpConnector connector = new IMTcpConnector();
        try {
            connector.activate(new LogIf(), info, (long) 3000);

            long transId = IMUtil.getTransactionLongRoundKey4();

            Log.d(TAG, rows.toString());
            // 계측 데이터 HashMap 객체로 전송한다. key는 센싱태그 명 value는 계측값을 넣는다.
            connector.requestNumColecDatas(rows, new Date(), transId);

            connector.deactivate();;

        } catch (SdkException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
    }
}

3.3 MainActivity.java 수정

public class MainActivity extends AppCompatActivity {
    //...
    private Map<String, Double> rows = new HashMap<String, Double>();
    private DeviceTask deviceTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
        // ... 이전코드와 동일
        
               // Location 정보를 IoTMaker에 전송하기 위한 버튼
        Button send_location_button = (Button) findViewById(R.id.device_button);
        send_location_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startDeviceTask();

            }
        });
    }

    private void startDeviceTask() {
        deviceTask = new DeviceTask(rows);
        deviceTask.execute();
    }
    
    private void startLocationUpdates() {
        // ...
        mLocationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult);

                mLastLocation  = locationResult.getLastLocation();
                
                // ********** 추가 되는 부분 *************************
                // 새로운 위치가 변경될 때마다, rows Map 객체에 위도, 경도 저장
                rows.put("latitude", mLastLocation.getLatitude());
                rows.put("longitude", mLastLocation.getLongitude());
             // ********** 추가 되는 부분 *************************
            }
        };
}    
    

3.4 IoTMakers 연동 확인


4. 안드로이드 디바이스의 다양한 센서 추가 실습

참고자료