ควบคุมอุปกรณ์ภายนอก

ใน Android 11 ขึ้นไป ฟีเจอร์การควบคุมอุปกรณ์เข้าถึงด่วน ทำให้ผู้ใช้ดูและควบคุมอุปกรณ์ภายนอก เช่น หลอดไฟ ได้อย่างรวดเร็ว ตัวควบคุมอุณหภูมิ และกล้องจากผู้ใช้ในราคาที่สมเหตุสมผลภายในการโต้ตอบ 3 ครั้งจาก Launcher เริ่มต้น อุปกรณ์ OEM จะเลือก Launcher ที่ใช้ อุปกรณ์ ผู้รวบรวมข้อมูล เช่น Google Home และแอปของผู้ให้บริการบุคคลที่สาม อุปกรณ์สำหรับแสดงในพื้นที่นี้ หน้านี้จะแสดงวิธีการนำเสนอ ระบบควบคุมอุปกรณ์ในพื้นที่ทำงานนี้และลิงก์กับแอปควบคุมของคุณ

รูปที่ 1 พื้นที่ควบคุมอุปกรณ์ใน UI ของ Android

หากต้องการเพิ่มการสนับสนุนนี้ ให้สร้างและประกาศControlsProviderService สร้าง ควบคุมที่แอปของคุณรองรับตามประเภทการควบคุมที่กำหนดไว้ล่วงหน้า จากนั้นสร้าง ผู้เผยแพร่โฆษณาสำหรับการควบคุมเหล่านี้

ส่วนติดต่อผู้ใช้

อุปกรณ์จะปรากฏในส่วนระบบควบคุมอุปกรณ์เป็นวิดเจ็ตแบบเทมเพลต ห้า วิดเจ็ตระบบควบคุมอุปกรณ์ที่พร้อมใช้งาน ตามที่ปรากฏในรูปต่อไปนี้

วันที่ เปิด/ปิดวิดเจ็ต
สลับ
วันที่ สลับด้วยวิดเจ็ตแถบเลื่อน
สลับกับแถบเลื่อน
วันที่ วิดเจ็ตช่วง
ช่วง (เปิดหรือปิดไม่ได้)
วันที่ วิดเจ็ตเปิด/ปิดแบบไม่เก็บสถานะ
สลับแบบไม่เก็บสถานะ
วันที่ วิดเจ็ตแผงอุณหภูมิ (ปิดอยู่)
แผงอุณหภูมิ (ปิด)
รูปที่ 2 คอลเล็กชันวิดเจ็ตที่เป็นเทมเพลต

การแตะและ การกดวิดเจ็ตค้างไว้จะนำคุณไปยังแอปเพื่อให้ควบคุมได้ลึกซึ้งยิ่งขึ้น คุณสามารถ สามารถปรับแต่งไอคอนและสีของแต่ละวิดเจ็ตได้ แต่เพื่อให้ผู้ใช้ได้รับประสบการณ์ที่ดีที่สุด ใช้ไอคอนและสีเริ่มต้นหากชุดเริ่มต้นตรงกับอุปกรณ์

วันที่ รูปภาพแสดงวิดเจ็ตแผงอุณหภูมิ (เปิด)
รูปที่ 3 เปิดวิดเจ็ตแผงอุณหภูมิ

สร้างบริการ

ส่วนนี้จะแสดงวิธีสร้าง ControlsProviderService บริการนี้จะแจ้ง UI ของระบบ Android ว่าแอปของคุณมีการควบคุมอุปกรณ์ ซึ่งต้องแสดงในส่วนระบบควบคุมอุปกรณ์ของ Android UI

ControlsProviderService API มีความคุ้นเคยกับสตรีมเชิงรับ อย่างเช่น ที่กำหนดไว้ใน Reactive Streams GitHub โปรเจ็กต์ และมีการนำไปใช้ใน Java 9 Flow อินเทอร์เฟซ API สร้างขึ้นจากแนวคิดต่อไปนี้

  • ผู้เผยแพร่: แอปพลิเคชันของคุณจะเป็นผู้เผยแพร่
  • สมาชิก: UI ของระบบคือสมาชิกและสามารถขอหมายเลขโทรศัพท์ได้ จากผู้เผยแพร่โฆษณาได้
  • การสมัครใช้บริการ: กรอบเวลาที่ผู้เผยแพร่โฆษณาสามารถส่งการอัปเดตได้ ไปยัง UI ระบบ ผู้เผยแพร่หรือสมาชิกจะปิดข้อความนี้ได้

