기기 상태 가져오기

Cloud IoT Core를 사용하면 연결된 각 기기의 상태를 모니터링할 수 있습니다. 상태는 기기에서 바이너리 데이터로 보고됩니다. 기기 상태 업데이트는 일반적으로 기기 변경, 즉 Cloud IoT Core의 구성 업데이트 또는 다른 외부 소스의 유사한 변경(예: 펌웨어 업데이트)에 의해 트리거됩니다.

기기 상태는 기기 구성과 다릅니다. 구성 데이터는 Cloud IoT Core에서 기기로 전송됩니다. 상태 데이터는 기기에서 Cloud IoT Core 전송됩니다. 구성은 외부 명령으로, 상태는 내부 표현으로 생각할 수 있습니다.

Cloud IoT Core는 구성과 상태에 대해 기기에서는 현재 어떤 작업을 해야 한다고 '고려'하고 있나요?, 기기의 최신 구성과 비교하면 어떻게 다른가요?와 같은 기본적인 질문에 답하는 데 도움이 됩니다.

한도

상태 업데이트는 기기별로 초당 1회 업데이트로 제한됩니다. 그러나 최상의 결과를 얻으려면 기기 상태를 최대 10초마다 한번씩 업데이트해야 합니다.

업데이트 속도는 최근 서버 확인과 다음 업데이트 요청 사이의 시간으로 계산됩니다.

기기 상태 보고

MQTT 브리지

MQTT 브리지를 통해 Cloud IoT Core에 상태를 보고하려면 /devices/DEVICE_ID/state MQTT 주제에 메시지를 게시합니다. 레지스트리를 만들거나 업데이트할 때 상태 이벤트를 저장할 Cloud Pub/Sub 주제를 선택할 수 있습니다.

자세한 내용은 MQTT 브리지를 통해 게시를 참조하세요.

HTTP 브리지

HTTP 브리지를 통해 Cloud IoT Core에 상태를 보고하려면 기기에서 setState 요청을 사용해야 합니다. 바이너리 상태 데이터는 요청 본문에 base64로 인코딩된 문자열로 전달됩니다.

자세한 내용은 HTTP 브리지를 통해 게시를 참조하세요.

기기 상태 데이터 가져오기

이 섹션에서는 기기에서 Cloud IoT Core에 보고하는 상태 데이터를 가져오는 방법을 설명합니다. (기기 자체는 클라우드에서 상태 데이터를 읽을 수 없습니다.)

상태 데이터는 바이너리 형식으로 반환됩니다. 상태 데이터의 구조는 상태 변경을 트리거하는 구성 데이터와 다를 수 있습니다.

예를 들어 팬이 여러 개인 기기가 있다고 가정해 보겠습니다. 구성 데이터는 냉각을 사용 설정하거나 중지하는 단순한 불리언이 포함된 JSON 객체일 수 있습니다.

구성 데이터 예시

{
  'cooling': true
}

하지만 기기의 상태 데이터에는 진단 정보와 'cooling' 변경에 대응하여 확인할 수 있는 팬 데이터가 포함될 수 있습니다.

상태 데이터 예시

{
  'fan1_target_rpm': 1000,
  'fan2_target_rpm': 1200,
  'firmware_version': '1.2.3b'
}

기기의 firmware_version은 구성 데이터와 관련이 없지만 기기가 상태에 대한 전체 내부 표현을 반환합니다. 이 예시에서는 기기 상태가 일반적으로 디버깅에 얼마나 유용한지와 기기가 특정 구성을 확인했는지 파악하는 데 얼마나 유용한지 보여줍니다.

Cloud Pub/Sub 주제, Cloud Platform Console, Cloud IoT Core API, gcloud를 사용하여 기기 상태 데이터를 가져올 수 있습니다.

Cloud Pub/Sub 주제

Cloud IoT Core는 스토리지에 상태 데이터를 보관합니다. Cloud Console, gcloud, API를 통해 각 기기 레지스트리에서 선택적 상태 알림 Cloud Pub/Sub 주제를 구성할 수도 있습니다. 이 주제는 원격 분석 이벤트 주제와 동일하거나 다를 수 있습니다.

상태 데이터는 최상의 방식으로 Cloud Pub/Sub에 게시됩니다. 주제에 게시하지 못하면 재시도되지 않습니다. 정의된 주제가 없어도 Cloud IoT Core에서 기기 상태 업데이트가 내부적으로 유지되지만 마지막 10개 상태만 보관됩니다.

