matter create a virtual device and make an open source contribution objective learn how to create a matter virtual device, which you can control using the smartthings app also, know how to contribute your code to matter open source overview matter is an open-source connectivity standard for smart home and internet of things iot devices it is a secure, reliable, and seamless cross-platform protocol for connecting compatible devices and systems with one another smartthings provides the matter virtual device app and smartthings home apis to help you quickly develop matter devices and use the smartthings ecosystem without needing to build your own iot ecosystem you can use smartthings home apis to onboard, control, remove, and share all matter devices when building your application other iot ecosystems can use the matter devices onboarded on your iot app through the multi-admin function notethis code lab focuses only on creating a matter virtual device you can control using the smartthings app to learn how to make your controller app, see build a matter iot app with smartthings home apis for detailed information, go to partners smartthings com/matter set up your environment you will need the following host pc running on windows 10 or higher or ubuntu 20 04 x64 android studio latest version recommended java se development kit jdk 11 or later devices connected on the same network mobile device with android 8 0 oreo or higher operating system os mobile device with smartthings app installed matter-enabled smartthings station onboarded with samsung account used for smartthings app initial setup turn on developer mode and enable usb debugging option on your mobile device install a few os-specific dependencies by entering the below command in your terminal window $ sudo apt-get install git gcc g++ pkg-config libssl-dev libdbus-1-dev \ libglib2 0-dev libavahi-client-dev ninja-build python3-venv python3-dev \ python3-pip unzip libgirepository1 0-dev libcairo2-dev libreadline-dev to build the matter virtual device app, install sdk platform 26 and ndk version 22 1 7171670 using sdk manager in android studio after installing ndk, register the ndk path to the env path export android_ndk_home=[ndk path] export path=$path ${android_ndk_home} install kotlin compiler kotlinc version 1 5 10 after installing kotlinc, register the kotlinc path to the env path export kotlinc_home=[kotlinc path]/bin export path=$path ${kotlinc_home} sample code here is a sample code for you to start coding in this codelab download it and start your learning experience! matter virtual device sample code 11 42 mb start your project after downloading the sample code containing the project files, open your android studio and click open to open an existing project locate the downloaded android project from the directory and click ok select and create the device type when you build and run the sample matter virtual device app, you can see the already added on/off switch aside from the switch, other types of devices you can create are already prepared in the sample app noterefer to the matter device library specification for the list of matter devices you can create go to feature > main > java > com matter virtual device app feature main in the mainfragment kt file, select the device type you want to create mainuistate start -> { // =================================================================================== // codelab // todo uncomment the following lines to add your own device type // ----------------------------------------------------------------------------------- val itemlist = listof device onoffswitch, // sample // device occupancysensor, // level 1 8+ mins // device contactsensor, // level 2 8+ mins // device videoplayer, // level 2 10+ mins // device doorlock, // level 3 15+ mins // device extendedcolorlight, // level 3 15+ mins // device windowcovering, // level 4 17+ mins // device thermostat, // level 5 20+ mins // =================================================================================== depending on the device type you selected at this step, the part you need to modify at the next step will vary the level of modification complexity is assigned per each device get cluster value clusters are the functional building block elements of the data model a cluster can be an interface, a service, or an object class, and it is the lowest independent functional element in the data model a matter device supports a set of appropriate clusters, which can interact with your preferred controller such as smartthings this allows for easy information retrieval, behavior setting, event notifications, and more through the viewmodel, get the value of the cluster used in the device you created noteto learn more about clusters, see matter application cluster specification occupancy sensorlevel 1 file path feature > sensor > java > com matter virtual device app feature sensor file name occupancysensorviewmodel kt // =================================================================================== // codelab level 1 // the current status of the occupancy the boolean value is used by the [occupancyfragment] // to react to update ui // todo 1 uncomment the following code blocks // ----------------------------------------------------------------------------------- //private val _occupancy stateflow<boolean> = getoccupancyflowusecase //val occupancy livedata<boolean> // get = _occupancy aslivedata // =================================================================================== // =================================================================================== // codelab level 1 // the current status of the battery the int value is used by the [occupancyfragment] // to react to update fragment's ui // todo 2 uncomment the following code blocks // ----------------------------------------------------------------------------------- //private val _batterystatus mutablestateflow<int> = // getbatpercentremainingusecase as mutablestateflow<int> //val batterystatus livedata<int> // get = _batterystatus aslivedata // =================================================================================== // =================================================================================== // codelab level 1 // triggered by the "occupancy" button in the [occupancyfragment] // [setoccupancyusecase] will update the boolean value of the new occupancy status // todo 3 uncomment the following code blocks // ----------------------------------------------------------------------------------- //viewmodelscope launch { // timber d "current value = ${_occupancy value}" // if _occupancy value { // timber d "set value = false" // setoccupancyusecase false // } else { // timber d "set value = true" // setoccupancyusecase true // } //} // =================================================================================== // =================================================================================== // codelab level 1 // triggered by the "battery" seekbar in the [occupancyfragment] // [batterystatus] store the current status of the battery to indicate the progress // todo 4 uncomment the following code blocks // ----------------------------------------------------------------------------------- //_batterystatus value = progress // =================================================================================== // =================================================================================== // codelab level 1 // triggered by the "battery" seekbar in the [occupancyfragment] // [updatebatteryseekbarprogress] update the current status of the battery to indicate the // progress // [setbatpercentremainingusecase] will update the int value of the new battery status // todo 5 uncomment the following code blocks // ----------------------------------------------------------------------------------- //viewmodelscope launch { // updatebatteryseekbarprogress progress // setbatpercentremainingusecase progress //} // =================================================================================== contact sensorlevel 2 file path feature > sensor > java > com matter virtual device app feature sensor file name contactsensorviewmodel kt // =================================================================================== // codelab level 2 // the current status of the contact the boolean value is used by the [contactsensorfragment] // to react to update ui // todo 1 uncomment the following code blocks // ----------------------------------------------------------------------------------- //private val _statevalue stateflow<boolean> = getstatevalueflowusecase //val statevalue livedata<boolean> // get = _statevalue aslivedata // =================================================================================== // =================================================================================== // codelab level 2 // the current status of the battery the int value is used by the [contactsensorfragment] // to react to update fragment's ui // todo 2 uncomment the following code blocks // ----------------------------------------------------------------------------------- //private val _batterystatus mutablestateflow<int> = // getbatpercentremainingusecase as mutablestateflow<int> //val batterystatus livedata<int> // get = _batterystatus aslivedata // =================================================================================== // =================================================================================== // codelab level 2 // triggered by the "contact" button in the [contactsensorfragment] // [setstatevalueusecase] will update the boolean value of the new contact status // todo 3 uncomment the following code blocks // ----------------------------------------------------------------------------------- //viewmodelscope launch { // timber d "current value = ${_statevalue value}" // if _statevalue value { // timber d "set value = false" // setstatevalueusecase false // } else { // timber d "set value = true" // setstatevalueusecase true // } //} // =================================================================================== // =================================================================================== // codelab level 2 // triggered by the "battery" seekbar in the [contactsensorfragment] // [batterystatus] store the current status of the battery to indicate the progress // todo 4 uncomment the following code blocks // ----------------------------------------------------------------------------------- //_batterystatus value = progress // =================================================================================== // =================================================================================== // codelab level 2 // triggered by the "battery" seekbar in the [contactsensorfragment] // [updatebatteryseekbarprogress] update the current status of the battery to indicate the // progress // [setbatpercentremainingusecase] will update the int value of the new battery status // todo 5 uncomment the following code blocks // ----------------------------------------------------------------------------------- //viewmodelscope launch { // updatebatteryseekbarprogress progress // setbatpercentremainingusecase progress //} // =================================================================================== video playerlevel 2 file path feature > media > java > com matter virtual device app feature media file name videoplayerviewmodel kt // =================================================================================== // codelab level 2 // the current status of the on/off the boolean value is used by the [videoplayerfragment] // to react to update fragment's ui // todo 1 uncomment the following code blocks // ----------------------------------------------------------------------------------- //private val _onoff stateflow<boolean> = getonoffflowusecase //val onoff livedata<boolean> // get = _onoff aslivedata // =================================================================================== // =================================================================================== // codelab level 2 // the current status of the playback state the int value is used by the [videoplayerfragment] // to react to update fragment's ui // todo 2 uncomment the following code blocks // ----------------------------------------------------------------------------------- //private val _playbackstate stateflow<int> = getplaybackstateflowusecase //val playbackstate livedata<int> // get = _playbackstate aslivedata // =================================================================================== // =================================================================================== // codelab level 2 // the current status of the playback speed the int value is used by the [videoplayerfragment] // to react to update fragment's ui // todo 3 uncomment the following code blocks // ----------------------------------------------------------------------------------- //private val _playbackspeed stateflow<int> = getplaybackspeedflowusecase //val playbackspeed livedata<int> // get = _playbackspeed aslivedata // =================================================================================== // =================================================================================== // codelab level 2 // the current status of the key code the enum value is used by the [videoplayerfragment] // to react to update fragment's ui // todo 4 uncomment the following code blocks // ----------------------------------------------------------------------------------- //private val _keycode stateflow<keycode> = getkeycodestateflowusecase //val keycode livedata<keycode> // get = _keycode aslivedata // =================================================================================== // =================================================================================== // codelab level 2 // triggered by the "on/off" button in the [videoplayerfragment] // [setonoffusecase] will update the boolean value of the new on/off status // todo 5 uncomment the following code blocks // ----------------------------------------------------------------------------------- //viewmodelscope launch { // timber d "current value = ${_onoff value}" // if _onoff value { // timber d "set value = false" // setonoffusecase false // } else { // timber d "set value = true" // setonoffusecase true // } //} // =================================================================================== door locklevel 3 file path feature > closure > java > com matter virtual device app feature closure file name doorlockviewmodel kt // =================================================================================== // codelab level 3 // the current status of the lock the boolean value is used by the [doorlockfragment] // to react to update fragment's ui // ----------------------------------------------------------------------------------- // todo 1 copy code below private val _lockstate stateflow<boolean> = getlockstateflowusecase val lockstate livedata<boolean> get = _lockstate aslivedata // ============================================================================== // =================================================================================== // codelab level 3 // the current status of the battery the int value is used by the [doorlockfragment] // to react to update fragment's ui // ----------------------------------------------------------------------------------- // todo 2 copy code below private val _batterystatus mutablestateflow<int> = getbatpercentremainingusecase as mutablestateflow<int> val batterystatus livedata<int> get = _batterystatus aslivedata // ============================================================================== // =================================================================================== // codelab level 3 // triggered by the "lock" button in the [doorlockfragment] // [setlockstateusecase] will update the boolean value of the new lock status // ----------------------------------------------------------------------------------- // todo 3 copy code below viewmodelscope launch { timber d "current lockstate value = ${_lockstate value}" if _lockstate value == lock_state_locked { timber d "set value = unlocked" setlockstateusecase lock_state_unlocked } else { timber d "set value = locked" setlockstateusecase lock_state_locked } } // ============================================================================== // =================================================================================== // codelab level 3 // triggered by the "send alarm" button in the [doorlockfragment] // [sendlockalarmeventusecase] will send alarm event // [setlockstateusecase] will update the boolean value of the unlock status // ----------------------------------------------------------------------------------- // todo 4 copy code below viewmodelscope launch { if !_lockstate value { // if lockstate == locked, send alarm event and change the lockstate to unlocked sendlockalarmeventusecase setlockstateusecase lock_state_unlocked } } // ============================================================================== // =================================================================================== // codelab level 3 // triggered by the "battery" seekbar in the [doorlockfragment] // [batterystatus] store the current status of the battery to indicate the progress // ----------------------------------------------------------------------------------- // todo 5 copy code below _batterystatus value = progress // ============================================================================== // =================================================================================== // codelab level 3 // triggered by the "battery" seekbar in the [doorlockfragment] // [updatebatteryseekbarprogress] update the current status of the battery to indicate the // progress // [setbatpercentremainingusecase] will update the int value of the new battery status // ----------------------------------------------------------------------------------- // todo 6 copy code below viewmodelscope launch { updatebatteryseekbarprogress progress setbatpercentremainingusecase progress } // ============================================================================== extended color lightlevel 3 file path feature > lighting > java > com matter virtual device app feature lighting file name extendedcolorlightviewmodel kt // =================================================================================== // codelab level 3 // the current status of the on/off the boolean value is used by the [extendedcolorlightfragment] // to react to update ui // ----------------------------------------------------------------------------------- // todo 1 copy code below private val _onoff stateflow<boolean> = getonoffflowusecase val onoff livedata<boolean> get = _onoff aslivedata // =================================================================================== // =================================================================================== // codelab level 3 // the current status of the color level the int value is used by the // [extendedcolorlightfragment] // to react to update ui // ----------------------------------------------------------------------------------- // todo 2 copy code below private val _level stateflow<int> = getlevelflowusecase val level livedata<int> get = _level aslivedata // =================================================================================== // =================================================================================== // codelab level 3 // the current status of the color the enum value is used by the [extendedcolorlightfragment] // to react to update ui // ----------------------------------------------------------------------------------- // todo 3 copy code below private val _currenthue stateflow<int> = getcurrenthueflowusecase private val _currentsaturation stateflow<int> = getcurrentsaturationflowusecase val currentcolor livedata<hsvcolor> = combine _currenthue, _currentsaturation { currenthue, currentsaturation -> hsvcolor currenthue, currentsaturation } aslivedata // =================================================================================== // =================================================================================== // codelab level 3 // the current status of the color temperature the int value is used by the // [extendedcolorlightfragment] // to react to update ui // ----------------------------------------------------------------------------------- // todo 4 copy code below private val _colortemperature stateflow<int> = getcolortemperatureflowusecase val colortemperature livedata<int> get = _colortemperature aslivedata // =================================================================================== // =================================================================================== // codelab level 3 // triggered by the "on/off" button in the [extendedcolorlightfragment] // [setonoffusecase] will update the boolean value of the new on/off status // ----------------------------------------------------------------------------------- // todo 5 copy code below viewmodelscope launch { timber d "current value = ${_onoff value}" if _onoff value { timber d "set value = false" setonoffusecase false } else { timber d "set value = true" setonoffusecase true } } // =================================================================================== window coveringlevel 4 file path feature > closure > java > com matter virtual device app feature closure file name windowcoveringviewmodel kt // =================================================================================== // codelab level 4 // the current status of the position/operation the enum value is used by the // [windowcoveringfragment] // to react to update fragment's ui // ----------------------------------------------------------------------------------- // todo 1 copy code below val windowcoveringstatus livedata<windowcoveringstatus> = combine _currentposition, _operationalstatus { currentposition, operationalstatus -> windowcoveringstatus currentposition, operationalstatus } aslivedata // =================================================================================== // =================================================================================== // codelab level 4 // the current status of the battery the int value is used by the [windowcoveringfragment] // to react to update fragment's ui // ----------------------------------------------------------------------------------- // todo 2 copy code below private val _batterystatus mutablestateflow<int> = getbatpercentremainingusecase as mutablestateflow<int> val batterystatus livedata<int> get = _batterystatus aslivedata // =================================================================================== // =================================================================================== // codelab level 4 // triggered by the "windowshade" seekbar in the [windowcoveringfragment] // [settargetpositionusecase] will update the int value of the new target position status // ----------------------------------------------------------------------------------- // todo 3 copy code below viewmodelscope launch { timber d "target position = $percentage" settargetpositionusecase percentage } // =================================================================================== // =================================================================================== // codelab level 4 // triggered by the "open" button in the [fragment_window_covering xml] // [settargetpositionusecase] will update the int value of the open position 100 status // ----------------------------------------------------------------------------------- // todo 4 copy code below viewmodelscope launch { timber d "target position = 100" settargetpositionusecase 100 } // =================================================================================== // =================================================================================== // codelab level 4 // triggered by the "close" button in the [fragment_window_covering xml] // [settargetpositionusecase] will update the int value of the close position 0 status // ----------------------------------------------------------------------------------- // todo 5 copy code below viewmodelscope launch { settargetpositionusecase 0 } // =================================================================================== // =================================================================================== // codelab level 4 // triggered by the "pause" button in the [fragment_window_covering xml] // [settargetpositionusecase] will update the int value of the pause position status // ----------------------------------------------------------------------------------- // todo 6 copy code below viewmodelscope launch { timber d "current position = ${_currentposition value}, target position ${_targetposition value}" if _currentposition value != _targetposition value { settargetpositionusecase _currentposition value } } // =================================================================================== // =================================================================================== // codelab level 4 // triggered by the "battery" seekbar in the [windowcoveringfragment] // [batterystatus] store the current status of the battery to indicate the progress // ----------------------------------------------------------------------------------- // todo 7 copy code below _batterystatus value = progress // =================================================================================== // =================================================================================== // codelab level 4 // triggered by the "battery" seekbar in the [windowcoveringfragment] // [updatebatteryseekbarprogress] update the current status of the battery to indicate the // progress // [setbatpercentremainingusecase] will update the int value of the new battery status // ----------------------------------------------------------------------------------- // todo 8 copy code below viewmodelscope launch { updatebatteryseekbarprogress progress setbatpercentremainingusecase progress } // =================================================================================== thermostatlevel 5 file path feature > hvac > java > com matter virtual device app feature hvac file name thermostatviewmodel kt // =================================================================================== // codelab level 5 // the current status of the temperature the int value is used by the [thermostatfragment] // to react to update fragment's ui // ----------------------------------------------------------------------------------- // todo 1 copy code below private val _temperature mutablestateflow<int> = getlocaltemperatureusecase as mutablestateflow<int> val temperature livedata<int> get = _temperature aslivedata // =================================================================================== // =================================================================================== // codelab level 5 // the current status of the humidity the int value is used by the [thermostatfragment] // to react to update fragment's ui // ----------------------------------------------------------------------------------- // todo 2 copy code below private val _humidity mutablestateflow<int> = getrelativehumidityusecase as mutablestateflow<int> val humidity livedata<int> get = _humidity aslivedata // =================================================================================== // =================================================================================== // codelab level 5 // the current status of the system mode the enum value is used by the [thermostatfragment] // to react to update fragment's ui // ----------------------------------------------------------------------------------- // todo 3 copy code below private val _systemmode stateflow<thermostatsystemmode> = getsystemmodeflowusecase val systemmode livedata<thermostatsystemmode> get = _systemmode aslivedata // =================================================================================== // =================================================================================== // codelab level 5 // the current status of the fan mode the enum value is used by the [thermostatfragment] // to react to update fragment's ui // ----------------------------------------------------------------------------------- // todo 4 copy code below private val _fanmode stateflow<fancontrolfanmode> = getfanmodeflowusecase val fanmode livedata<fancontrolfanmode> get = _fanmode aslivedata // =================================================================================== // =================================================================================== // codelab level 5 // the current status of the cooling setpoint the int value is used by the [thermostatfragment] // to react to update fragment's ui // ----------------------------------------------------------------------------------- // todo 5 copy code below private val _occupiedcoolingsetpoint stateflow<int> = getoccupiedcoolingsetpointflowusecase val occupiedcoolingsetpoint livedata<int> get = _occupiedcoolingsetpoint aslivedata // =================================================================================== // =================================================================================== // codelab level 5 // the current status of the heating setpoint the int value is used by the [thermostatfragment] // to react to update fragment's ui // ----------------------------------------------------------------------------------- // todo 6 copy code below private val _occupiedheatingsetpoint stateflow<int> = getoccupiedheatingsetpointflowusecase val occupiedheatingsetpoint livedata<int> get = _occupiedheatingsetpoint aslivedata // =================================================================================== // =================================================================================== // codelab level 5 // the current status of the battery the int value is used by the [thermostatfragment] // to react to update fragment's ui // ----------------------------------------------------------------------------------- // todo 7 copy code below private val _batterystatus mutablestateflow<int> = getbatpercentremainingusecase as mutablestateflow<int> val batterystatus livedata<int> get = _batterystatus aslivedata // =================================================================================== // =================================================================================== // codelab level 5 // triggered by the "humidity" seekbar in the [thermostatfragment] // [humidity] store the current status of the humidity to indicate the progress // ----------------------------------------------------------------------------------- // todo 8 copy code below _humidity value = progress * 100 // =================================================================================== // =================================================================================== // codelab level 5 // triggered by the "humidity" seekbar in the [thermostatfragment] // [updatehumidityseekbarprogress] update the current status of the humidity to indicate the // progress // [setrelativehumidityusecase] will update the int value of the new humidity status [0 100] // * 100 // ----------------------------------------------------------------------------------- // todo 9 copy code below viewmodelscope launch { updatehumidityseekbarprogress progress setrelativehumidityusecase progress * 100 } // =================================================================================== // =================================================================================== // codelab level 5 // triggered by the "temperature" seekbar in the [thermostatfragment] // [temperature] store the current status of the temperature to indicate the progress // ----------------------------------------------------------------------------------- // todo 10 copy code below _temperature value = progress * 100 // =================================================================================== // =================================================================================== // codelab level 5 // triggered by the "temperature" seekbar in the [thermostatfragment] // [updatetemperatureseekbarprogress] update the current status of the temperature to indicate // the progress // [setlocaltemperatureusecase] will update the int value of the new temperature status // [value] * 100 // ----------------------------------------------------------------------------------- // todo 11 copy code below viewmodelscope launch { updatetemperatureseekbarprogress progress setlocaltemperatureusecase progress * 100 } // ==================================================================================== // =================================================================================== // codelab level 5 // triggered by the "battery" seekbar in the [thermostatfragment] // [batterystatus] store the current status of the battery to indicate the progress // ----------------------------------------------------------------------------------- // todo 12 copy code below _batterystatus value = progress // ==================================================================================== // =================================================================================== // codelab level 5 // triggered by the "battery" seekbar in the [thermostatfragment] // [updatebatteryseekbarprogress] update the current status of the battery to indicate the // progress // [setbatpercentremainingusecase] will update the int value of the new battery status // ----------------------------------------------------------------------------------- // todo 13 copy code below viewmodelscope launch { updatebatteryseekbarprogress progress setbatpercentremainingusecase progress } // ==================================================================================== // =================================================================================== // codelab level 5 // triggered by the "systemmode" popup in the [thermostatfragment] // [setsystemmodeusecase] will update the enum value of the new system mode status // ----------------------------------------------------------------------------------- // todo 14 copy code below viewmodelscope launch { setsystemmodeusecase systemmode } // ==================================================================================== // =================================================================================== // codelab level 5 // triggered by the "fanmode" popup in the [thermostatfragment] // [setfanmodeusecase] will update the enum value of the new fan mode status // ----------------------------------------------------------------------------------- // todo 15 copy code below viewmodelscope launch { setfanmodeusecase fanmode } // ==================================================================================== // =================================================================================== // codelab level 5 // triggered by the "heating plus" button in the [fragment_thermostat xml] // [setoccupiedheatingsetpointusecase] will update the int value of the +1 degree [degree] * // 100 // ----------------------------------------------------------------------------------- // todo 16 copy code below viewmodelscope launch { val nextvalue = _occupiedheatingsetpoint value + 100 timber d "current value = ${_occupiedheatingsetpoint value} set value = $nextvalue" setoccupiedheatingsetpointusecase nextvalue } // ==================================================================================== // =================================================================================== // codelab level 5 // triggered by the "heating minus" button in the [fragment_thermostat xml] // [setoccupiedheatingsetpointusecase] will update the int value of the -1 degree [degree] * // 100 // ----------------------------------------------------------------------------------- // todo 17 copy code below viewmodelscope launch { val nextvalue = _occupiedheatingsetpoint value - 100 timber d "current value = ${_occupiedheatingsetpoint value} set value = $nextvalue" setoccupiedheatingsetpointusecase nextvalue } // ==================================================================================== // =================================================================================== // codelab level 5 // triggered by the "cooling plus" button in the [fragment_thermostat xml] // [setoccupiedcoolingsetpointusecase] will update the int value of the +1 degree [degree] * // 100 // ----------------------------------------------------------------------------------- // todo 18 copy code below viewmodelscope launch { val nextvalue = _occupiedcoolingsetpoint value + 100 timber d "current value = ${_occupiedcoolingsetpoint value} set value = $nextvalue" setoccupiedcoolingsetpointusecase nextvalue } // ==================================================================================== // =================================================================================== // codelab level 5 // triggered by the "cooling minus" button in the [fragment_thermostat xml] // [setoccupiedcoolingsetpointusecase] will update the int value of the -1 degree [degree] * // 100 // ----------------------------------------------------------------------------------- // todo 19 copy code below viewmodelscope launch { val nextvalue = _occupiedcoolingsetpoint value - 100 timber d "current value = ${_occupiedcoolingsetpoint value} set value = $nextvalue" setoccupiedcoolingsetpointusecase nextvalue } // ==================================================================================== noteyou can find related files in android studio by going to edit menu> find > find in files and entering the keyword "codelab" observe cluster value next, use the observe function to keep track whenever there is a change in the cluster value occupancy sensorlevel 1 file path feature > sensor > java > com matter virtual device app feature sensor file name occupancysensorfragment kt // =================================================================================== // codelab level 1 // trigger the processing for updating new occupancy state of the virtual device // todo 1 uncomment the following code blocks // ----------------------------------------------------------------------------------- //binding occupancybutton setonclicklistener { viewmodel onclickbutton } // =================================================================================== // =================================================================================== // codelab level 1 // [onprogresschanged] will update the fragment's ui via viewmodel livedata // [onstoptrackingtouch] will trigger the processing for updating new battery state of the // virtual device // todo 2 uncomment the following code blocks // ----------------------------------------------------------------------------------- //binding occupancysensorbatterylayout titletext text = getstring r string battery //binding occupancysensorbatterylayout seekbardata = // seekbardata progress = viewmodel batterystatus //binding occupancysensorbatterylayout seekbar setonseekbarchangelistener // object seekbar onseekbarchangelistener { // override fun onprogresschanged seekbar seekbar, progress int, fromuser boolean { // viewmodel updatebatteryseekbarprogress progress // } // // override fun onstarttrackingtouch seekbar seekbar {} // // override fun onstoptrackingtouch seekbar seekbar { // viewmodel updatebatterystatustocluster seekbar progress // } // } // // =================================================================================== // =================================================================================== // codelab level 1 // observer on the current occupancy status and react on the fragment's ui // todo 3 uncomment the following code blocks // ----------------------------------------------------------------------------------- //viewmodel occupancy observe viewlifecycleowner { // if it { // binding occupancyvaluetext text = getstring r string occupancy_state_occupied // binding occupancybutton setimageresource r drawable ic_occupied // } else { // binding occupancyvaluetext text = getstring r string occupancy_state_unoccupied // binding occupancybutton setimageresource r drawable ic_unoccupied // } //} // =================================================================================== // =================================================================================== // codelab level 1 // observer on the current battery status and react on the fragment's ui // todo 4 uncomment the following code blocks // ----------------------------------------------------------------------------------- //viewmodel batterystatus observe viewlifecycleowner { // val text string = getstring r string battery_format, it // binding occupancysensorbatterylayout valuetext text = // html fromhtml text, html from_html_mode_legacy //} // =================================================================================== contact sensorlevel 2 file path feature > sensor > java > com matter virtual device app feature sensor file name contactsensorfragment kt // =================================================================================== // codelab level 2 // trigger the processing for updating new contact state of the virtual device // todo 1 uncomment the following code blocks // ----------------------------------------------------------------------------------- //binding contactbutton setonclicklistener { viewmodel onclickbutton } // =================================================================================== /** battery layout */ // =================================================================================== // codelab level 2 // [onprogresschanged] will update the fragment's ui via viewmodel livedata // [onstoptrackingtouch] will trigger the processing for updating new battery state of the // virtual device // todo 2 uncomment the following code blocks // ----------------------------------------------------------------------------------- //binding contactsensorbatterylayout titletext text = getstring r string battery //binding contactsensorbatterylayout seekbardata = seekbardata progress = viewmodel batterystatus //binding contactsensorbatterylayout seekbar setonseekbarchangelistener // object seekbar onseekbarchangelistener { // override fun onprogresschanged seekbar seekbar, progress int, fromuser boolean { // viewmodel updatebatteryseekbarprogress progress // } // // override fun onstarttrackingtouch seekbar seekbar {} // // override fun onstoptrackingtouch seekbar seekbar { // viewmodel updatebatterystatustocluster seekbar progress // } // } // // =================================================================================== // =================================================================================== // codelab level 2 // observer on the current contact status and react on the fragment's ui // todo 3 uncomment the following code blocks // ----------------------------------------------------------------------------------- //viewmodel statevalue observe viewlifecycleowner { // if it { // binding contactvaluetext text = getstring r string contact_state_close // binding contactbutton setimageresource r drawable ic_unoccupied // } else { // binding contactvaluetext text = getstring r string contact_state_open // binding contactbutton setimageresource r drawable ic_occupied // } //} // =================================================================================== // =================================================================================== // codelab level 2 // observer on the current battery status and react on the fragment's ui // todo 4 uncomment the following code blocks // ----------------------------------------------------------------------------------- //viewmodel batterystatus observe viewlifecycleowner { // val text string = getstring r string battery_format, it // binding contactsensorbatterylayout valuetext text = // html fromhtml text, html from_html_mode_legacy } // =================================================================================== video playerlevel 2 file path feature > media > java > com matter virtual device app feature media file name videoplayerfragment kt // =================================================================================== // codelab level 2 // [buttondata] observer on the current on/off status and react on the fragment's ui // [onclicklistener] trigger the processing for updating new on/off state of the virtual device // todo 1 uncomment the following code blocks // ----------------------------------------------------------------------------------- //binding videoplayeronofflayout buttondata = // buttondata // onoff = viewmodel onoff, // ontext = r string on_off_switch_power_on, // offtext = r string on_off_switch_power_off // //binding videoplayeronofflayout button setonclicklistener { viewmodel onclickbutton } // =================================================================================== // =================================================================================== // codelab level 2 // observer on the current playback status and react on the fragment's ui // todo 2 uncomment the following code blocks // ----------------------------------------------------------------------------------- //viewmodel playbackstate observe viewlifecycleowner { state -> // val statetext = convertplaybackstatetostring state // timber d "playbackstate $state $statetext " // binding videoplayerstatelayout valuetext text = statetext //} // =================================================================================== // =================================================================================== // codelab level 2 // observer on the current playback speed and react on the fragment's ui // todo 3 uncomment the following code blocks // ----------------------------------------------------------------------------------- //viewmodel playbackspeed observe viewlifecycleowner { speed -> // binding videoplayerspeedlayout valuetext text = speed tostring //} // =================================================================================== // =================================================================================== // codelab level 2 // observer on the current key code and react on the fragment's ui // todo 4 uncomment the following code blocks // ----------------------------------------------------------------------------------- //viewmodel keycode observe viewlifecycleowner { keycode -> // binding videoplayerkeypadlayout valuetext text = keycode value //} // =================================================================================== door locklevel 3 file path feature > closure > java > com matter virtual device app feature closure file name doorlockfragment kt // =================================================================================== // codelab level 3 // [buttondata] observer on the current lock status and react on the fragment's ui // [onclicklistener] trigger the processing for updating new lock state of the virtual device // ----------------------------------------------------------------------------------- // todo 1 copy code below binding doorlockonofflayout buttondata = buttondata onoff = viewmodel lockstate, ontext = r string door_lock_unlocked, offtext = r string door_lock_locked binding doorlockonofflayout button setonclicklistener { viewmodel onclickbutton } // =================================================================================== // =================================================================================== // codelab level 3 // trigger the processing for sending alarm event // ----------------------------------------------------------------------------------- // todo 2 copy code below binding doorlocksendalarmlayout button setonclicklistener { viewmodel onclicksendlockalarmeventbutton } // =================================================================================== // =================================================================================== // codelab level 3 // [onprogresschanged] will update the fragment's ui via viewmodel livedata // [onstoptrackingtouch] will trigger the processing for updating new battery state of the // virtual device // ----------------------------------------------------------------------------------- // todo 3 copy code below binding doorlockbatterylayout titletext text = getstring r string battery binding doorlockbatterylayout seekbardata = seekbardata progress = viewmodel batterystatus binding doorlockbatterylayout seekbar setonseekbarchangelistener object seekbar onseekbarchangelistener { override fun onprogresschanged seekbar seekbar, progress int, fromuser boolean { viewmodel updatebatteryseekbarprogress progress } override fun onstarttrackingtouch seekbar seekbar {} override fun onstoptrackingtouch seekbar seekbar { viewmodel updatebatterystatustocluster seekbar progress } } // =================================================================================== // =================================================================================== // codelab level 3 // observer on the current battery status and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 4 copy code below viewmodel batterystatus observe viewlifecycleowner { val text string = getstring r string battery_format, it binding doorlockbatterylayout valuetext text = html fromhtml text, html from_html_mode_legacy } // =================================================================================== extended color lightlevel 3 file path feature > lighting > java > com matter virtual device app feature lighting file name extendedcolorlightfragment kt // =================================================================================== // codelab level 3 // [buttondata] observer on the current on/off status and react on the fragment's ui // [onclicklistener] trigger the processing for updating new on/off state of the virtual device // ----------------------------------------------------------------------------------- // todo 1 copy code below binding extendedcolorlightonofflayout buttondata = buttondata onoff = viewmodel onoff, ontext = r string on_off_switch_power_on, offtext = r string on_off_switch_power_off binding extendedcolorlightonofflayout button setonclicklistener { viewmodel onclickbutton } // =================================================================================== // =================================================================================== // codelab level 3 // observer on the current color level status and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 2 copy code below viewmodel level observe viewlifecycleowner { // min 2 1% , max 255 100% val level int = it tofloat / 100 * 255 toint timber d "level $it" // if level value is 0, user can't distinguish the color // so, set it to half value + half of max binding extendedcolorlightcolorlayout colorboard drawable? alpha = level / 2 + 127 } // =================================================================================== // =================================================================================== // codelab level 3 // observer on the current color status and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 3 copy code below viewmodel currentcolor observe viewlifecycleowner { hsvcolor -> val rgbcolor int = colorcontrolutil hue2rgb hsvcolor currenthue tofloat , hsvcolor currentsaturation tofloat timber d "currenthue ${hsvcolor currenthue},currentsaturation ${hsvcolor currentsaturation}" timber d "color #${integer tohexstring rgbcolor }" var level int? = binding extendedcolorlightcolorlayout colorboard drawable? alpha if level == null level = 255 timber d "level $level" binding extendedcolorlightcolorlayout colorboard setimagedrawable bitmapdrawable resources, colorcontrolutil colorboard rgbcolor } // =================================================================================== // =================================================================================== // codelab level 3 // observer on the current color temperature status and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 4 copy code below viewmodel colortemperature observe viewlifecycleowner { // min 2580k 2577k , max 7050k 7042k val colortemperature int = 1000000 / it val rgbcolor int = colorcontrolutil kelvin2rgb colortemperature timber d "color temperature $colortemperature $it" timber d "color #${integer tohexstring rgbcolor }" binding extendedcolorlightcolorlayout colorboard setimagedrawable bitmapdrawable resources, colorcontrolutil colorboard rgbcolor } // =================================================================================== window coveringlevel 4 file path feature > closure > java > com matter virtual device app feature closure file name windowcoveringfragment kt // =================================================================================== // codelab level 4 // [onprogresschanged] will update the fragment's ui via viewmodel livedata // [onstoptrackingtouch] will trigger the processing for updating new windowshade state of the // virtual device // ----------------------------------------------------------------------------------- // todo 1 copy code below binding windowcoveringwindowshadeseekbar setonseekbarchangelistener object seekbar onseekbarchangelistener { override fun onprogresschanged seekbar seekbar, progress int, fromuser boolean { val targetpercentage = seekbar progress val text string = getstring r string window_covering_window_shade_format, targetpercentage val percentagetextview = binding windowcoveringwindowshadevaluetext percentagetextview text = html fromhtml text, html from_html_mode_legacy } override fun onstarttrackingtouch seekbar seekbar {} override fun onstoptrackingtouch seekbar seekbar { viewmodel stopmotion seekbar progress } } // ======================================================================================================= // =================================================================================== // codelab level 4 // [onprogresschanged] will update the fragment's ui via viewmodel livedata // [onstoptrackingtouch] will trigger the processing for updating new battery state of the // virtual device // ----------------------------------------------------------------------------------- // todo 2 copy code below binding windowcoveringbatterylayout titletext text = getstring r string battery binding windowcoveringbatterylayout seekbardata = seekbardata progress = viewmodel batterystatus binding windowcoveringbatterylayout seekbar setonseekbarchangelistener object seekbar onseekbarchangelistener { override fun onprogresschanged seekbar seekbar, progress int, fromuser boolean { viewmodel updatebatteryseekbarprogress progress } override fun onstarttrackingtouch seekbar seekbar {} override fun onstoptrackingtouch seekbar seekbar { viewmodel updatebatterystatustocluster seekbar progress } } // ======================================================================================================= // =================================================================================== // codelab level 4 // observer on the current position/operation status and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 3 copy code below viewmodel windowcoveringstatus observe viewlifecycleowner { status -> timber d "currentposition ${status currentposition},operationalstatus ${status operationalstatus}" binding windowcoveringwindowshadeseekbar progress = status currentposition val text string = getstring r string window_covering_window_shade_format, status currentposition binding windowcoveringwindowshadevaluetext text = html fromhtml text, html from_html_mode_legacy when status operationalstatus { 0 -> { when status currentposition { 0 -> { binding windowcoveringoperationalstatustext settext r string window_covering_closed } 100 -> { binding windowcoveringoperationalstatustext settext r string window_covering_open } else -> { binding windowcoveringoperationalstatustext settext r string window_covering_partially_open } } } 1 -> { binding windowcoveringoperationalstatustext settext r string window_covering_opening } 2 -> { binding windowcoveringoperationalstatustext settext r string window_covering_closing } else -> {} } } // ======================================================================================================= // =================================================================================== // codelab level 4 // observer on the current battery status and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 4 copy code below viewmodel batterystatus observe viewlifecycleowner { val text string = getstring r string battery_format, it binding windowcoveringbatterylayout valuetext text = html fromhtml text, html from_html_mode_legacy } // ======================================================================================================= thermostatlevel 5 file path feature > hvac > java > com matter virtual device app feature hvac file name themostatfragment kt // =================================================================================== // codelab level 5 // [onprogresschanged] will update the fragment's ui via viewmodel livedata // [onstoptrackingtouch] will trigger the processing for updating new temperature state of the // virtual device // ----------------------------------------------------------------------------------- // todo 1 copy code below binding thermostattemperatureseekbar setonseekbarchangelistener object seekbar onseekbarchangelistener { override fun onprogresschanged seekbar seekbar, progress int, fromuser boolean { viewmodel updatetemperatureseekbarprogress progress } override fun onstarttrackingtouch seekbar seekbar {} override fun onstoptrackingtouch seekbar seekbar { viewmodel updatetemperaturetocluster seekbar progress } } // =================================================================================== // =================================================================================== // codelab level 5 // [onprogresschanged] will update the fragment's ui via viewmodel livedata // [onstoptrackingtouch] will trigger the processing for updating new humidity state of the // virtual device // ----------------------------------------------------------------------------------- // todo 2 copy code below binding humiditysensorhumidityseekbar setonseekbarchangelistener object seekbar onseekbarchangelistener { override fun onprogresschanged seekbar seekbar, progress int, fromuser boolean { viewmodel updatehumidityseekbarprogress progress } override fun onstarttrackingtouch seekbar seekbar {} override fun onstoptrackingtouch seekbar seekbar { viewmodel updatehumiditytocluster seekbar progress } } // =================================================================================== // =================================================================================== // codelab level 5 // [onprogresschanged] will update the fragment's ui via viewmodel livedata // [onstoptrackingtouch] will trigger the processing for updating new battery state of the // virtual device // ----------------------------------------------------------------------------------- // todo 3 copy code below binding thermostatbatterylayout titletext text = getstring r string battery binding thermostatbatterylayout seekbardata = seekbardata progress = viewmodel batterystatus binding thermostatbatterylayout seekbar setonseekbarchangelistener object seekbar onseekbarchangelistener { override fun onprogresschanged seekbar seekbar, progress int, fromuser boolean { viewmodel updatebatteryseekbarprogress progress } override fun onstarttrackingtouch seekbar seekbar {} override fun onstoptrackingtouch seekbar seekbar { viewmodel updatebatterystatustocluster seekbar progress } } // =================================================================================== // =================================================================================== // codelab level 5 // observer on the current temperature status and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 4 copy code below viewmodel temperature observe viewlifecycleowner { val celsiustemp float = it tofloat / 100 val celsiustext string = getstring r string temperature_celsius_format, celsiustemp binding thermostattemperaturecelsiusvaluetext text = html fromhtml celsiustext, html from_html_mode_legacy val fahrenheittemp float = it tofloat / 100 * 9 / 5 + 32 val fahrenheittext string = getstring r string temperature_fahrenheit_format, fahrenheittemp binding thermostattemperaturefahrenheitvaluetext text = html fromhtml fahrenheittext, html from_html_mode_legacy binding thermostattemperatureseekbar progress = celsiustemp toint } // ========================================================================================== // =================================================================================== // codelab level 5 // observer on the current fan mode status and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 5 copy code below viewmodel fanmode observe viewlifecycleowner { timber d "fanmode $it" this fanmode = it binding fancontrolfanmodelayout valuetext text = convertfanmodetostring it } // ========================================================================================== // =================================================================================== // codelab level 5 // observer on the current heating setpoint and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 6 copy code below viewmodel occupiedheatingsetpoint observe viewlifecycleowner { val celsiustemp float = it tofloat / 100 val celsiustext string = getstring r string temperature_celsius_format, celsiustemp binding thermostatsettemperatureheatingcelsiusvaluetext text = html fromhtml celsiustext, html from_html_mode_legacy val fahrenheittemp float = it tofloat / 100 * 9 / 5 + 32 val fahrenheittext string = getstring r string temperature_fahrenheit_format, fahrenheittemp binding thermostatsettemperatureheatingfahrenheitvaluetext text = html fromhtml fahrenheittext, html from_html_mode_legacy } // =================================================================================== // =================================================================================== // codelab level 5 // observer on the current cooling setpoint and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 7 copy code below viewmodel occupiedcoolingsetpoint observe viewlifecycleowner { val celsiustemp float = it tofloat / 100 val celsiustext string = getstring r string temperature_celsius_format, celsiustemp binding thermostatsettemperaturecoolingcelsiusvaluetext text = html fromhtml celsiustext, html from_html_mode_legacy val fahrenheittemp float = it tofloat / 100 * 9 / 5 + 32 val fahrenheittext string = getstring r string temperature_fahrenheit_format, fahrenheittemp binding thermostatsettemperaturecoolingfahrenheitvaluetext text = html fromhtml fahrenheittext, html from_html_mode_legacy } // =================================================================================== // =================================================================================== // codelab level 5 // observer on the current system mode status and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 8 copy code below viewmodel systemmode observe viewlifecycleowner { timber d "systemmode $it" this systemmode = it binding thermostatsystemmodelayout valuetext text = convertsystemmodetostring it } // =================================================================================== // =================================================================================== // codelab level 5 // observer on the current humidity status and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 9 copy code below viewmodel humidity observe viewlifecycleowner { val humidity int = it / 100 val humiditytext string = getstring r string humidity_format, humidity binding humiditysensorhumiditypercentagevaluetext text = html fromhtml humiditytext, html from_html_mode_legacy binding humiditysensorhumidityseekbar progress = humidity } // =================================================================================== // =================================================================================== // codelab level 5 // observer on the current battery status and react on the fragment's ui // ----------------------------------------------------------------------------------- // todo 10 copy code below viewmodel batterystatus observe viewlifecycleowner { val text string = getstring r string battery_format, it binding thermostatbatterylayout valuetext text = html fromhtml text, html from_html_mode_legacy } // =================================================================================== // =================================================================================== // codelab level 5 // trigger the processing for setting system mode // ----------------------------------------------------------------------------------- // todo 11 copy code below alertdialog builder requirecontext settitle r string thermostat_mode setsinglechoiceitems modelist, convertsystemmodetoindex this systemmode { dialog, which -> timber d "thermostat mode set $which ${modelist[which]} " viewmodel setsystemmode convertindextosystemmode which dialog dismiss } setnegativebutton r string cancel, null show // =================================================================================== // =================================================================================== // codelab level 5 // trigger the processing for setting fan mode // ----------------------------------------------------------------------------------- // todo 12 copy code below alertdialog builder requirecontext settitle r string fan_control_fan_mode setsinglechoiceitems modelist, convertfanmodetoindex this fanmode { dialog, which -> timber d "fan mode set $which ${modelist[which]} " viewmodel setfanmode convertindextofanmode which dialog dismiss } setnegativebutton r string cancel, null show // =================================================================================== build and run the virtual device app to build and run your app, follow these steps using a usb cable, connect your mobile device the minimum os requirement is android 8 0 oreo select the sample virtual device app from the run configurations menu in the android studio then, select the connected device in the target device menu click run you can see the device you created in the matter virtual device app onboard and control the virtual device via the smartthings app onboard to onboard the virtual device select and set up the virtual device type you created click save click start to show the qr code for onboarding then, go to the smartthings app and click the + button then, onboard the virtual device by scanning its qr code control by smartthings app in the smartthings app, control the virtual device by using its various functions such as on and off for switch contribute to matter open source optional notethis step is optional, but you can proceed if you want to know how to contribute your code to matter open source to contribute to matter open source, you need to have the latest code therefore, apart from the project files provided by this code lab activity, you should fork and modify the latest code from matter open source project matter follows the "fork-and-pull" model for accepting contributions to do this sign in or sign up to github fork the matter repository by clicking fork on the web ui for each new feature, clone your fork to the local pc and create a working branch $ git clone https //github com/<username>/connectedhomeip git $ git checkout –b <branch-name> before running the build command, source the environment setup script activate sh at the top level this script takes care of downloading gn, ninja, and setting up a python environment with libraries used to build and test $ source scripts/activate sh build the virtual device app using the build_example py $ /scripts/build/build_examples py --target android-arm64-virtual-device-app build add each modified file to include in the commit then, create a commit $ git add <filename1> <filename1> $ git commit –s noteto contribute to the open source, you must check the integrity of the code for this, checking using restyle is recommended push to your github fork $ git push origin <branch-name> then, submit your pull request by clicking contribute > open pull request on the web ui write a description of the problem, change overview, and test then, sign the contributor license agreement cla so a reviewer can automatically be assigned click open pull request tipsee contributing to matter for more information you're done! congratulations! you have successfully achieved the goal of this code lab topic now, you can create a matter-compatible virtual device and contribute your code to matter open source by yourself! if you're having trouble, you may download this file matter virtual device complete code 11 49 mb learn more by going to smartthings matter libraries