ประกาศบริการ

แอปของคุณต้องประกาศบริการ เช่น MyCustomControlService ใน ไฟล์ Manifest ของแอป

บริการต้องมีตัวกรอง Intent สำหรับ ControlsProviderService ช่วงเวลานี้ ทำให้แอปพลิเคชันมีส่วนในการควบคุม UI ของระบบ

และต้องมี label ที่แสดงในตัวควบคุมใน UI ของระบบด้วย

ตัวอย่างต่อไปนี้แสดงวิธีประกาศบริการ

<service
    android:name="MyCustomControlService"
    android:label="My Custom Controls"
    android:permission="android.permission.BIND_CONTROLS"
    android:exported="true"
    >
    <intent-filter>
      <action android:name="android.service.controls.ControlsProviderService" />
    </intent-filter>
</service>

จากนั้นสร้างไฟล์ Kotlin ใหม่ชื่อ MyCustomControlService.kt แล้วสร้าง ขยาย ControlsProviderService():

Kotlin

    class MyCustomControlService : ControlsProviderService() {
        ...
    }
    

Java

    public class MyCustomJavaControlService extends ControlsProviderService {
        ...
    }
    

เลือกประเภทการควบคุมที่ถูกต้อง

โดย API จะมีเมธอดของเครื่องมือสร้างเพื่อสร้างการควบคุม หากต้องการป้อนข้อมูล ของเครื่องมือสร้าง ให้กำหนดอุปกรณ์ที่คุณต้องการควบคุมและวิธีการโต้ตอบของผู้ใช้ ด้วย โปรดทำตามขั้นตอนต่อไปนี้

  1. เลือกประเภทของอุปกรณ์ที่ตัวควบคุมจะแสดง ชั้นเรียน DeviceTypes คือ จำนวนอุปกรณ์ที่สนับสนุนทั้งหมด ประเภทจะใช้ในการกำหนด ไอคอนและสีของอุปกรณ์ใน UI
  2. ระบุชื่อที่แสดงต่อผู้ใช้ ตำแหน่งของอุปกรณ์ เช่น Kitchen และองค์ประกอบข้อความของ UI อื่นๆ ที่เชื่อมโยงกับการควบคุม
  3. เลือกเทมเพลตที่ดีที่สุดเพื่อรองรับการโต้ตอบของผู้ใช้ มีการมอบหมายการควบคุม ControlTemplate จากแอปพลิเคชัน เทมเพลตนี้แสดงสถานะการควบคุมโดยตรงต่อ และวิธีการป้อนข้อมูลที่มีอยู่ ซึ่งก็คือ ControlAction ตารางต่อไปนี้จะสรุปเทมเพลตที่ใช้ได้และการทำงานบางส่วน ที่สนับสนุน
เทมเพลต การดำเนินการ คำอธิบาย
ControlTemplate.getNoTemplateObject() None แอปพลิเคชันอาจใช้ข้อมูลนี้เพื่อบอกข้อมูลเกี่ยวกับการควบคุม แต่ผู้ใช้จะโต้ตอบ ด้วยไม่ได้
ToggleTemplate BooleanAction หมายถึงการควบคุมที่สลับระหว่างเปิดใช้และปิดใช้ได้ รัฐ ออบเจ็กต์ BooleanAction มีช่องที่เปลี่ยนแปลง เพื่อแสดงสถานะใหม่ที่ขอเมื่อผู้ใช้แตะตัวควบคุม
RangeTemplate FloatAction แสดงวิดเจ็ตตัวเลื่อนที่มีค่าขั้นต่ำ ค่าสูงสุด และขั้นตอนที่ระบุไว้ วันและเวลา ผู้ใช้โต้ตอบกับแถบเลื่อน แล้วส่ง FloatAction ใหม่ ย้อนกลับไปยังแอปพลิเคชันพร้อมด้วยค่าที่อัปเดตแล้ว
ToggleRangeTemplate BooleanAction, FloatAction เทมเพลตนี้เป็นการรวม ToggleTemplate และ RangeTemplate รองรับกิจกรรมการแตะ รวมถึงแถบเลื่อน เช่น เพื่อควบคุมแสงไฟที่ปรับความสว่างได้
TemperatureControlTemplate ModeAction, BooleanAction, FloatAction นอกจากการสรุปการดำเนินการก่อนหน้านี้แล้ว เทมเพลตนี้ยังทำให้ ผู้ใช้ตั้งค่าโหมด เช่น ทำความร้อน ทำความเย็น ทำความร้อน/ทำความเย็น อีโค หรือปิด
StatelessTemplate CommandAction ใช้เพื่อระบุการควบคุมที่มีความสามารถในการสัมผัส แต่มีสถานะ ไม่สามารถกำหนดได้ เช่น รีโมตทีวี IR คุณใช้ เทมเพลตเพื่อกำหนดกิจวัตรหรือมาโคร ซึ่งเป็นการรวมการควบคุม และการเปลี่ยนแปลงสถานะ