콘솔

  1. Cloud Console에서 레지스트리 페이지로 이동합니다.

    레지스트리 페이지로 이동

  2. 기기의 레지스트리 ID를 클릭합니다.

  3. 왼쪽의 레지스트리 메뉴에서 기기를 클릭합니다.

  4. 기기 ID를 클릭하여 기기 세부정보 페이지로 이동합니다.

  5. 구성 및 상태 기록을 클릭합니다. 체크박스를 사용하여 구성 기록, 상태 기록 또는 둘 다 표시합니다. 기본적으로 둘 다 표시됩니다.

    • 녹색 체크표시는 기기가 구성을 확인했음을 나타냅니다(MQTT만 해당).
    • 노란색 경고 기호는 기기가 아직 구성을 확인하지 않았음을 나타냅니다(MQTT만 해당).
    • JSON의 전체 구성 또는 상태 데이터와 타임스탬프 및 버전을 가져오려면 행을 클릭합니다.
  6. 비교를 클릭하여 구성 데이터를 상태 데이터와 비교합니다. 이 뷰는 구성을 디버그하는 데 도움이 되며, MQTT를 사용하는 경우에는 기기에서 특정 구성 버전을 확인해야 합니다. (HTTP 브리지는 구성 확인을 지원하지 않습니다.)

gcloud

기기의 최신 상태 메시지를 가져오려면(최대 10개) gcloud iot devices states list 명령어를 실행합니다.

gcloud iot devices states list \
    --registry=REGISTRY_ID \
    --device=DEVICE_ID \
    --region=REGION

상태 알림 Cloud Pub/Sub 플래그(--state-pubsub-topic)는 gcloud iot registries createupdate 명령어에 사용할 수 있습니다.

gcloud iot registries create REGISTRY_ID \
    --project=PROJECT_ID \
    --region=REGION \
    [--event-notification-config=topic=TOPIC,[subfolder=SUBFOLDER] [--event-notification-config=...]]
    [--state-pubsub-topic=STATE_PUBSUB_TOPIC]
gcloud iot registries update REGISTRY_ID \
    --project=PROJECT_ID \
    --region=REGION \
    [--event-notification-config=topic=TOPIC,[subfolder=SUBFOLDER] [--event-notification-config=...]]
    [--state-pubsub-topic=STATE_PUBSUB_TOPIC]

API

기기 states.list 메서드를 사용하여 최신 기기 상태를 가져옵니다(최대 10개). 각 Device 리소스에는 기기에서 가장 최근에 수신된 상태가 포함된 DeviceState 필드가 있습니다. DeviceRegistry 리소스에는 레지스트리를 만들거나 업데이트할 때 상태 알림 Cloud Pub/Sub 주제를 지정하는 데 사용할 수 있는 StateNotificationConfig 필드가 있습니다.

다음 샘플은 기기 레지스트리에서 기기 상태를 검색하는 방법을 보여줍니다.

C#

public static object GetDeviceStates(string projectId, string cloudRegion, string registryId, string deviceId)
{
    var cloudIot = CreateAuthorizedClient();

    // The resource name of the location associated with the key rings.
    var name = $"projects/{projectId}/locations/{cloudRegion}/registries/{registryId}/devices/{deviceId}";

    try
    {
        Console.WriteLine("States: ");
        var res = cloudIot.Projects.Locations.Registries.Devices.States.List(name).Execute();
        res.DeviceStates.ToList().ForEach(state =>
        {
            Console.WriteLine($"\t{state.UpdateTime}: {state.BinaryData}");
        });
    }
    catch (Google.GoogleApiException e)
    {
        Console.WriteLine(e.Message);
        if (e.Error != null) return e.Error.Code;
        return -1;
    }
    return 0;
}

Go


// getDeviceStates retrieves and lists device states.
func getDeviceStates(w io.Writer, projectID string, region string, registryID string, device string) ([]*cloudiot.DeviceState, error) {
	// Authorize the client using Application Default Credentials.
	// See https://g.co/dv/identity/protocols/application-default-credentials
	ctx := context.Background()
	httpClient, err := google.DefaultClient(ctx, cloudiot.CloudPlatformScope)
	if err != nil {
		return nil, err
	}
	client, err := cloudiot.New(httpClient)
	if err != nil {
		return nil, err
	}

	path := fmt.Sprintf("projects/%s/locations/%s/registries/%s/devices/%s", projectID, region, registryID, device)
	response, err := client.Projects.Locations.Registries.Devices.States.List(path).Do()
	if err != nil {
		return nil, err
	}

	fmt.Fprintln(w, "Successfully retrieved device states!")

	for _, state := range response.DeviceStates {
		fmt.Fprintf(w, "%s : %s\n", state.UpdateTime, state.BinaryData)
	}

	return response.DeviceStates, nil
}