คุณสร้างการควบคุมได้ด้วยข้อมูลนี้

  • ใช้เมนู Control.StatelessBuilder คลาสเครื่องมือสร้างเมื่อไม่ทราบสถานะของตัวควบคุม
  • ใช้เมนู Control.StatefulBuilder คลาสเครื่องมือสร้างเมื่อทราบสถานะของตัวควบคุม

เช่น หากต้องการควบคุมหลอดไฟอัจฉริยะและตัวควบคุมอุณหภูมิ ให้เพิ่มค่าต่อไปนี้ ค่าคงที่ของ MyCustomControlService:

Kotlin

    private const val LIGHT_ID = 1234
    private const val LIGHT_TITLE = "My fancy light"
    private const val LIGHT_TYPE = DeviceTypes.TYPE_LIGHT
    private const val THERMOSTAT_ID = 5678
    private const val THERMOSTAT_TITLE = "My fancy thermostat"
    private const val THERMOSTAT_TYPE = DeviceTypes.TYPE_THERMOSTAT
 
    class MyCustomControlService : ControlsProviderService() {
      ...
    }
    

Java

    public class MyCustomJavaControlService extends ControlsProviderService {
 
    private final int LIGHT_ID = 1337;
    private final String LIGHT_TITLE = "My fancy light";
    private final int LIGHT_TYPE = DeviceTypes.TYPE_LIGHT;
    private final int THERMOSTAT_ID = 1338;
    private final String THERMOSTAT_TITLE = "My fancy thermostat";
    private final int THERMOSTAT_TYPE = DeviceTypes.TYPE_THERMOSTAT;
 
    ...
    }
    

สร้างผู้เผยแพร่โฆษณาสำหรับการควบคุม

หลังจากสร้างการควบคุมแล้ว จะต้องมีผู้เผยแพร่โฆษณา ผู้เผยแพร่โฆษณาแจ้ง UI ของระบบที่มีอยู่ของตัวควบคุม ชั้นเรียน ControlsProviderService มีวิธีการสำหรับผู้เผยแพร่โฆษณา 2 วิธีที่คุณต้องลบล้างในโค้ดแอปพลิเคชัน

  • createPublisherForAllAvailable(): สร้าง Publisher สำหรับการควบคุมทั้งหมดที่พร้อมใช้งานในแอปของคุณ ใช้ Control.StatelessBuilder() เพื่อสร้างออบเจ็กต์ Control รายการสำหรับผู้เผยแพร่โฆษณารายนี้
  • createPublisherFor(): สร้าง Publisher สำหรับรายการควบคุมที่กำหนด ตามที่ระบุโดยตัวระบุสตริง ใช้ Control.StatefulBuilder เพื่อ สร้างวัตถุ Control เหล่านี้ เนื่องจากผู้เผยแพร่โฆษณาต้องกำหนดสถานะให้กับ ตัวควบคุมแต่ละตัว

สร้างผู้เผยแพร่โฆษณา

เมื่อแอปเผยแพร่การควบคุมไปยัง UI ของระบบเป็นครั้งแรก แอปจะไม่ทราบ สถานะของการควบคุมแต่ละรายการ การขอข้อมูลรัฐอาจเป็นการดำเนินการที่ใช้เวลานาน ซึ่งเกี่ยวข้องกับการกระโดดหลายครั้งในเครือข่ายของผู้ให้บริการอุปกรณ์ ใช้เมนู createPublisherForAllAvailable() เพื่อโฆษณาการควบคุมที่ใช้ได้ในระบบ วิธีนี้ใช้เมธอด คลาสเครื่องมือสร้าง Control.StatelessBuilder เนื่องจากสถานะของตัวควบคุมแต่ละรายการคือ ไม่รู้จัก

เมื่อตัวควบคุมปรากฏใน UI ของ Android ผู้ใช้จะเลือกรายการโปรด

หากต้องการใช้โครูทีนของ Kotlin เพื่อสร้าง ControlsProviderService ให้เพิ่ม ขึ้นกับ build.gradle ของคุณ:

ดึงดูด

dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk9:1.6.4"
}

Kotlin

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk9:1.6.4")
}

เมื่อคุณซิงค์ไฟล์ Gradle แล้ว ให้เพิ่มข้อมูลโค้ดต่อไปนี้ลงใน Service เพื่อ ใช้ createPublisherForAllAvailable():

Kotlin

    class MyCustomControlService : ControlsProviderService() {
 
      override fun createPublisherForAllAvailable(): Flow.Publisher =
          flowPublish {
              send(createStatelessControl(LIGHT_ID, LIGHT_TITLE, LIGHT_TYPE))
              send(createStatelessControl(THERMOSTAT_ID, THERMOSTAT_TITLE, THERMOSTAT_TYPE))
          }
 
      private fun createStatelessControl(id: Int, title: String, type: Int): Control {
          val intent = Intent(this, MainActivity::class.java)
              .putExtra(EXTRA_MESSAGE, title)
              .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
          val action = PendingIntent.getActivity(
              this,
              id,
              intent,
              PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
          )
 
          return Control.StatelessBuilder(id.toString(), action)
              .setTitle(title)
              .setDeviceType(type)
              .build()
      }
 
          override fun createPublisherFor(controlIds: List): Flow.Publisher {
           TODO()
        }
 
        override fun performControlAction(
            controlId: String,
            action: ControlAction,
            consumer: Consumer
        ) {
            TODO()
        }
    }
    

Java

    public class MyCustomJavaControlService extends ControlsProviderService {
 
        private final int LIGHT_ID = 1337;
        private final String LIGHT_TITLE = "My fancy light";
        private final int LIGHT_TYPE = DeviceTypes.TYPE_LIGHT;
        private final int THERMOSTAT_ID = 1338;
        private final String THERMOSTAT_TITLE = "My fancy thermostat";
        private final int THERMOSTAT_TYPE = DeviceTypes.TYPE_THERMOSTAT;
 
        private boolean toggleState = false;
        private float rangeState = 18f;
        private final Map<String, ReplayProcessor> controlFlows = new HashMap<>();
 
        @NonNull
        @Override
        public Flow.Publisher createPublisherForAllAvailable() {
            List controls = new ArrayList<>();
            controls.add(createStatelessControl(LIGHT_ID, LIGHT_TITLE, LIGHT_TYPE));
            controls.add(createStatelessControl(THERMOSTAT_ID, THERMOSTAT_TITLE, THERMOSTAT_TYPE));
            return FlowAdapters.toFlowPublisher(Flowable.fromIterable(controls));
        }
 
        @NonNull
        @Override
        public Flow.Publisher createPublisherFor(@NonNull List controlIds) {
            ReplayProcessor updatePublisher = ReplayProcessor.create();
 
            controlIds.forEach(control -> {
                controlFlows.put(control, updatePublisher);
                updatePublisher.onNext(createLight());
                updatePublisher.onNext(createThermostat());
            });
 
            return FlowAdapters.toFlowPublisher(updatePublisher);
        }
    }
    

ปัดเมนูระบบลง แล้วหาปุ่มระบบควบคุมอุปกรณ์ที่แสดงใน รูปที่ 4:

วันที่ รูปภาพแสดง UI ของระบบสำหรับระบบควบคุมอุปกรณ์
รูปที่ 4 ระบบควบคุมอุปกรณ์ในเมนูระบบ