자바

/** Retrieves device metadata from a registry. * */
protected static List<DeviceState> getDeviceStates(
    String deviceId, String projectId, String cloudRegion, String registryName)
    throws GeneralSecurityException, IOException {
  GoogleCredentials credential =
      GoogleCredentials.getApplicationDefault().createScoped(CloudIotScopes.all());
  JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
  HttpRequestInitializer init = new HttpCredentialsAdapter(credential);
  final CloudIot service =
      new CloudIot.Builder(GoogleNetHttpTransport.newTrustedTransport(), jsonFactory, init)
          .setApplicationName(APP_NAME)
          .build();

  final String devicePath =
      String.format(
          "projects/%s/locations/%s/registries/%s/devices/%s",
          projectId, cloudRegion, registryName, deviceId);

  System.out.println("Retrieving device states " + devicePath);

  ListDeviceStatesResponse resp =
      service.projects().locations().registries().devices().states().list(devicePath).execute();

  return resp.getDeviceStates();
}

Node.js

// const cloudRegion = 'us-central1';
// const deviceId = 'my-device';
// const projectId = 'adjective-noun-123';
// const registryId = 'my-registry';
const iot = require('@google-cloud/iot');
const iotClient = new iot.v1.DeviceManagerClient({
  // optional auth parameters.
});

async function listDeviceStates() {
  const devicePath = iotClient.devicePath(
    projectId,
    cloudRegion,
    registryId,
    deviceId
  );

  const [response] = await iotClient.listDeviceStates({name: devicePath});
  const states = response.deviceStates;
  if (states.length === 0) {
    console.log(`No States for device: ${deviceId}`);
  } else {
    console.log(`States for device: ${deviceId}`);
  }

  for (let i = 0; i < states.length; i++) {
    const state = states[i];
    console.log(
      'State:',
      state,
      '\nData:\n',
      state.binaryData.toString('utf8')
    );
  }
}

listDeviceStates();

PHP

use Google\Cloud\Iot\V1\DeviceManagerClient;

/**
 * Retrieve a device's state blobs.
 *
 * @param string $registryId IOT Device Registry ID
 * @param string $deviceId IOT Device ID
 * @param string $projectId Google Cloud project ID
 * @param string $location (Optional) Google Cloud region
 */
function get_device_state(
    $registryId,
    $deviceId,
    $projectId,
    $location = 'us-central1'
) {
    print('Getting device state' . PHP_EOL);

    // Instantiate a client.
    $deviceManager = new DeviceManagerClient();
    $deviceName = $deviceManager->deviceName($projectId, $location, $registryId, $deviceId);

    $response = $deviceManager->listDeviceStates($deviceName);

    foreach ($response->getDeviceStates() as $state) {
        print('State:' . PHP_EOL);
        printf('    Data: %s' . PHP_EOL, $state->getBinaryData());
        printf('    Update Time: %s' . PHP_EOL,
            $state->getUpdateTime()->toDateTime()->format('Y-m-d H:i:s'));
    }
}

Python

이 샘플에서는 Python용 Google API 클라이언트 라이브러리를 사용합니다.
# project_id = 'YOUR_PROJECT_ID'
# cloud_region = 'us-central1'
# registry_id = 'your-registry-id'
# device_id = 'your-device-id'
client = iot_v1.DeviceManagerClient()
device_path = client.device_path(project_id, cloud_region, registry_id, device_id)

device = client.get_device(request={"name": device_path})
print("Last state: {}".format(device.state))

print("State history")
states = client.list_device_states(request={"name": device_path}).device_states
for state in states:
    print("State: {}".format(state))

return states

Ruby

# project_id  = "Your Google Cloud project ID"
# location_id = "The Cloud region the registry is located in"
# registry_id = "The registry to get device states from"
# device_id   = "The identifier of the device to get states for"

require "google/apis/cloudiot_v1"

# Initialize the client and authenticate with the specified scope
Cloudiot   = Google::Apis::CloudiotV1
iot_client = Cloudiot::CloudIotService.new
iot_client.authorization = Google::Auth.get_application_default(
  "https://www.googleapis.com/auth/cloud-platform"
)

# The resource name of the location associated with the project
parent   = "projects/#{project_id}/locations/#{location_id}"
resource = "#{parent}/registries/#{registry_id}/devices/#{device_id}"

# List the configurations for the provided device
result = iot_client.list_project_location_registry_device_states(
  resource
)
if result.device_states
  result.device_states.each do |state|
    puts "#{state.update_time}: #{state.binary_data}"
  end
else
  puts "No state messages"
end