การแตะระบบควบคุมอุปกรณ์จะไปยังหน้าจอที่ 2 ซึ่งคุณสามารถเลือก แอปของคุณ เมื่อเลือกแอปแล้ว คุณจะเห็นว่าข้อมูลโค้ดก่อนหน้าสร้าง เมนูระบบที่กำหนดเองซึ่งแสดงการควบคุมใหม่ของคุณดังในรูปที่ 5:

วันที่ รูปภาพแสดงเมนูระบบที่มีการควบคุมแสงไฟและตัวควบคุมอุณหภูมิ
รูปที่ 5 ควบคุมแสงสว่างและตัวควบคุมอุณหภูมิเพื่อเพิ่ม

ตอนนี้ ให้ใช้เมธอด createPublisherFor() โดยเพิ่มข้อมูลต่อไปนี้ลงใน Service:

Kotlin

    private val job = SupervisorJob()
    private val scope = CoroutineScope(Dispatchers.IO + job)
    private val controlFlows = mutableMapOf<String, MutableSharedFlow>()
 
    private var toggleState = false
    private var rangeState = 18f
 
    override fun createPublisherFor(controlIds: List): Flow.Publisher {
        val flow = MutableSharedFlow(replay = 2, extraBufferCapacity = 2)
 
        controlIds.forEach { controlFlows[it] = flow }
 
        scope.launch {
            delay(1000) // Retrieving the toggle state.
            flow.tryEmit(createLight())
 
            delay(1000) // Retrieving the range state.
            flow.tryEmit(createThermostat())
 
        }
        return flow.asPublisher()
    }
 
    private fun createLight() = createStatefulControl(
        LIGHT_ID,
        LIGHT_TITLE,
        LIGHT_TYPE,
        toggleState,
        ToggleTemplate(
            LIGHT_ID.toString(),
            ControlButton(
                toggleState,
                toggleState.toString().uppercase(Locale.getDefault())
            )
        )
    )
 
    private fun createThermostat() = createStatefulControl(
        THERMOSTAT_ID,
        THERMOSTAT_TITLE,
        THERMOSTAT_TYPE,
        rangeState,
        RangeTemplate(
            THERMOSTAT_ID.toString(),
            15f,
            25f,
            rangeState,
            0.1f,
            "%1.1f"
        )
    )
 
    private fun  createStatefulControl(id: Int, title: String, type: Int, state: T, template: ControlTemplate): Control {
        val intent = Intent(this, MainActivity::class.java)
            .putExtra(EXTRA_MESSAGE, "$title $state")
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        val action = PendingIntent.getActivity(
            this,
            id,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
 
        return Control.StatefulBuilder(id.toString(), action)
            .setTitle(title)
            .setDeviceType(type)
            .setStatus(Control.STATUS_OK)
            .setControlTemplate(template)
            .build()
    }
 
    override fun onDestroy() {
        super.onDestroy()
        job.cancel()
    }
 
    

Java

    @NonNull
    @Override
    public Flow.Publisher createPublisherFor(@NonNull List controlIds) {
        ReplayProcessor updatePublisher = ReplayProcessor.create();
 
        controlIds.forEach(control -> {
            controlFlows.put(control, updatePublisher);
            updatePublisher.onNext(createLight());
            updatePublisher.onNext(createThermostat());
        });
 
        return FlowAdapters.toFlowPublisher(updatePublisher);
    }
 
    private Control createStatelessControl(int id, String title, int type) {
        Intent intent = new Intent(this, MainActivity.class)
                .putExtra(EXTRA_MESSAGE, title)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent action = PendingIntent.getActivity(
                this,
                id,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
        );
 
        return new Control.StatelessBuilder(id + "", action)
                .setTitle(title)
                .setDeviceType(type)
                .build();
    }
 
    private Control createLight() {
        return createStatefulControl(
                LIGHT_ID,
                LIGHT_TITLE,
                LIGHT_TYPE,
                toggleState,
                new ToggleTemplate(
                        LIGHT_ID + "",
                        new ControlButton(
                                toggleState,
                                String.valueOf(toggleState).toUpperCase(Locale.getDefault())
                        )
                )
        );
    }
 
    private Control createThermostat() {
        return createStatefulControl(
                THERMOSTAT_ID,
                THERMOSTAT_TITLE,
                THERMOSTAT_TYPE,
                rangeState,
                new RangeTemplate(
                        THERMOSTAT_ID + "",
                        15f,
                        25f,
                        rangeState,
                        0.1f,
                        "%1.1f"
                )
        );
    }
 
    private  Control createStatefulControl(int id, String title, int type, T state, ControlTemplate template) {
        Intent intent = new Intent(this, MainActivity.class)
                .putExtra(EXTRA_MESSAGE, "$title $state")
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent action = PendingIntent.getActivity(
                this,
                id,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
        );
 
        return new Control.StatefulBuilder(id + "", action)
                .setTitle(title)
                .setDeviceType(type)
                .setStatus(Control.STATUS_OK)
                .setControlTemplate(template)
                .build();
    }
    

ในตัวอย่างนี้ เมธอด createPublisherFor() มีแท็กปลอม ว่าแอปของคุณต้องทำอย่างไรบ้าง: สื่อสารกับอุปกรณ์เพื่อ เรียกสถานะ และแสดงสถานะนั้นในระบบ

เมธอด createPublisherFor() ใช้โครูทีนของ Kotlin และโฟลว์การตอบสนอง Reactive Streams API ที่จำเป็นโดยทำตามขั้นตอนต่อไปนี้

  1. สร้าง Flow
  2. รอ 1 วินาที
  3. สร้างและปล่อยสถานะของหลอดไฟอัจฉริยะ
  4. รออีกวินาที
  5. สร้างและปล่อยสถานะของตัวควบคุมอุณหภูมิ

จัดการ

เมธอด performControlAction() จะส่งสัญญาณเมื่อผู้ใช้โต้ตอบกับ ตัวควบคุมที่เผยแพร่ ประเภทของ ControlAction ที่ส่งจะเป็นตัวกำหนดการดำเนินการ ดำเนินการที่เหมาะสมกับการควบคุมนั้นๆ แล้วอัปเดตสถานะ ของอุปกรณ์ใน UI ของ Android

หากต้องการทำให้ตัวอย่างเสร็จสมบูรณ์ ให้เพิ่มรายการต่อไปนี้ลงใน Service ของคุณ

Kotlin

    override fun performControlAction(
        controlId: String,
        action: ControlAction,
        consumer: Consumer
    ) {
        controlFlows[controlId]?.let { flow ->
            when (controlId) {
                LIGHT_ID.toString() -> {
                    consumer.accept(ControlAction.RESPONSE_OK)
                    if (action is BooleanAction) toggleState = action.newState
                    flow.tryEmit(createLight())
                }
                THERMOSTAT_ID.toString() -> {
                    consumer.accept(ControlAction.RESPONSE_OK)
                    if (action is FloatAction) rangeState = action.newValue
                    flow.tryEmit(createThermostat())
                }
                else -> consumer.accept(ControlAction.RESPONSE_FAIL)
            }
        } ?: consumer.accept(ControlAction.RESPONSE_FAIL)
    }
    

Java

    @Override
    public void performControlAction(@NonNull String controlId, @NonNull ControlAction action, @NonNull Consumer consumer) {
        ReplayProcessor processor = controlFlows.get(controlId);
        if (processor == null) return;
 
        if (controlId.equals(LIGHT_ID + "")) {
            consumer.accept(ControlAction.RESPONSE_OK);
            if (action instanceof BooleanAction) toggleState = ((BooleanAction) action).getNewState();
            processor.onNext(createLight());
        }
        if (controlId.equals(THERMOSTAT_ID + "")) {
            consumer.accept(ControlAction.RESPONSE_OK);
            if (action instanceof FloatAction) rangeState = ((FloatAction) action).getNewValue()
            processor.onNext(createThermostat());
        }
    }
    

เรียกใช้แอป เข้าถึงเมนูการควบคุมอุปกรณ์ และดูหลอดไฟและ การควบคุมของตัวควบคุมอุณหภูมิ

วันที่ รูปภาพแสดงการควบคุมแสงไฟและตัวควบคุมอุณหภูมิ
รูปที่ 6 การควบคุมแสงสว่างและตัวควบคุมอุณหภูมิ