[matter] Implement All Concentration Measurement Clusters (#20009)

* [matter] Implement All Concentration Measurement Clusters

Signed-off-by: Dan Cunningham <dan@digitaldan.com>
This commit is contained in:
Dan Cunningham
2026-01-24 10:08:16 +01:00
committed by GitHub
parent 0c3ef688fc
commit 63a8eaae2f
26 changed files with 3026 additions and 184 deletions
+95 -84
View File
@@ -214,89 +214,100 @@ Possible channels include:
## Endpoint Channels
| Channel ID | Type | Label | Description | Category | ReadOnly | Pattern | State Options |
|-------------------------------------------------------------|--------------------------|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|----------|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| airquality-airquality | Number | Air Quality | Indicates the currently measured air quality | | true | | 0=Unknown, 1=Good, 2=Fair, 3=Moderate, 4=Poor, 5=Very Poor, 6=Extremely Poor |
| booleanstate-statevalue | Switch | Boolean State | Indicates a boolean state value | Status | true | | |
| carbondioxideconcentrationmeasurement-measuredvalue | Number:Dimensionless | CO2 Concentration | Indicates the measured carbon dioxide concentration in parts per million | CarbonDioxide | true | %.0f ppm | |
| carbonmonoxideconcentrationmeasurement-measuredvalue | Number:Dimensionless | CO Concentration | Indicates the measured carbon monoxide concentration in parts per million | Alarm | true | %.0f ppm | |
| colorcontrol-color | Color | Color | The color channel allows to control the color of a light. It is also possible to dim values and switch the light on and off. | ColorLight | | | |
| colorcontrol-temperature | Dimmer | Color Temperature | Sets the color temperature of the light | ColorLight | | | |
| colorcontrol-temperature-abs | Number:Temperature | Color Temperature | Sets the color temperature of the light in mirek | ColorLight | | %.0f %unit% | |
| doorlock-alarm | Trigger | Door Lock Alarm | Event that fires when a lock alarm occurs | | | | 0=Lock Jammed, 1=Lock Factory Reset, 3=Lock Radio Power Cycled, 4=Wrong Code Entry Limit, 5=Front Escutcheon Removed, 6=Door Forced Open, 7=Door Ajar, 8=Forced User |
| doorlock-doorstate | Contact | Door Sensor State | Door Sensor State | Door | true | | |
| doorlock-lockoperationerror | Trigger | Lock Operation Error | Event that fires when a lock operation error occurs | | | | 0=Lock, 1=Unlock, 2=Non Access User Event, 3=Forced User Event, 4=Unlatch |
| doorlock-lockstate | Switch | Door Lock State | Locks and unlocks the door and maintains the lock state | Door | | | |
| electricalenergymeasurement-cumulativeenergyexported-energy | Number:Energy | Cumulative Energy Exported | The cumulative energy exported measurement | Energy | true | %.1f %unit% | |
| electricalenergymeasurement-cumulativeenergyimported-energy | Number:Energy | Cumulative Energy Imported | The cumulative energy imported measurement | Energy | true | %.1f %unit% | |
| electricalenergymeasurement-energymeasurmement-energy | Number:Energy | Energy | The measured energy | Energy | true | %.1f %unit% | |
| electricalenergymeasurement-periodicenergyexported-energy | Number:Energy | Periodic Energy Exported | The periodic energy exported measurement | Energy | true | %.1f %unit% | |
| electricalenergymeasurement-periodicenergyimported-energy | Number:Energy | Periodic Energy Imported | The periodic energy imported measurement | Energy | true | %.1f %unit% | |
| electricalpowermeasurement-activecurrent | Number:ElectricCurrent | Active Current | The active current measurement in amperes | Energy | true | %.1f %unit% | |
| electricalpowermeasurement-activepower | Number:Power | Active Power | The active power measurement in watts | Energy | true | %.1f %unit% | |
| electricalpowermeasurement-voltage | Number:ElectricPotential | Voltage | The voltage measurement in volts | Energy | true | %.2f %unit% | |
| fancontrol-fanmode | Number | Fan Mode | Set the fan mode | HVAC | | | 0=Off, 1=Low, 2=Medium, 3=High, 4=On, 5=Auto |
| fancontrol-mode | Number | Fan Control Mode | The current mode of the fan | HVAC | | | |
| fancontrol-percent | Dimmer | Fan Control Percent | The current fan speed percentage level | HVAC | true | %.0f %% | |
| illuminancemeasurement-measuredvalue | Number:Illuminance | Illuminance | The measured illuminance in Lux | Illuminance | true | %d %unit% | |
| levelcontrol-level | Dimmer | Dimmer | Sets the level of the light | Light | | | |
| modeselect-mode | Number | Mode Select | Selection of 1 or more states | | | %d | |
| occupancysensing-occupied | Switch | Occupancy | Indicates if an occupancy sensor is triggered | Presence | true | | |
| onoffcontrol-onoff | Switch | Switch | Switches the power on and off | Light | | | |
| powersource-batchargelevel | Number | Battery Charge Level | Indicates a coarse ranking of the charge level of the battery, used to indicate when intervention is required | Energy | true | | 0=Ok, 1=Warning, 2=Critical |
| powersource-batpercentremaining | Number:Dimensionless | Battery Percent Remaining | Indicates the estimated percentage of battery charge remaining until the battery will no longer be able to provide power to the Node | Energy | true | %d %% | |
| relativehumiditymeasurement-measuredvalue | Number:Dimensionless | Humidity | The measured humidity | Humidity | true | %.0f %% | |
| rvccleanmode-mode | Number | Clean Mode | Selects the cleaning mode (vacuum, mop etc.) of the robotic vacuum cleaner | | | %d | |
| rvcoperationalstate-gohome | Switch | Go Home | Sends the robotic vacuum cleaner back to the dock | | | | |
| rvcoperationalstate-state | Number | Operational State | Reports the operational state of the robotic vacuum cleaner | | true | %d | |
| rvcrunmode-mode | Number | Run Mode | Selects the run mode (idle, cleaning, mapping) of the robotic vacuum cleaner | | | %d | |
| servicearea-selectedarea | Switch | Area Selection | Toggle to enable a mapped area for cleaning | | | | |
| smokecoalarm-batteryalert | Number | Battery Alert | Indicates whether the battery power resource fault detection is triggered | Alarm | true | | 0=Normal, 1=Warning, 2=Critical |
| smokecoalarm-contaminationstate | Number | Contamination State | Indicates the contamination level of the smoke sensor | Alarm | true | | 0=Normal, 1=Low, 2=Warning, 3=Critical |
| smokecoalarm-costate | Number | CO Alarm | Indicates whether the CO sensor is currently triggering an alarm | Alarm | true | | 0=Normal, 1=Warning, 2=Critical |
| smokecoalarm-devicemuted | Number | Device Muted | Indicates whether the audible expression of the device is currently muted | Alarm | true | | 0=Not Muted, 1=Muted |
| smokecoalarm-endofservice | Number | End Of Service | Indicates whether the end-of-service has been triggered at the device | Alarm | true | | 0=Normal, 1=Expired |
| smokecoalarm-expressedstate | Number | Expressed State | The visibly and audibly expressed alarm state with the highest priority | Alarm | true | | 0=Normal, 1=Smoke Alarm, 2=CO Alarm, 3=Battery Alert, 4=Testing, 5=Hardware Fault, 6=End Of Service, 7=Interconnect Smoke, 8=Interconnect CO |
| smokecoalarm-expirydate | DateTime | Expiry Date | Indicates the date when the device reaches its stated expiry date | Time | true | | |
| smokecoalarm-hardwarefault | Switch | Hardware Fault | Indicates whether the hardware fault detection mechanism is triggered | Alarm | true | | |
| smokecoalarm-interconnectco | Number | Interconnect CO Alarm | Indicates whether the interconnected CO alarm is currently triggering from another device | Alarm | true | | 0=Normal, 1=Warning, 2=Critical |
| smokecoalarm-interconnectsmoke | Number | Interconnect Smoke Alarm | Indicates whether the interconnected smoke alarm is currently triggering from another device | Alarm | true | | 0=Normal, 1=Warning, 2=Critical |
| smokecoalarm-smokesensitivity | Number | Smoke Sensitivity | Indicates the sensitivity level of the smoke sensor | Alarm | | | 0=High, 1=Standard, 2=Low |
| smokecoalarm-smokestate | Number | Smoke Alarm | Indicates whether the smoke sensor is currently triggering an alarm | Alarm | true | | 0=Normal, 1=Warning, 2=Critical |
| smokecoalarm-testinprogress | Switch | Test In Progress | Indicates whether the device self-test is currently activated | Alarm | true | | |
| switch-initialpress | Trigger | Initial Press Trigger | This trigger shall indicate the new value of the CurrentPosition attribute as a JSON object, i.e. while pressed. | | | | |
| switch-longpress | Trigger | Long Press Trigger | This trigger shall indicate the new value of the CurrentPosition attribute as a JSON object, i.e. while pressed. | | | | |
| switch-longrelease | Trigger | Long Release Trigger | This trigger shall indicate the previous value of the CurrentPosition attribute as a JSON object, i.e. just prior to release. | | | | |
| switch-multipresscomplete | Trigger | Multi-Press Complete Trigger | This trigger shall indicate 2 numeric fields as a JSON object. The first is the new value of the CurrentPosition attribute, i.e. while pressed. The second is how many times the momentary switch has been pressed in a multi-press sequence. | | | | |
| switch-multipressongoing | Trigger | Multi-Press Ongoing Trigger | This trigger shall indicate 2 numeric fields as a JSON object. The first is the new value of the CurrentPosition attribute, i.e. while pressed. The second is the multi press code with a value of N when the Nth press of a multi-press sequence has been detected. | | | | |
| switch-shortrelease | Trigger | Short Release Trigger | This trigger shall indicate the previous value of the CurrentPosition attribute as a JSON object, i.e. just prior to release. | | | | |
| switch-switch | Number | Switch | Indication of a switch or remote being activated | | true | %d | |
| switch-switchlatched | Trigger | Switched Latched Trigger | This trigger shall indicate the new value of the CurrentPosition attribute as a JSON object, i.e. after the move. | | | | |
| temperaturemeasurement-measuredvalue | Number:Temperature | Temperature | The measured temperature | Temperature | true | %.1f %unit% | |
| thermostat-localtemperature | Number:Temperature | Local Temperature | Indicates the local temperature provided by the thermostat | HVAC | true | %.1f %unit% | |
| thermostat-occupiedcooling | Number:Temperature | Occupied Cooling Setpoint | Set the cooling temperature when the room is occupied | HVAC | | %.1f %unit% | |
| thermostat-occupiedheating | Number:Temperature | Occupied Heating Setpoint | Set the heating temperature when the room is occupied | HVAC | | %.1f %unit% | |
| thermostat-outdoortemperature | Number:Temperature | Outdoor Temperature | Indicates the outdoor temperature provided by the thermostat | HVAC | true | %.1f %unit% | |
| thermostat-runningmode | Number | Running Mode | The running mode of the thermostat | HVAC | true | | 0=Off, 3=Cool, 4=Heat |
| thermostat-systemmode | Number | System Mode | Set the system mode of the thermostat | HVAC | | | 0=Off, 1=Auto, 3=Cool, 4=Heat, 5=Emergency Heating, 6=Precooling, 7=Fan Only, 8=Dry, 9=Sleep |
| thermostat-unoccupiedcooling | Number:Temperature | Unoccupied Cooling Setpoint | Set the cooling temperature when the room is unoccupied | HVAC | | %.1f %unit% | |
| thermostat-unoccupiedheating | Number:Temperature | Unoccupied Heating Setpoint | Set the heating temperature when the room is unoccupied | HVAC | | %.1f %unit% | |
| threadborderroutermanagement-activedataset | String | Active Dataset | The active Thread network dataset configuration | Network | | | |
| threadborderroutermanagement-activedatasettimestamp | Number | Active Dataset Timestamp | Timestamp of the active Thread network dataset | Network | true | %d | |
| threadborderroutermanagement-borderagentid | String | Border Agent ID | The unique identifier of the Thread border agent | Network | true | | |
| threadborderroutermanagement-borderroutername | String | Border Router Name | The name of the Thread border router | Network | true | | |
| threadborderroutermanagement-interfaceenabled | Switch | Interface Enabled | Whether the Thread border router interface is enabled | Network | | | |
| threadborderroutermanagement-pendingdataset | String | Pending Dataset | The pending Thread network dataset configuration (only available if PAN change feature is supported) | Network | | | |
| threadborderroutermanagement-pendingdatasettimestamp | Number | Pending Dataset Timestamp | Timestamp of the pending Thread network dataset (only available if PAN change feature is supported) | Network | true | %d | |
| threadborderroutermanagement-threadversion | Number | Thread Version | The version of Thread protocol being used | Network | true | %d | |
| threadnetworkdiagnostics-channel | Number | Channel | The Thread network channel | Network | true | %d | |
| threadnetworkdiagnostics-extendedpanid | Number | Extended PAN ID | The Thread network extended PAN ID | Network | true | %d | |
| threadnetworkdiagnostics-networkname | String | Network Name | The Thread network name | Network | true | | |
| threadnetworkdiagnostics-panid | Number | PAN ID | The Thread network PAN ID | Network | true | %d | |
| threadnetworkdiagnostics-rloc16 | Number | RLOC16 | The Thread network RLOC16 address | Network | true | %d | |
| threadnetworkdiagnostics-routingrole | Number | Routing Role | The Thread routing role | Network | true | %d | 0=Unspecified, 1=Unassigned, 2=Sleepy End Device, 3=End Device, 4=Reed, 5=Router, 6=Leader |
| wifinetworkdiagnostics-rssi | Number:Power | Signal | Wi-Fi signal strength indicator. | QualityOfService | true | %d %unit% | |
| windowcovering-lift | Rollershutter | Window Covering Lift | Sets the window covering level - supporting open/close and up/down type commands | Blinds | | %.0f %% | |
| Channel ID | Type | Label | Description | Category | ReadOnly | Pattern | State Options |
|---------------------------------------------------------------------|--------------------------|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|----------|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| airquality-airquality | Number | Air Quality | Indicates the currently measured air quality | | true | | 0=Unknown, 1=Good, 2=Fair, 3=Moderate, 4=Poor, 5=Very Poor, 6=Extremely Poor |
| booleanstate-statevalue | Switch | Boolean State | Indicates a boolean state value | Status | true | | |
| carbondioxideconcentrationmeasurement-measuredvalue | Number:Dimensionless | CO2 Concentration | Indicates the measured carbon dioxide concentration | CarbonDioxide | true | %.2f ppm | |
| carbonmonoxideconcentrationmeasurement-measuredvalue | Number:Dimensionless | CO Concentration | Indicates the measured carbon monoxide concentration | Alarm | true | %.2f ppm | |
| concentrationmeasurement-averagemeasuredvalue | Number:Dimensionless | Average Concentration | Indicates the average concentration measured during the measurement window | Chart | true | %.2f | |
| concentrationmeasurement-levelvalue | Number | Concentration Level | Indicates the concentration level as an enumeration | QualityOfService | true | | 0=Unknown, 1=Low, 2=Medium, 3=High, 4=Critical |
| concentrationmeasurement-peakmeasuredvalue | Number:Dimensionless | Peak Concentration | Indicates the peak (maximum) concentration measured during the measurement window | Chart | true | %.2f | |
| colorcontrol-color | Color | Color | The color channel allows to control the color of a light. It is also possible to dim values and switch the light on and off. | ColorLight | | | |
| colorcontrol-temperature | Dimmer | Color Temperature | Sets the color temperature of the light | ColorLight | | | |
| colorcontrol-temperature-abs | Number:Temperature | Color Temperature | Sets the color temperature of the light in mirek | ColorLight | | %.0f %unit% | |
| doorlock-alarm | Trigger | Door Lock Alarm | Event that fires when a lock alarm occurs | | | | 0=Lock Jammed, 1=Lock Factory Reset, 3=Lock Radio Power Cycled, 4=Wrong Code Entry Limit, 5=Front Escutcheon Removed, 6=Door Forced Open, 7=Door Ajar, 8=Forced User |
| doorlock-doorstate | Contact | Door Sensor State | Door Sensor State | Door | true | | |
| doorlock-lockoperationerror | Trigger | Lock Operation Error | Event that fires when a lock operation error occurs | | | | 0=Lock, 1=Unlock, 2=Non Access User Event, 3=Forced User Event, 4=Unlatch |
| doorlock-lockstate | Switch | Door Lock State | Locks and unlocks the door and maintains the lock state | Door | | | |
| electricalenergymeasurement-cumulativeenergyexported-energy | Number:Energy | Cumulative Energy Exported | The cumulative energy exported measurement | Energy | true | %.1f %unit% | |
| electricalenergymeasurement-cumulativeenergyimported-energy | Number:Energy | Cumulative Energy Imported | The cumulative energy imported measurement | Energy | true | %.1f %unit% | |
| electricalenergymeasurement-energymeasurmement-energy | Number:Energy | Energy | The measured energy | Energy | true | %.1f %unit% | |
| electricalenergymeasurement-periodicenergyexported-energy | Number:Energy | Periodic Energy Exported | The periodic energy exported measurement | Energy | true | %.1f %unit% | |
| electricalenergymeasurement-periodicenergyimported-energy | Number:Energy | Periodic Energy Imported | The periodic energy imported measurement | Energy | true | %.1f %unit% | |
| electricalpowermeasurement-activecurrent | Number:ElectricCurrent | Active Current | The active current measurement in amperes | Energy | true | %.1f %unit% | |
| electricalpowermeasurement-activepower | Number:Power | Active Power | The active power measurement in watts | Energy | true | %.1f %unit% | |
| electricalpowermeasurement-voltage | Number:ElectricPotential | Voltage | The voltage measurement in volts | Energy | true | %.2f %unit% | |
| fancontrol-fanmode | Number | Fan Mode | Set the fan mode | HVAC | | | 0=Off, 1=Low, 2=Medium, 3=High, 4=On, 5=Auto |
| fancontrol-mode | Number | Fan Control Mode | The current mode of the fan | HVAC | | | |
| fancontrol-percent | Dimmer | Fan Control Percent | The current fan speed percentage level | HVAC | true | %.0f %% | |
| formaldehydeconcentrationmeasurement-measuredvalue | Number:Dimensionless | Formaldehyde Concentration | Indicates the measured formaldehyde (HCHO) concentration | Gas | true | %.2f ppm | |
| illuminancemeasurement-measuredvalue | Number:Illuminance | Illuminance | The measured illuminance in Lux | Illuminance | true | %d %unit% | |
| levelcontrol-level | Dimmer | Dimmer | Sets the level of the light | Light | | | |
| modeselect-mode | Number | Mode Select | Selection of 1 or more states | | | %d | |
| nitrogendioxideconcentrationmeasurement-measuredvalue | Number:Dimensionless | NO2 Concentration | Indicates the measured nitrogen dioxide concentration | Gas | true | %.2f ppm | |
| occupancysensing-occupied | Switch | Occupancy | Indicates if an occupancy sensor is triggered | Presence | true | | |
| onoffcontrol-onoff | Switch | Switch | Switches the power on and off | Light | | | |
| ozoneconcentrationmeasurement-measuredvalue | Number:Dimensionless | Ozone Concentration | Indicates the measured ozone (O₃) concentration | Gas | true | %.2f ppm | |
| pm1concentrationmeasurement-measuredvalue | Number:Dimensionless | PM1 Concentration | Indicates the measured PM1 particulate matter concentration | QualityOfService | true | %.1f µg/m³ | |
| pm10concentrationmeasurement-measuredvalue | Number:Dimensionless | PM10 Concentration | Indicates the measured PM10 particulate matter concentration | QualityOfService | true | %.1f µg/m³ | |
| pm25concentrationmeasurement-measuredvalue | Number:Dimensionless | PM2.5 Concentration | Indicates the measured PM2.5 particulate matter concentration | QualityOfService | true | %.1f µg/m³ | |
| powersource-batchargelevel | Number | Battery Charge Level | Indicates a coarse ranking of the charge level of the battery, used to indicate when intervention is required | Energy | true | | 0=Ok, 1=Warning, 2=Critical |
| powersource-batpercentremaining | Number:Dimensionless | Battery Percent Remaining | Indicates the estimated percentage of battery charge remaining until the battery will no longer be able to provide power to the Node | Energy | true | %d %% | |
| radonconcentrationmeasurement-measuredvalue | Number:Dimensionless | Radon Concentration | Indicates the measured radon concentration | Gas | true | %.2f | |
| relativehumiditymeasurement-measuredvalue | Number:Dimensionless | Humidity | The measured humidity | Humidity | true | %.0f %% | |
| rvccleanmode-mode | Number | Clean Mode | Selects the cleaning mode (vacuum, mop etc.) of the robotic vacuum cleaner | | | %d | |
| rvcoperationalstate-gohome | Switch | Go Home | Sends the robotic vacuum cleaner back to the dock | | | | |
| rvcoperationalstate-state | Number | Operational State | Reports the operational state of the robotic vacuum cleaner | | true | %d | |
| rvcrunmode-mode | Number | Run Mode | Selects the run mode (idle, cleaning, mapping) of the robotic vacuum cleaner | | | %d | |
| servicearea-selectedarea | Switch | Area Selection | Toggle to enable a mapped area for cleaning | | | | |
| smokecoalarm-batteryalert | Number | Battery Alert | Indicates whether the battery power resource fault detection is triggered | Alarm | true | | 0=Normal, 1=Warning, 2=Critical |
| smokecoalarm-contaminationstate | Number | Contamination State | Indicates the contamination level of the smoke sensor | Alarm | true | | 0=Normal, 1=Low, 2=Warning, 3=Critical |
| smokecoalarm-costate | Number | CO Alarm | Indicates whether the CO sensor is currently triggering an alarm | Alarm | true | | 0=Normal, 1=Warning, 2=Critical |
| smokecoalarm-devicemuted | Number | Device Muted | Indicates whether the audible expression of the device is currently muted | Alarm | true | | 0=Not Muted, 1=Muted |
| smokecoalarm-endofservice | Number | End Of Service | Indicates whether the end-of-service has been triggered at the device | Alarm | true | | 0=Normal, 1=Expired |
| smokecoalarm-expressedstate | Number | Expressed State | The visibly and audibly expressed alarm state with the highest priority | Alarm | true | | 0=Normal, 1=Smoke Alarm, 2=CO Alarm, 3=Battery Alert, 4=Testing, 5=Hardware Fault, 6=End Of Service, 7=Interconnect Smoke, 8=Interconnect CO |
| smokecoalarm-expirydate | DateTime | Expiry Date | Indicates the date when the device reaches its stated expiry date | Time | true | | |
| smokecoalarm-hardwarefault | Switch | Hardware Fault | Indicates whether the hardware fault detection mechanism is triggered | Alarm | true | | |
| smokecoalarm-interconnectco | Number | Interconnect CO Alarm | Indicates whether the interconnected CO alarm is currently triggering from another device | Alarm | true | | 0=Normal, 1=Warning, 2=Critical |
| smokecoalarm-interconnectsmoke | Number | Interconnect Smoke Alarm | Indicates whether the interconnected smoke alarm is currently triggering from another device | Alarm | true | | 0=Normal, 1=Warning, 2=Critical |
| smokecoalarm-smokesensitivity | Number | Smoke Sensitivity | Indicates the sensitivity level of the smoke sensor | Alarm | | | 0=High, 1=Standard, 2=Low |
| smokecoalarm-smokestate | Number | Smoke Alarm | Indicates whether the smoke sensor is currently triggering an alarm | Alarm | true | | 0=Normal, 1=Warning, 2=Critical |
| smokecoalarm-testinprogress | Switch | Test In Progress | Indicates whether the device self-test is currently activated | Alarm | true | | |
| totalvolatileorganiccompoundsconcentrationmeasurement-measuredvalue | Number:Dimensionless | TVOC Concentration | Indicates the measured total volatile organic compounds concentration | Gas | true | %.2f ppm | |
| switch-initialpress | Trigger | Initial Press Trigger | This trigger shall indicate the new value of the CurrentPosition attribute as a JSON object, i.e. while pressed. | | | | |
| switch-longpress | Trigger | Long Press Trigger | This trigger shall indicate the new value of the CurrentPosition attribute as a JSON object, i.e. while pressed. | | | | |
| switch-longrelease | Trigger | Long Release Trigger | This trigger shall indicate the previous value of the CurrentPosition attribute as a JSON object, i.e. just prior to release. | | | | |
| switch-multipresscomplete | Trigger | Multi-Press Complete Trigger | This trigger shall indicate 2 numeric fields as a JSON object. The first is the new value of the CurrentPosition attribute, i.e. while pressed. The second is how many times the momentary switch has been pressed in a multi-press sequence. | | | | |
| switch-multipressongoing | Trigger | Multi-Press Ongoing Trigger | This trigger shall indicate 2 numeric fields as a JSON object. The first is the new value of the CurrentPosition attribute, i.e. while pressed. The second is the multi press code with a value of N when the Nth press of a multi-press sequence has been detected. | | | | |
| switch-shortrelease | Trigger | Short Release Trigger | This trigger shall indicate the previous value of the CurrentPosition attribute as a JSON object, i.e. just prior to release. | | | | |
| switch-switch | Number | Switch | Indication of a switch or remote being activated | | true | %d | |
| switch-switchlatched | Trigger | Switched Latched Trigger | This trigger shall indicate the new value of the CurrentPosition attribute as a JSON object, i.e. after the move. | | | | |
| temperaturemeasurement-measuredvalue | Number:Temperature | Temperature | The measured temperature | Temperature | true | %.1f %unit% | |
| thermostat-localtemperature | Number:Temperature | Local Temperature | Indicates the local temperature provided by the thermostat | HVAC | true | %.1f %unit% | |
| thermostat-occupiedcooling | Number:Temperature | Occupied Cooling Setpoint | Set the cooling temperature when the room is occupied | HVAC | | %.1f %unit% | |
| thermostat-occupiedheating | Number:Temperature | Occupied Heating Setpoint | Set the heating temperature when the room is occupied | HVAC | | %.1f %unit% | |
| thermostat-outdoortemperature | Number:Temperature | Outdoor Temperature | Indicates the outdoor temperature provided by the thermostat | HVAC | true | %.1f %unit% | |
| thermostat-runningmode | Number | Running Mode | The running mode of the thermostat | HVAC | true | | 0=Off, 3=Cool, 4=Heat |
| thermostat-systemmode | Number | System Mode | Set the system mode of the thermostat | HVAC | | | 0=Off, 1=Auto, 3=Cool, 4=Heat, 5=Emergency Heating, 6=Precooling, 7=Fan Only, 8=Dry, 9=Sleep |
| thermostat-unoccupiedcooling | Number:Temperature | Unoccupied Cooling Setpoint | Set the cooling temperature when the room is unoccupied | HVAC | | %.1f %unit% | |
| thermostat-unoccupiedheating | Number:Temperature | Unoccupied Heating Setpoint | Set the heating temperature when the room is unoccupied | HVAC | | %.1f %unit% | |
| threadborderroutermanagement-activedataset | String | Active Dataset | The active Thread network dataset configuration | Network | | | |
| threadborderroutermanagement-activedatasettimestamp | Number | Active Dataset Timestamp | Timestamp of the active Thread network dataset | Network | true | %d | |
| threadborderroutermanagement-borderagentid | String | Border Agent ID | The unique identifier of the Thread border agent | Network | true | | |
| threadborderroutermanagement-borderroutername | String | Border Router Name | The name of the Thread border router | Network | true | | |
| threadborderroutermanagement-interfaceenabled | Switch | Interface Enabled | Whether the Thread border router interface is enabled | Network | | | |
| threadborderroutermanagement-pendingdataset | String | Pending Dataset | The pending Thread network dataset configuration (only available if PAN change feature is supported) | Network | | | |
| threadborderroutermanagement-pendingdatasettimestamp | Number | Pending Dataset Timestamp | Timestamp of the pending Thread network dataset (only available if PAN change feature is supported) | Network | true | %d | |
| threadborderroutermanagement-threadversion | Number | Thread Version | The version of Thread protocol being used | Network | true | %d | |
| threadnetworkdiagnostics-channel | Number | Channel | The Thread network channel | Network | true | %d | |
| threadnetworkdiagnostics-extendedpanid | Number | Extended PAN ID | The Thread network extended PAN ID | Network | true | %d | |
| threadnetworkdiagnostics-networkname | String | Network Name | The Thread network name | Network | true | | |
| threadnetworkdiagnostics-panid | Number | PAN ID | The Thread network PAN ID | Network | true | %d | |
| threadnetworkdiagnostics-rloc16 | Number | RLOC16 | The Thread network RLOC16 address | Network | true | %d | |
| threadnetworkdiagnostics-routingrole | Number | Routing Role | The Thread routing role | Network | true | %d | 0=Unspecified, 1=Unassigned, 2=Sleepy End Device, 3=End Device, 4=Reed, 5=Router, 6=Leader |
| wifinetworkdiagnostics-rssi | Number:Power | Signal | Wi-Fi signal strength indicator. | QualityOfService | true | %d %unit% | |
| windowcovering-lift | Rollershutter | Window Covering Lift | Sets the window covering level - supporting open/close and up/down type commands | Blinds | | %.0f %% | |
## Supported Matter Device Types
@@ -327,7 +338,7 @@ Other device types may be supported, but with limited or missing functionality.
| Humidity Sensor | 0x0307 | Relative Humidity Measurement (0x0405) |
| On/Off Sensor | 0x0850 | On/Off (0x0006) |
| Air Quality Sensor | 0x002C | Air Quality (0x005B) |
| Smoke CO Alarm | 0x0076 | Smoke CO Alarm (0x005C), Relative Humidity Measurement (0x0405), Temperature Measurement (0x0402), Carbon Monoxide Concentration Measurement (0x040C) |
| Smoke CO Alarm | 0x0076 | Smoke CO Alarm (0x005C), Relative Humidity Measurement (0x0405), Temperature Measurement (0x0402), Concentration Measurement Clusters |
| Water Freeze Detector | 0x0041 | Boolean State (0x0045) |
| Water Leak Detector | 0x0043 | Boolean State (0x0045) |
| Rain Sensor | 0x0044 | Boolean State (0x0045) |
@@ -35,11 +35,77 @@ public class MatterBindingConstants {
public static final ChannelTypeUID CHANNEL_AIRQUALITY_AIRQUALITY = new ChannelTypeUID(BINDING_ID,
CHANNEL_ID_AIRQUALITY_AIRQUALITY);
public static final String CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "carbondioxideconcentrationmeasurement-measuredvalue";
public static final ChannelTypeUID CHANNEL_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = new ChannelTypeUID(
BINDING_ID, CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE);
public static final String CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "carbonmonoxideconcentrationmeasurement-measuredvalue";
public static final ChannelTypeUID CHANNEL_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = new ChannelTypeUID(
BINDING_ID, CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE);
public static final String CHANNEL_ID_PM1CONCENTRATIONMEASUREMENT_MEASUREDVALUE = "pm1concentrationmeasurement-measuredvalue";
public static final String CHANNEL_ID_PM10CONCENTRATIONMEASUREMENT_MEASUREDVALUE = "pm10concentrationmeasurement-measuredvalue";
public static final String CHANNEL_ID_PM25CONCENTRATIONMEASUREMENT_MEASUREDVALUE = "pm25concentrationmeasurement-measuredvalue";
public static final String CHANNEL_ID_OZONECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "ozoneconcentrationmeasurement-measuredvalue";
public static final String CHANNEL_ID_NITROGENDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "nitrogendioxideconcentrationmeasurement-measuredvalue";
public static final String CHANNEL_ID_FORMALDEHYDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "formaldehydeconcentrationmeasurement-measuredvalue";
public static final String CHANNEL_ID_TOTALVOLATILEORGANICCOMPOUNDSCONCENTRATIONMEASUREMENT_MEASUREDVALUE = "totalvolatileorganiccompoundsconcentrationmeasurement-measuredvalue";
public static final String CHANNEL_ID_RADONCONCENTRATIONMEASUREMENT_MEASUREDVALUE = "radonconcentrationmeasurement-measuredvalue";
public static final String CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_LEVELVALUE = "carbondioxideconcentrationmeasurement-levelvalue";
public static final String CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE = "carbondioxideconcentrationmeasurement-peakmeasuredvalue";
public static final String CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE = "carbondioxideconcentrationmeasurement-averagemeasuredvalue";
public static final String CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_LEVELVALUE = "carbonmonoxideconcentrationmeasurement-levelvalue";
public static final String CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE = "carbonmonoxideconcentrationmeasurement-peakmeasuredvalue";
public static final String CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE = "carbonmonoxideconcentrationmeasurement-averagemeasuredvalue";
public static final String CHANNEL_ID_PM1CONCENTRATIONMEASUREMENT_LEVELVALUE = "pm1concentrationmeasurement-levelvalue";
public static final String CHANNEL_ID_PM1CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE = "pm1concentrationmeasurement-peakmeasuredvalue";
public static final String CHANNEL_ID_PM1CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE = "pm1concentrationmeasurement-averagemeasuredvalue";
public static final String CHANNEL_ID_PM10CONCENTRATIONMEASUREMENT_LEVELVALUE = "pm10concentrationmeasurement-levelvalue";
public static final String CHANNEL_ID_PM10CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE = "pm10concentrationmeasurement-peakmeasuredvalue";
public static final String CHANNEL_ID_PM10CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE = "pm10concentrationmeasurement-averagemeasuredvalue";
public static final String CHANNEL_ID_PM25CONCENTRATIONMEASUREMENT_LEVELVALUE = "pm25concentrationmeasurement-levelvalue";
public static final String CHANNEL_ID_PM25CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE = "pm25concentrationmeasurement-peakmeasuredvalue";
public static final String CHANNEL_ID_PM25CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE = "pm25concentrationmeasurement-averagemeasuredvalue";
public static final String CHANNEL_ID_OZONECONCENTRATIONMEASUREMENT_LEVELVALUE = "ozoneconcentrationmeasurement-levelvalue";
public static final String CHANNEL_ID_OZONECONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE = "ozoneconcentrationmeasurement-peakmeasuredvalue";
public static final String CHANNEL_ID_OZONECONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE = "ozoneconcentrationmeasurement-averagemeasuredvalue";
public static final String CHANNEL_ID_NITROGENDIOXIDECONCENTRATIONMEASUREMENT_LEVELVALUE = "nitrogendioxideconcentrationmeasurement-levelvalue";
public static final String CHANNEL_ID_NITROGENDIOXIDECONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE = "nitrogendioxideconcentrationmeasurement-peakmeasuredvalue";
public static final String CHANNEL_ID_NITROGENDIOXIDECONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE = "nitrogendioxideconcentrationmeasurement-averagemeasuredvalue";
public static final String CHANNEL_ID_FORMALDEHYDECONCENTRATIONMEASUREMENT_LEVELVALUE = "formaldehydeconcentrationmeasurement-levelvalue";
public static final String CHANNEL_ID_FORMALDEHYDECONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE = "formaldehydeconcentrationmeasurement-peakmeasuredvalue";
public static final String CHANNEL_ID_FORMALDEHYDECONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE = "formaldehydeconcentrationmeasurement-averagemeasuredvalue";
public static final String CHANNEL_ID_TOTALVOLATILEORGANICCOMPOUNDSCONCENTRATIONMEASUREMENT_LEVELVALUE = "totalvolatileorganiccompoundsconcentrationmeasurement-levelvalue";
public static final String CHANNEL_ID_TOTALVOLATILEORGANICCOMPOUNDSCONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE = "totalvolatileorganiccompoundsconcentrationmeasurement-peakmeasuredvalue";
public static final String CHANNEL_ID_TOTALVOLATILEORGANICCOMPOUNDSCONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE = "totalvolatileorganiccompoundsconcentrationmeasurement-averagemeasuredvalue";
public static final String CHANNEL_ID_RADONCONCENTRATIONMEASUREMENT_LEVELVALUE = "radonconcentrationmeasurement-levelvalue";
public static final String CHANNEL_ID_RADONCONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE = "radonconcentrationmeasurement-peakmeasuredvalue";
public static final String CHANNEL_ID_RADONCONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE = "radonconcentrationmeasurement-averagemeasuredvalue";
public static final String CHANNEL_ID_CONCENTRATIONMEASUREMENT_MEASUREDVALUE = "concentrationmeasurement-measuredvalue";
public static final ChannelTypeUID CHANNEL_CONCENTRATIONMEASUREMENT_MEASUREDVALUE = new ChannelTypeUID(BINDING_ID,
CHANNEL_ID_CONCENTRATIONMEASUREMENT_MEASUREDVALUE);
public static final String CHANNEL_ID_CONCENTRATIONMEASUREMENT_LEVELVALUE = "concentrationmeasurement-levelvalue";
public static final ChannelTypeUID CHANNEL_CONCENTRATIONMEASUREMENT_LEVELVALUE = new ChannelTypeUID(BINDING_ID,
CHANNEL_ID_CONCENTRATIONMEASUREMENT_LEVELVALUE);
public static final String CHANNEL_ID_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE = "concentrationmeasurement-peakmeasuredvalue";
public static final ChannelTypeUID CHANNEL_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE = new ChannelTypeUID(
BINDING_ID, CHANNEL_ID_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE);
public static final String CHANNEL_ID_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE = "concentrationmeasurement-averagemeasuredvalue";
public static final ChannelTypeUID CHANNEL_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE = new ChannelTypeUID(
BINDING_ID, CHANNEL_ID_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE);
public static final String CHANNEL_LABEL_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.carbondioxideconcentrationmeasurement-measuredvalue.label";
public static final String CHANNEL_DESC_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.carbondioxideconcentrationmeasurement-measuredvalue.description";
public static final String CHANNEL_LABEL_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.carbonmonoxideconcentrationmeasurement-measuredvalue.label";
public static final String CHANNEL_DESC_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.carbonmonoxideconcentrationmeasurement-measuredvalue.description";
public static final String CHANNEL_LABEL_PM1CONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.pm1concentrationmeasurement-measuredvalue.label";
public static final String CHANNEL_DESC_PM1CONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.pm1concentrationmeasurement-measuredvalue.description";
public static final String CHANNEL_LABEL_PM10CONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.pm10concentrationmeasurement-measuredvalue.label";
public static final String CHANNEL_DESC_PM10CONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.pm10concentrationmeasurement-measuredvalue.description";
public static final String CHANNEL_LABEL_PM25CONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.pm25concentrationmeasurement-measuredvalue.label";
public static final String CHANNEL_DESC_PM25CONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.pm25concentrationmeasurement-measuredvalue.description";
public static final String CHANNEL_LABEL_OZONECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.ozoneconcentrationmeasurement-measuredvalue.label";
public static final String CHANNEL_DESC_OZONECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.ozoneconcentrationmeasurement-measuredvalue.description";
public static final String CHANNEL_LABEL_NITROGENDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.nitrogendioxideconcentrationmeasurement-measuredvalue.label";
public static final String CHANNEL_DESC_NITROGENDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.nitrogendioxideconcentrationmeasurement-measuredvalue.description";
public static final String CHANNEL_LABEL_FORMALDEHYDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.formaldehydeconcentrationmeasurement-measuredvalue.label";
public static final String CHANNEL_DESC_FORMALDEHYDECONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.formaldehydeconcentrationmeasurement-measuredvalue.description";
public static final String CHANNEL_LABEL_TOTALVOLATILEORGANICCOMPOUNDSCONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.totalvolatileorganiccompoundsconcentrationmeasurement-measuredvalue.label";
public static final String CHANNEL_DESC_TOTALVOLATILEORGANICCOMPOUNDSCONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.totalvolatileorganiccompoundsconcentrationmeasurement-measuredvalue.description";
public static final String CHANNEL_LABEL_RADONCONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.radonconcentrationmeasurement-measuredvalue.label";
public static final String CHANNEL_DESC_RADONCONCENTRATIONMEASUREMENT_MEASUREDVALUE = "@text/channel-type.matter.radonconcentrationmeasurement-measuredvalue.description";
public static final String CHANNEL_ID_SMOKECOALARM_EXPRESSEDSTATE = "smokecoalarm-expressedstate";
public static final ChannelTypeUID CHANNEL_SMOKECOALARM_EXPRESSEDSTATE = new ChannelTypeUID(BINDING_ID,
CHANNEL_ID_SMOKECOALARM_EXPRESSEDSTATE);
@@ -0,0 +1,348 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.BaseCluster;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.handler.MatterBaseThingHandler;
import org.openhab.core.library.CoreItemFactory;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.StateDescriptionFragmentBuilder;
import org.openhab.core.types.UnDefType;
/**
* Abstract base converter for all concentration measurement clusters (CO2, CO, PM1, PM10, PM2.5, Ozone, NO2, etc.).
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
public abstract class AbstractConcentrationMeasurementConverter<T extends BaseCluster> extends GenericConverter<T> {
protected static final String ATTRIBUTE_MEASURED_VALUE = "measuredValue";
protected static final String ATTRIBUTE_MIN_MEASURED_VALUE = "minMeasuredValue";
protected static final String ATTRIBUTE_MAX_MEASURED_VALUE = "maxMeasuredValue";
protected static final String ATTRIBUTE_PEAK_MEASURED_VALUE = "peakMeasuredValue";
protected static final String ATTRIBUTE_AVERAGE_MEASURED_VALUE = "averageMeasuredValue";
protected static final String ATTRIBUTE_UNCERTAINTY = "uncertainty";
protected static final String ATTRIBUTE_MEASUREMENT_UNIT = "measurementUnit";
protected static final String ATTRIBUTE_MEASUREMENT_MEDIUM = "measurementMedium";
protected static final String ATTRIBUTE_LEVEL_VALUE = "levelValue";
private final String measuredValueChannelId;
private final ChannelTypeUID measuredValueChannelType;
private final String measuredValueLabel;
private final String measuredValueDescription;
private final String levelValueChannelId;
private final ChannelTypeUID levelValueChannelType;
private final String peakMeasuredValueChannelId;
private final ChannelTypeUID peakMeasuredValueChannelType;
private final String averageMeasuredValueChannelId;
private final ChannelTypeUID averageMeasuredValueChannelType;
@Nullable
private Unit<?> cachedUnit = null;
public AbstractConcentrationMeasurementConverter(T cluster, MatterBaseThingHandler handler, int endpointNumber,
String labelPrefix, String measuredValueChannelId, ChannelTypeUID measuredValueChannelType,
String measuredValueLabel, String measuredValueDescription, String levelValueChannelId,
ChannelTypeUID levelValueChannelType, String peakMeasuredValueChannelId,
ChannelTypeUID peakMeasuredValueChannelType, String averageMeasuredValueChannelId,
ChannelTypeUID averageMeasuredValueChannelType) {
super(cluster, handler, endpointNumber, labelPrefix);
this.measuredValueChannelId = measuredValueChannelId;
this.measuredValueChannelType = measuredValueChannelType;
this.measuredValueLabel = measuredValueLabel;
this.measuredValueDescription = measuredValueDescription;
this.levelValueChannelId = levelValueChannelId;
this.levelValueChannelType = levelValueChannelType;
this.peakMeasuredValueChannelId = peakMeasuredValueChannelId;
this.peakMeasuredValueChannelType = peakMeasuredValueChannelType;
this.averageMeasuredValueChannelId = averageMeasuredValueChannelId;
this.averageMeasuredValueChannelType = averageMeasuredValueChannelType;
}
@Override
public Map<Channel, @Nullable StateDescription> createChannels(ChannelGroupUID channelGroupUID) {
Map<Channel, @Nullable StateDescription> channels = new HashMap<>();
Channel measuredValueChannel = ChannelBuilder
.create(new ChannelUID(channelGroupUID, measuredValueChannelId), "Number:Dimensionless")
.withType(measuredValueChannelType).withLabel(measuredValueLabel)
.withDescription(measuredValueDescription).build();
StateDescription stateDescription = createStateDescriptionWithPattern();
channels.put(measuredValueChannel, stateDescription);
if (hasLevelIndication()) {
Channel levelValueChannel = ChannelBuilder
.create(new ChannelUID(channelGroupUID, levelValueChannelId), CoreItemFactory.NUMBER)
.withType(levelValueChannelType).build();
channels.put(levelValueChannel, null);
}
if (hasPeakMeasurement()) {
Channel peakChannel = ChannelBuilder
.create(new ChannelUID(channelGroupUID, peakMeasuredValueChannelId), "Number:Dimensionless")
.withType(peakMeasuredValueChannelType).build();
channels.put(peakChannel, null);
}
if (hasAverageMeasurement()) {
Channel averageChannel = ChannelBuilder
.create(new ChannelUID(channelGroupUID, averageMeasuredValueChannelId), "Number:Dimensionless")
.withType(averageMeasuredValueChannelType).build();
channels.put(averageChannel, null);
}
return channels;
}
/**
* Creates a StateDescription with an appropriate pattern based on the default unit.
*
* @return StateDescription with pattern, or null if pattern cannot be determined
*/
@Nullable
private StateDescription createStateDescriptionWithPattern() {
Unit<?> unit = getDefaultUnit();
String pattern = getPatternForUnit(unit);
if (pattern != null) {
return StateDescriptionFragmentBuilder.create().withPattern(pattern).withReadOnly(true).build()
.toStateDescription();
}
return null;
}
/**
* Gets the display pattern for a given unit.
*
* @param unit The unit to get the pattern for
* @return Pattern string or null if no specific pattern
*/
@Nullable
private String getPatternForUnit(Unit<?> unit) {
if (unit.equals(Units.PARTS_PER_MILLION)) {
return "%.2f ppm";
} else if (unit.equals(Units.PARTS_PER_BILLION)) {
return "%.2f ppb";
} else if (unit.equals(Units.MICROGRAM_PER_CUBICMETRE)) {
return "%.1f µg/m³";
} else if (unit.equals(Units.ONE)) {
// Dimensionless/unknown - no specific pattern
return "%.2f";
}
return null;
}
@Override
public void onEvent(AttributeChangedMessage message) {
switch (message.path.attributeName) {
case ATTRIBUTE_MEASURED_VALUE:
if (message.value instanceof Number number) {
updateState(measuredValueChannelId, toQuantityType(number));
}
break;
case ATTRIBUTE_LEVEL_VALUE:
if (message.value instanceof Number number) {
updateState(levelValueChannelId, new DecimalType(number.intValue()));
}
break;
case ATTRIBUTE_PEAK_MEASURED_VALUE:
if (message.value instanceof Number number) {
updateState(peakMeasuredValueChannelId, toQuantityType(number));
}
break;
case ATTRIBUTE_AVERAGE_MEASURED_VALUE:
if (message.value instanceof Number number) {
updateState(averageMeasuredValueChannelId, toQuantityType(number));
}
break;
case ATTRIBUTE_MEASUREMENT_UNIT:
// Unit changed - clear cache so it gets recalculated
cachedUnit = null;
break;
}
super.onEvent(message);
}
@Override
public void initState() {
Float measuredValue = getFloatAttribute("measuredValue");
if (measuredValue != null) {
updateState(measuredValueChannelId, toQuantityType(measuredValue));
} else {
updateState(measuredValueChannelId, UnDefType.NULL);
}
if (hasLevelIndication()) {
Object levelValue = getClusterAttribute("levelValue");
if (levelValue != null) {
Integer levelInt = getEnumValue(levelValue);
if (levelInt != null) {
updateState(levelValueChannelId, new DecimalType(levelInt));
} else {
updateState(levelValueChannelId, UnDefType.NULL);
}
} else {
updateState(levelValueChannelId, UnDefType.NULL);
}
}
if (hasPeakMeasurement()) {
Float peakMeasuredValue = getFloatAttribute("peakMeasuredValue");
if (peakMeasuredValue != null) {
updateState(peakMeasuredValueChannelId, toQuantityType(peakMeasuredValue));
} else {
updateState(peakMeasuredValueChannelId, UnDefType.NULL);
}
}
if (hasAverageMeasurement()) {
Float averageMeasuredValue = getFloatAttribute("averageMeasuredValue");
if (averageMeasuredValue != null) {
updateState(averageMeasuredValueChannelId, toQuantityType(averageMeasuredValue));
} else {
updateState(averageMeasuredValueChannelId, UnDefType.NULL);
}
}
}
/**
* Converts a numeric value to a QuantityType using the appropriate unit from the device's measurementUnit
* attribute.
*/
protected QuantityType<?> toQuantityType(Number value) {
Unit<?> unit = getUnit();
return new QuantityType<>(BigDecimal.valueOf(value.doubleValue()), unit);
}
/**
* Gets the appropriate openHAB Unit based on the device's measurementUnit attribute.
* Caches the unit to avoid repeated reflection calls.
*/
protected Unit<?> getUnit() {
Unit<?> unit = cachedUnit;
if (unit != null) {
return unit;
}
Object measurementUnit = getClusterAttribute("measurementUnit");
if (measurementUnit == null) {
unit = getDefaultUnit();
cachedUnit = unit;
return unit;
}
Integer unitValue = getEnumValue(measurementUnit);
if (unitValue == null) {
unit = getDefaultUnit();
cachedUnit = unit;
return unit;
}
unit = measurementUnitToOpenHABUnit(unitValue);
cachedUnit = unit;
return unit;
}
/**
* Maps Matter MeasurementUnitEnum values to openHAB Units.
*
* @param unitValue The enum value from MeasurementUnitEnum
* @return The corresponding openHAB Unit
*/
protected Unit<?> measurementUnitToOpenHABUnit(Integer unitValue) {
return switch (unitValue) {
case 0 -> Units.PARTS_PER_MILLION;
case 4 -> Units.MICROGRAM_PER_CUBICMETRE;
case 1, 2, 3, 5, 6, 7 -> Units.ONE; // PPB, PPT, MGM3, NGM3, PM3, BQM3
default -> getDefaultUnit();
};
}
/**
* Returns the default unit for this cluster type.
*/
protected abstract Unit<?> getDefaultUnit();
/**
* Checks if the device supports the LevelIndication feature.
*/
protected abstract boolean hasLevelIndication();
/**
* Checks if the device supports the PeakMeasurement feature.
*/
protected abstract boolean hasPeakMeasurement();
/**
* Checks if the device supports the AverageMeasurement feature.
*/
protected abstract boolean hasAverageMeasurement();
/**
* Helper method to get a Float attribute from the cluster.
*/
@Nullable
protected Float getFloatAttribute(String attributeName) {
Object value = getClusterAttribute(attributeName);
return value instanceof Float f ? f : null;
}
/**
* Helper method to get any attribute from the cluster.
*/
@Nullable
protected Object getClusterAttribute(String attributeName) {
try {
var field = initializingCluster.getClass().getField(attributeName);
return field.get(initializingCluster);
} catch (NoSuchFieldException | IllegalAccessException e) {
logger.debug("Could not access attribute {}: {}", attributeName, e.getMessage());
return null;
}
}
/**
* Extracts the integer value from a Matter enum object (LevelValueEnum, MeasurementUnitEnum, etc.).
*
*/
@Nullable
protected Integer getEnumValue(Object enumValue) {
try {
var method = enumValue.getClass().getMethod("getValue");
Object result = method.invoke(enumValue);
return result instanceof Integer i ? i : null;
} catch (Exception e) {
logger.debug("Could not extract enum value: {}", e.getMessage());
return null;
}
}
}
@@ -12,25 +12,14 @@
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.openhab.binding.matter.internal.MatterBindingConstants.CHANNEL_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE;
import static org.openhab.binding.matter.internal.MatterBindingConstants.CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE;
import static org.openhab.binding.matter.internal.MatterBindingConstants.*;
import java.util.Collections;
import java.util.Map;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.CarbonDioxideConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.handler.MatterBaseThingHandler;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.UnDefType;
/**
* A converter for translating {@link CarbonDioxideConcentrationMeasurementCluster} events and attributes to openHAB
@@ -40,43 +29,40 @@ import org.openhab.core.types.UnDefType;
*/
@NonNullByDefault
public class CarbonDioxideConcentrationMeasurementConverter
extends GenericConverter<CarbonDioxideConcentrationMeasurementCluster> {
extends AbstractConcentrationMeasurementConverter<CarbonDioxideConcentrationMeasurementCluster> {
public CarbonDioxideConcentrationMeasurementConverter(CarbonDioxideConcentrationMeasurementCluster cluster,
MatterBaseThingHandler handler, int endpointNumber, String labelPrefix) {
super(cluster, handler, endpointNumber, labelPrefix);
super(cluster, handler, endpointNumber, labelPrefix,
CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_LABEL_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_DESC_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE);
}
@Override
public Map<Channel, @Nullable StateDescription> createChannels(ChannelGroupUID channelGroupUID) {
Channel channel = ChannelBuilder
.create(new ChannelUID(channelGroupUID, CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE),
"Number:Dimensionless")
.withType(CHANNEL_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE).build();
return Collections.singletonMap(channel, null);
protected Unit<?> getDefaultUnit() {
return Units.PARTS_PER_MILLION;
}
@Override
public void onEvent(AttributeChangedMessage message) {
switch (message.path.attributeName) {
case CarbonDioxideConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE:
if (message.value instanceof Number number) {
updateState(CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
new QuantityType<>(number, Units.PARTS_PER_MILLION));
}
break;
}
super.onEvent(message);
protected boolean hasLevelIndication() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.levelIndication;
}
@Override
public void initState() {
Float measuredValue = initializingCluster.measuredValue;
if (measuredValue != null) {
updateState(CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
new QuantityType<>(measuredValue, Units.PARTS_PER_MILLION));
} else {
updateState(CHANNEL_ID_CARBONDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE, UnDefType.NULL);
}
protected boolean hasPeakMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.peakMeasurement;
}
@Override
protected boolean hasAverageMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.averageMeasurement;
}
}
@@ -12,25 +12,14 @@
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.openhab.binding.matter.internal.MatterBindingConstants.CHANNEL_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE;
import static org.openhab.binding.matter.internal.MatterBindingConstants.CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE;
import static org.openhab.binding.matter.internal.MatterBindingConstants.*;
import java.util.Collections;
import java.util.Map;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.CarbonMonoxideConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.handler.MatterBaseThingHandler;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.UnDefType;
/**
* A converter for translating {@link CarbonMonoxideConcentrationMeasurementCluster} events and attributes to openHAB
@@ -40,43 +29,40 @@ import org.openhab.core.types.UnDefType;
*/
@NonNullByDefault
public class CarbonMonoxideConcentrationMeasurementConverter
extends GenericConverter<CarbonMonoxideConcentrationMeasurementCluster> {
extends AbstractConcentrationMeasurementConverter<CarbonMonoxideConcentrationMeasurementCluster> {
public CarbonMonoxideConcentrationMeasurementConverter(CarbonMonoxideConcentrationMeasurementCluster cluster,
MatterBaseThingHandler handler, int endpointNumber, String labelPrefix) {
super(cluster, handler, endpointNumber, labelPrefix);
super(cluster, handler, endpointNumber, labelPrefix,
CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_LABEL_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_DESC_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE);
}
@Override
public Map<Channel, @Nullable StateDescription> createChannels(ChannelGroupUID channelGroupUID) {
Channel channel = ChannelBuilder
.create(new ChannelUID(channelGroupUID,
CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE), "Number:Dimensionless")
.withType(CHANNEL_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE).build();
return Collections.singletonMap(channel, null);
protected Unit<?> getDefaultUnit() {
return Units.PARTS_PER_MILLION;
}
@Override
public void onEvent(AttributeChangedMessage message) {
switch (message.path.attributeName) {
case CarbonMonoxideConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE:
if (message.value instanceof Number number) {
updateState(CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
new QuantityType<>(number, Units.PARTS_PER_MILLION));
}
break;
}
super.onEvent(message);
protected boolean hasLevelIndication() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.levelIndication;
}
@Override
public void initState() {
Float measuredValue = initializingCluster.measuredValue;
if (measuredValue != null) {
updateState(CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
new QuantityType<>(measuredValue, Units.PARTS_PER_MILLION));
} else {
updateState(CHANNEL_ID_CARBONMONOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE, UnDefType.NULL);
}
protected boolean hasPeakMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.peakMeasurement;
}
@Override
protected boolean hasAverageMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.averageMeasurement;
}
}
@@ -28,12 +28,19 @@ import org.openhab.binding.matter.internal.client.dto.cluster.gen.DoorLockCluste
import org.openhab.binding.matter.internal.client.dto.cluster.gen.ElectricalEnergyMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.ElectricalPowerMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.FanControlCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.FormaldehydeConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.IlluminanceMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.LevelControlCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.ModeSelectCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.NitrogenDioxideConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.OccupancySensingCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.OnOffCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.OzoneConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm10ConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm1ConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm25ConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.PowerSourceCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.RadonConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.RelativeHumidityMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.SmokeCoAlarmCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.SwitchCluster;
@@ -41,6 +48,7 @@ import org.openhab.binding.matter.internal.client.dto.cluster.gen.TemperatureMea
import org.openhab.binding.matter.internal.client.dto.cluster.gen.ThermostatCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.ThreadBorderRouterManagementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.ThreadNetworkDiagnosticsCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.TotalVolatileOrganicCompoundsConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.WiFiNetworkDiagnosticsCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.WindowCoveringCluster;
import org.openhab.binding.matter.internal.handler.MatterBaseThingHandler;
@@ -80,6 +88,22 @@ public class ConverterRegistry {
CarbonDioxideConcentrationMeasurementConverter.class);
ConverterRegistry.registerConverter(CarbonMonoxideConcentrationMeasurementCluster.CLUSTER_ID,
CarbonMonoxideConcentrationMeasurementConverter.class);
ConverterRegistry.registerConverter(Pm1ConcentrationMeasurementCluster.CLUSTER_ID,
Pm1ConcentrationMeasurementConverter.class);
ConverterRegistry.registerConverter(Pm10ConcentrationMeasurementCluster.CLUSTER_ID,
Pm10ConcentrationMeasurementConverter.class);
ConverterRegistry.registerConverter(Pm25ConcentrationMeasurementCluster.CLUSTER_ID,
Pm25ConcentrationMeasurementConverter.class);
ConverterRegistry.registerConverter(OzoneConcentrationMeasurementCluster.CLUSTER_ID,
OzoneConcentrationMeasurementConverter.class);
ConverterRegistry.registerConverter(NitrogenDioxideConcentrationMeasurementCluster.CLUSTER_ID,
NitrogenDioxideConcentrationMeasurementConverter.class);
ConverterRegistry.registerConverter(FormaldehydeConcentrationMeasurementCluster.CLUSTER_ID,
FormaldehydeConcentrationMeasurementConverter.class);
ConverterRegistry.registerConverter(TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.CLUSTER_ID,
TotalVolatileOrganicCompoundsConcentrationMeasurementConverter.class);
ConverterRegistry.registerConverter(RadonConcentrationMeasurementCluster.CLUSTER_ID,
RadonConcentrationMeasurementConverter.class);
ConverterRegistry.registerConverter(SmokeCoAlarmCluster.CLUSTER_ID, SmokeCoAlarmConverter.class);
ConverterRegistry.registerConverter(ElectricalPowerMeasurementCluster.CLUSTER_ID,
ElectricalPowerMeasurementConverter.class);
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.openhab.binding.matter.internal.MatterBindingConstants.*;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.FormaldehydeConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.handler.MatterBaseThingHandler;
import org.openhab.core.library.unit.Units;
/**
* A converter for translating {@link FormaldehydeConcentrationMeasurementCluster} events and attributes to openHAB
* channels.
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
public class FormaldehydeConcentrationMeasurementConverter
extends AbstractConcentrationMeasurementConverter<FormaldehydeConcentrationMeasurementCluster> {
public FormaldehydeConcentrationMeasurementConverter(FormaldehydeConcentrationMeasurementCluster cluster,
MatterBaseThingHandler handler, int endpointNumber, String labelPrefix) {
super(cluster, handler, endpointNumber, labelPrefix,
CHANNEL_ID_FORMALDEHYDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_LABEL_FORMALDEHYDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_DESC_FORMALDEHYDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_ID_FORMALDEHYDECONCENTRATIONMEASUREMENT_LEVELVALUE, CHANNEL_CONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_ID_FORMALDEHYDECONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_ID_FORMALDEHYDECONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE);
}
@Override
protected Unit<?> getDefaultUnit() {
return Units.PARTS_PER_MILLION;
}
@Override
protected boolean hasLevelIndication() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.levelIndication;
}
@Override
protected boolean hasPeakMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.peakMeasurement;
}
@Override
protected boolean hasAverageMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.averageMeasurement;
}
}
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.openhab.binding.matter.internal.MatterBindingConstants.*;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.NitrogenDioxideConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.handler.MatterBaseThingHandler;
import org.openhab.core.library.unit.Units;
/**
* A converter for translating {@link NitrogenDioxideConcentrationMeasurementCluster} events and attributes to openHAB
* channels.
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
public class NitrogenDioxideConcentrationMeasurementConverter
extends AbstractConcentrationMeasurementConverter<NitrogenDioxideConcentrationMeasurementCluster> {
public NitrogenDioxideConcentrationMeasurementConverter(NitrogenDioxideConcentrationMeasurementCluster cluster,
MatterBaseThingHandler handler, int endpointNumber, String labelPrefix) {
super(cluster, handler, endpointNumber, labelPrefix,
CHANNEL_ID_NITROGENDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_LABEL_NITROGENDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_DESC_NITROGENDIOXIDECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_ID_NITROGENDIOXIDECONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_ID_NITROGENDIOXIDECONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_ID_NITROGENDIOXIDECONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE);
}
@Override
protected Unit<?> getDefaultUnit() {
return Units.PARTS_PER_MILLION;
}
@Override
protected boolean hasLevelIndication() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.levelIndication;
}
@Override
protected boolean hasPeakMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.peakMeasurement;
}
@Override
protected boolean hasAverageMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.averageMeasurement;
}
}
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.openhab.binding.matter.internal.MatterBindingConstants.*;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.OzoneConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.handler.MatterBaseThingHandler;
import org.openhab.core.library.unit.Units;
/**
* A converter for translating {@link OzoneConcentrationMeasurementCluster} events and attributes to openHAB
* channels.
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
public class OzoneConcentrationMeasurementConverter
extends AbstractConcentrationMeasurementConverter<OzoneConcentrationMeasurementCluster> {
public OzoneConcentrationMeasurementConverter(OzoneConcentrationMeasurementCluster cluster,
MatterBaseThingHandler handler, int endpointNumber, String labelPrefix) {
super(cluster, handler, endpointNumber, labelPrefix, CHANNEL_ID_OZONECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_LABEL_OZONECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_DESC_OZONECONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_ID_OZONECONCENTRATIONMEASUREMENT_LEVELVALUE, CHANNEL_CONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_ID_OZONECONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_ID_OZONECONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE);
}
@Override
protected Unit<?> getDefaultUnit() {
return Units.PARTS_PER_MILLION;
}
@Override
protected boolean hasLevelIndication() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.levelIndication;
}
@Override
protected boolean hasPeakMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.peakMeasurement;
}
@Override
protected boolean hasAverageMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.averageMeasurement;
}
}
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.openhab.binding.matter.internal.MatterBindingConstants.*;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm10ConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.handler.MatterBaseThingHandler;
import org.openhab.core.library.unit.Units;
/**
* A converter for translating {@link Pm10ConcentrationMeasurementCluster} events and attributes to openHAB
* channels.
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
public class Pm10ConcentrationMeasurementConverter
extends AbstractConcentrationMeasurementConverter<Pm10ConcentrationMeasurementCluster> {
public Pm10ConcentrationMeasurementConverter(Pm10ConcentrationMeasurementCluster cluster,
MatterBaseThingHandler handler, int endpointNumber, String labelPrefix) {
super(cluster, handler, endpointNumber, labelPrefix, CHANNEL_ID_PM10CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_LABEL_PM10CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_DESC_PM10CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_ID_PM10CONCENTRATIONMEASUREMENT_LEVELVALUE, CHANNEL_CONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_ID_PM10CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_ID_PM10CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE);
}
@Override
protected Unit<?> getDefaultUnit() {
return Units.MICROGRAM_PER_CUBICMETRE;
}
@Override
protected boolean hasLevelIndication() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.levelIndication;
}
@Override
protected boolean hasPeakMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.peakMeasurement;
}
@Override
protected boolean hasAverageMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.averageMeasurement;
}
}
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.openhab.binding.matter.internal.MatterBindingConstants.*;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm1ConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.handler.MatterBaseThingHandler;
import org.openhab.core.library.unit.Units;
/**
* A converter for translating {@link Pm1ConcentrationMeasurementCluster} events and attributes to openHAB
* channels.
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
public class Pm1ConcentrationMeasurementConverter
extends AbstractConcentrationMeasurementConverter<Pm1ConcentrationMeasurementCluster> {
public Pm1ConcentrationMeasurementConverter(Pm1ConcentrationMeasurementCluster cluster,
MatterBaseThingHandler handler, int endpointNumber, String labelPrefix) {
super(cluster, handler, endpointNumber, labelPrefix, CHANNEL_ID_PM1CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_MEASUREDVALUE, CHANNEL_LABEL_PM1CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_DESC_PM1CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_ID_PM1CONCENTRATIONMEASUREMENT_LEVELVALUE, CHANNEL_CONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_ID_PM1CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_ID_PM1CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE);
}
@Override
protected Unit<?> getDefaultUnit() {
return Units.MICROGRAM_PER_CUBICMETRE;
}
@Override
protected boolean hasLevelIndication() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.levelIndication;
}
@Override
protected boolean hasPeakMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.peakMeasurement;
}
@Override
protected boolean hasAverageMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.averageMeasurement;
}
}
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.openhab.binding.matter.internal.MatterBindingConstants.*;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm25ConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.handler.MatterBaseThingHandler;
import org.openhab.core.library.unit.Units;
/**
* A converter for translating {@link Pm25ConcentrationMeasurementCluster} events and attributes to openHAB
* channels.
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
public class Pm25ConcentrationMeasurementConverter
extends AbstractConcentrationMeasurementConverter<Pm25ConcentrationMeasurementCluster> {
public Pm25ConcentrationMeasurementConverter(Pm25ConcentrationMeasurementCluster cluster,
MatterBaseThingHandler handler, int endpointNumber, String labelPrefix) {
super(cluster, handler, endpointNumber, labelPrefix, CHANNEL_ID_PM25CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_LABEL_PM25CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_DESC_PM25CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_ID_PM25CONCENTRATIONMEASUREMENT_LEVELVALUE, CHANNEL_CONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_ID_PM25CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_ID_PM25CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE);
}
@Override
protected Unit<?> getDefaultUnit() {
return Units.MICROGRAM_PER_CUBICMETRE;
}
@Override
protected boolean hasLevelIndication() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.levelIndication;
}
@Override
protected boolean hasPeakMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.peakMeasurement;
}
@Override
protected boolean hasAverageMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.averageMeasurement;
}
}
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.openhab.binding.matter.internal.MatterBindingConstants.*;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.RadonConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.handler.MatterBaseThingHandler;
import org.openhab.core.library.unit.Units;
/**
* A converter for translating {@link RadonConcentrationMeasurementCluster} events and attributes to openHAB
* channels.
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
public class RadonConcentrationMeasurementConverter
extends AbstractConcentrationMeasurementConverter<RadonConcentrationMeasurementCluster> {
public RadonConcentrationMeasurementConverter(RadonConcentrationMeasurementCluster cluster,
MatterBaseThingHandler handler, int endpointNumber, String labelPrefix) {
super(cluster, handler, endpointNumber, labelPrefix, CHANNEL_ID_RADONCONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_LABEL_RADONCONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_DESC_RADONCONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_ID_RADONCONCENTRATIONMEASUREMENT_LEVELVALUE, CHANNEL_CONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_ID_RADONCONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_ID_RADONCONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE);
}
@Override
protected Unit<?> getDefaultUnit() {
// Radon measurements typically use Bq/m³ (Becquerels per cubic meter)
// we don't have this unit, so use dimensionless
return Units.ONE;
}
@Override
protected boolean hasLevelIndication() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.levelIndication;
}
@Override
protected boolean hasPeakMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.peakMeasurement;
}
@Override
protected boolean hasAverageMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.averageMeasurement;
}
}
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.openhab.binding.matter.internal.MatterBindingConstants.*;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.TotalVolatileOrganicCompoundsConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.handler.MatterBaseThingHandler;
import org.openhab.core.library.unit.Units;
/**
* A converter for translating {@link TotalVolatileOrganicCompoundsConcentrationMeasurementCluster} events and
* attributes to openHAB channels.
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
public class TotalVolatileOrganicCompoundsConcentrationMeasurementConverter extends
AbstractConcentrationMeasurementConverter<TotalVolatileOrganicCompoundsConcentrationMeasurementCluster> {
public TotalVolatileOrganicCompoundsConcentrationMeasurementConverter(
TotalVolatileOrganicCompoundsConcentrationMeasurementCluster cluster, MatterBaseThingHandler handler,
int endpointNumber, String labelPrefix) {
super(cluster, handler, endpointNumber, labelPrefix,
CHANNEL_ID_TOTALVOLATILEORGANICCOMPOUNDSCONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_LABEL_TOTALVOLATILEORGANICCOMPOUNDSCONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_DESC_TOTALVOLATILEORGANICCOMPOUNDSCONCENTRATIONMEASUREMENT_MEASUREDVALUE,
CHANNEL_ID_TOTALVOLATILEORGANICCOMPOUNDSCONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_LEVELVALUE,
CHANNEL_ID_TOTALVOLATILEORGANICCOMPOUNDSCONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_PEAKMEASUREDVALUE,
CHANNEL_ID_TOTALVOLATILEORGANICCOMPOUNDSCONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE,
CHANNEL_CONCENTRATIONMEASUREMENT_AVERAGEMEASUREDVALUE);
}
@Override
protected Unit<?> getDefaultUnit() {
return Units.PARTS_PER_MILLION;
}
@Override
protected boolean hasLevelIndication() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.levelIndication;
}
@Override
protected boolean hasPeakMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.peakMeasurement;
}
@Override
protected boolean hasAverageMeasurement() {
return initializingCluster.featureMap != null && initializingCluster.featureMap.averageMeasurement;
}
}
@@ -62,16 +62,25 @@ channel-type.matter.airquality-airquality.state.option.5 = Very Poor
channel-type.matter.airquality-airquality.state.option.6 = Extremely Poor
channel-type.matter.booleanstate-statevalue.label = Boolean State
channel-type.matter.booleanstate-statevalue.description = Indicates a boolean, true or false, value
channel-type.matter.carbondioxideconcentrationmeasurement-measuredvalue.label = CO2 Concentration
channel-type.matter.carbondioxideconcentrationmeasurement-measuredvalue.description = Indicates the measured carbon dioxide concentration in parts per million (ppm).
channel-type.matter.carbonmonoxideconcentrationmeasurement-measuredvalue.label = CO Concentration
channel-type.matter.carbonmonoxideconcentrationmeasurement-measuredvalue.description = Indicates the measured carbon monoxide concentration in parts per million (ppm).
channel-type.matter.colorcontrol-color.label = Color
channel-type.matter.colorcontrol-color.description = The color channel allows to control the color of a light. It is also possible to dim values and switch the light on and off.
channel-type.matter.colorcontrol-temperature-abs.label = Color Temperature
channel-type.matter.colorcontrol-temperature-abs.description = Sets the color temperature of the light in mirek
channel-type.matter.colorcontrol-temperature.label = Color Temperature
channel-type.matter.colorcontrol-temperature.description = Sets the color temperature of the light
channel-type.matter.concentrationmeasurement-averagemeasuredvalue.label = Average Concentration
channel-type.matter.concentrationmeasurement-averagemeasuredvalue.description = Indicates the average concentration measured during the measurement window.
channel-type.matter.concentrationmeasurement-levelvalue.label = Concentration Level
channel-type.matter.concentrationmeasurement-levelvalue.description = Indicates the concentration level as an enumeration (0=Unknown, 1=Low, 2=Medium, 3=High, 4=Critical).
channel-type.matter.concentrationmeasurement-levelvalue.state.option.0 = Unknown
channel-type.matter.concentrationmeasurement-levelvalue.state.option.1 = Low
channel-type.matter.concentrationmeasurement-levelvalue.state.option.2 = Medium
channel-type.matter.concentrationmeasurement-levelvalue.state.option.3 = High
channel-type.matter.concentrationmeasurement-levelvalue.state.option.4 = Critical
channel-type.matter.concentrationmeasurement-measuredvalue.label = Concentration
channel-type.matter.concentrationmeasurement-measuredvalue.description = Indicates the measured concentration.
channel-type.matter.concentrationmeasurement-peakmeasuredvalue.label = Peak Concentration
channel-type.matter.concentrationmeasurement-peakmeasuredvalue.description = Indicates the peak (maximum) concentration measured during the measurement window.
channel-type.matter.doorlock-alarm.label = Door Lock Alarm
channel-type.matter.doorlock-alarm.description = Event that fires when a lock alarm occurs with a payload containing the alarm code
channel-type.matter.doorlock-doorstate.label = Door Sensor State
@@ -235,6 +244,29 @@ channel-type.matter.wifinetworkdiagnostics-rssi.description = Wi-Fi signal stren
channel-type.matter.windowcovering-lift.label = Window Covering Lift
channel-type.matter.windowcovering-lift.description = Sets the window covering level - supporting open/close and up/down type commands
# channel types
channel-type.matter.carbondioxideconcentrationmeasurement-measuredvalue.label = CO2 Concentration
channel-type.matter.carbondioxideconcentrationmeasurement-measuredvalue.description = Indicates the measured carbon dioxide concentration in parts per million (ppm).
channel-type.matter.carbonmonoxideconcentrationmeasurement-measuredvalue.label = CO Concentration
channel-type.matter.carbonmonoxideconcentrationmeasurement-measuredvalue.description = Indicates the measured carbon monoxide concentration in parts per million (ppm).
channel-type.matter.pm1concentrationmeasurement-measuredvalue.label = PM1 Concentration
channel-type.matter.pm1concentrationmeasurement-measuredvalue.description = Indicates the measured PM1 particulate matter concentration in micrograms per cubic meter (µg/m³).
channel-type.matter.pm10concentrationmeasurement-measuredvalue.label = PM10 Concentration
channel-type.matter.pm10concentrationmeasurement-measuredvalue.description = Indicates the measured PM10 particulate matter concentration in micrograms per cubic meter (µg/m³).
channel-type.matter.pm25concentrationmeasurement-measuredvalue.label = PM2.5 Concentration
channel-type.matter.pm25concentrationmeasurement-measuredvalue.description = Indicates the measured PM2.5 particulate matter concentration in micrograms per cubic meter (µg/m³).
channel-type.matter.ozoneconcentrationmeasurement-measuredvalue.label = Ozone Concentration
channel-type.matter.ozoneconcentrationmeasurement-measuredvalue.description = Indicates the measured ozone (O₃) concentration.
channel-type.matter.nitrogendioxideconcentrationmeasurement-measuredvalue.label = NO₂ Concentration
channel-type.matter.nitrogendioxideconcentrationmeasurement-measuredvalue.description = Indicates the measured nitrogen dioxide concentration.
channel-type.matter.formaldehydeconcentrationmeasurement-measuredvalue.label = Formaldehyde Concentration
channel-type.matter.formaldehydeconcentrationmeasurement-measuredvalue.description = Indicates the measured formaldehyde (HCHO) concentration.
channel-type.matter.totalvolatileorganiccompoundsconcentrationmeasurement-measuredvalue.label = TVOC Concentration
channel-type.matter.totalvolatileorganiccompoundsconcentrationmeasurement-measuredvalue.description = Indicates the measured total volatile organic compounds concentration.
channel-type.matter.radonconcentrationmeasurement-measuredvalue.label = Radon Concentration
channel-type.matter.radonconcentrationmeasurement-measuredvalue.description = Indicates the measured radon (Rn) concentration in Becquerels per cubic meter.
# thread border router configuration
thing-type.config.matter.node.thread_border_router_operational_dataset.label = Thread Border Router Operational Dataset
@@ -564,28 +564,57 @@
</state>
</channel-type>
<channel-type id="carbondioxideconcentrationmeasurement-measuredvalue">
<item-type unitHint="ppm">Number:Dimensionless</item-type>
<label>CO2 Concentration</label>
<description>Indicates the measured carbon dioxide concentration in parts per million (ppm).</description>
<category>CarbonDioxide</category>
<!-- Generic Concentration Measurement Channels (shared across all concentration measurement clusters) -->
<channel-type id="concentrationmeasurement-measuredvalue">
<item-type>Number:Dimensionless</item-type>
<label>Concentration</label>
<description>Indicates the measured concentration.</description>
<category>QualityOfService</category>
<tags>
<tag>Measurement</tag>
<tag>CO2</tag>
</tags>
<state pattern="%.0f ppm" readOnly="true"/>
<state readOnly="true"/>
</channel-type>
<channel-type id="carbonmonoxideconcentrationmeasurement-measuredvalue">
<item-type unitHint="ppm">Number:Dimensionless</item-type>
<label>CO Concentration</label>
<description>Indicates the measured carbon monoxide concentration in parts per million (ppm).</description>
<category>Alarm</category>
<channel-type id="concentrationmeasurement-levelvalue">
<item-type>Number</item-type>
<label>Concentration Level</label>
<description>Indicates the concentration level as an enumeration (0=Unknown, 1=Low, 2=Medium, 3=High, 4=Critical).</description>
<category>QualityOfService</category>
<tags>
<tag>Status</tag>
</tags>
<state readOnly="true">
<options>
<option value="0">Unknown</option>
<option value="1">Low</option>
<option value="2">Medium</option>
<option value="3">High</option>
<option value="4">Critical</option>
</options>
</state>
</channel-type>
<channel-type id="concentrationmeasurement-peakmeasuredvalue">
<item-type>Number:Dimensionless</item-type>
<label>Peak Concentration</label>
<description>Indicates the peak (maximum) concentration measured during the measurement window.</description>
<category>Chart</category>
<tags>
<tag>Measurement</tag>
<tag>CO</tag>
</tags>
<state pattern="%.0f ppm" readOnly="true"/>
<state readOnly="true"/>
</channel-type>
<channel-type id="concentrationmeasurement-averagemeasuredvalue">
<item-type>Number:Dimensionless</item-type>
<label>Average Concentration</label>
<description>Indicates the average concentration measured during the measurement window.</description>
<category>Chart</category>
<tags>
<tag>Measurement</tag>
</tags>
<state readOnly="true"/>
</channel-type>
<!-- Smoke/CO Alarm Channels -->
@@ -13,6 +13,7 @@
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -25,8 +26,12 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.CarbonDioxideConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.CarbonDioxideConcentrationMeasurementCluster.FeatureMap;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.CarbonDioxideConcentrationMeasurementCluster.LevelValueEnum;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.CarbonDioxideConcentrationMeasurementCluster.MeasurementUnitEnum;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.client.dto.ws.Path;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
@@ -53,6 +58,8 @@ class CarbonDioxideConcentrationMeasurementConverterTest extends BaseMatterConve
void setUp() {
super.setUp();
mockCluster.measuredValue = 400.0f;
mockCluster.measurementUnit = MeasurementUnitEnum.PPM;
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, false);
converter = new CarbonDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
}
@@ -67,6 +74,36 @@ class CarbonDioxideConcentrationMeasurementConverterTest extends BaseMatterConve
assertEquals("Number:Dimensionless", channel.getAcceptedItemType());
}
@Test
void testCreateChannelsWithAllFeatures() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new CarbonDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(4, channels.size());
Channel measuredValueChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#carbondioxideconcentrationmeasurement-measuredvalue"))
.findFirst().orElse(null);
assertNotNull(measuredValueChannel);
Channel levelChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#carbondioxideconcentrationmeasurement-levelvalue"))
.findFirst().orElse(null);
assertNotNull(levelChannel);
Channel peakChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#carbondioxideconcentrationmeasurement-peakmeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(peakChannel);
Channel averageChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#carbondioxideconcentrationmeasurement-averagemeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(averageChannel);
}
@Test
void testOnEventWithMeasuredValue() {
AttributeChangedMessage message = new AttributeChangedMessage();
@@ -78,6 +115,49 @@ class CarbonDioxideConcentrationMeasurementConverterTest extends BaseMatterConve
eq(new QuantityType<>(800.0f, Units.PARTS_PER_MILLION)));
}
@Test
void testOnEventWithLevelValue() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, false, false);
converter = new CarbonDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = CarbonDioxideConcentrationMeasurementCluster.ATTRIBUTE_LEVEL_VALUE;
message.value = 2;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("carbondioxideconcentrationmeasurement-levelvalue"),
eq(new DecimalType(2)));
}
@Test
void testOnEventWithPeakMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, true, false);
converter = new CarbonDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = CarbonDioxideConcentrationMeasurementCluster.ATTRIBUTE_PEAK_MEASURED_VALUE;
message.value = 1200.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("carbondioxideconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(1200.0f, Units.PARTS_PER_MILLION)));
}
@Test
void testOnEventWithAverageMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, true);
converter = new CarbonDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = CarbonDioxideConcentrationMeasurementCluster.ATTRIBUTE_AVERAGE_MEASURED_VALUE;
message.value = 600.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1),
eq("carbondioxideconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(600.0f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitState() {
mockCluster.measuredValue = 1000.0f;
@@ -86,6 +166,27 @@ class CarbonDioxideConcentrationMeasurementConverterTest extends BaseMatterConve
eq(new QuantityType<>(1000.0f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitStateWithAllAttributes() {
mockCluster.measuredValue = 1000.0f;
mockCluster.levelValue = LevelValueEnum.MEDIUM;
mockCluster.peakMeasuredValue = 1500.0f;
mockCluster.averageMeasuredValue = 800.0f;
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new CarbonDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("carbondioxideconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(1000.0f, Units.PARTS_PER_MILLION)));
verify(mockHandler, times(1)).updateState(eq(1), eq("carbondioxideconcentrationmeasurement-levelvalue"),
eq(new DecimalType(2)));
verify(mockHandler, times(1)).updateState(eq(1), eq("carbondioxideconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(1500.0f, Units.PARTS_PER_MILLION)));
verify(mockHandler, times(1)).updateState(eq(1),
eq("carbondioxideconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(800.0f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitStateWithNullValue() {
mockCluster.measuredValue = null;
@@ -93,4 +194,32 @@ class CarbonDioxideConcentrationMeasurementConverterTest extends BaseMatterConve
verify(mockHandler, times(1)).updateState(eq(1), eq("carbondioxideconcentrationmeasurement-measuredvalue"),
eq(UnDefType.NULL));
}
@Test
void testMeasuredValueWithMicrogramUnit() {
mockCluster.measurementUnit = MeasurementUnitEnum.UGM3;
converter = new CarbonDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = CarbonDioxideConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE;
message.value = 50.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("carbondioxideconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(50.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testMeasuredValueWithUnsupportedUnit() {
mockCluster.measurementUnit = MeasurementUnitEnum.PPB; // Not supported by openHAB Units
converter = new CarbonDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = CarbonDioxideConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE;
message.value = 500.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("carbondioxideconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(500.0f, Units.ONE))); // Falls back to dimensionless
}
}
@@ -13,6 +13,7 @@
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -25,8 +26,12 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.CarbonMonoxideConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.CarbonMonoxideConcentrationMeasurementCluster.FeatureMap;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.CarbonMonoxideConcentrationMeasurementCluster.LevelValueEnum;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.CarbonMonoxideConcentrationMeasurementCluster.MeasurementUnitEnum;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.client.dto.ws.Path;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
@@ -53,6 +58,8 @@ class CarbonMonoxideConcentrationMeasurementConverterTest extends BaseMatterConv
void setUp() {
super.setUp();
mockCluster.measuredValue = 0.0f;
mockCluster.measurementUnit = MeasurementUnitEnum.PPM;
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, false);
converter = new CarbonMonoxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
}
@@ -67,6 +74,36 @@ class CarbonMonoxideConcentrationMeasurementConverterTest extends BaseMatterConv
assertEquals("Number:Dimensionless", channel.getAcceptedItemType());
}
@Test
void testCreateChannelsWithAllFeatures() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new CarbonMonoxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(4, channels.size());
Channel measuredValueChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#carbonmonoxideconcentrationmeasurement-measuredvalue"))
.findFirst().orElse(null);
assertNotNull(measuredValueChannel);
Channel levelChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#carbonmonoxideconcentrationmeasurement-levelvalue"))
.findFirst().orElse(null);
assertNotNull(levelChannel);
Channel peakChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#carbonmonoxideconcentrationmeasurement-peakmeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(peakChannel);
Channel averageChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#carbonmonoxideconcentrationmeasurement-averagemeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(averageChannel);
}
@Test
void testOnEventWithMeasuredValue() {
AttributeChangedMessage message = new AttributeChangedMessage();
@@ -78,6 +115,49 @@ class CarbonMonoxideConcentrationMeasurementConverterTest extends BaseMatterConv
eq(new QuantityType<>(50.0f, Units.PARTS_PER_MILLION)));
}
@Test
void testOnEventWithLevelValue() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, false, false);
converter = new CarbonMonoxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = CarbonMonoxideConcentrationMeasurementCluster.ATTRIBUTE_LEVEL_VALUE;
message.value = 3;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("carbonmonoxideconcentrationmeasurement-levelvalue"),
eq(new DecimalType(3)));
}
@Test
void testOnEventWithPeakMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, true, false);
converter = new CarbonMonoxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = CarbonMonoxideConcentrationMeasurementCluster.ATTRIBUTE_PEAK_MEASURED_VALUE;
message.value = 100.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("carbonmonoxideconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(100.0f, Units.PARTS_PER_MILLION)));
}
@Test
void testOnEventWithAverageMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, true);
converter = new CarbonMonoxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = CarbonMonoxideConcentrationMeasurementCluster.ATTRIBUTE_AVERAGE_MEASURED_VALUE;
message.value = 30.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1),
eq("carbonmonoxideconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(30.0f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitState() {
mockCluster.measuredValue = 10.0f;
@@ -86,6 +166,27 @@ class CarbonMonoxideConcentrationMeasurementConverterTest extends BaseMatterConv
eq(new QuantityType<>(10.0f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitStateWithAllAttributes() {
mockCluster.measuredValue = 10.0f;
mockCluster.levelValue = LevelValueEnum.CRITICAL;
mockCluster.peakMeasuredValue = 150.0f;
mockCluster.averageMeasuredValue = 25.0f;
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new CarbonMonoxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("carbonmonoxideconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(10.0f, Units.PARTS_PER_MILLION)));
verify(mockHandler, times(1)).updateState(eq(1), eq("carbonmonoxideconcentrationmeasurement-levelvalue"),
eq(new DecimalType(4)));
verify(mockHandler, times(1)).updateState(eq(1), eq("carbonmonoxideconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(150.0f, Units.PARTS_PER_MILLION)));
verify(mockHandler, times(1)).updateState(eq(1),
eq("carbonmonoxideconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(25.0f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitStateWithNullValue() {
mockCluster.measuredValue = null;
@@ -93,4 +194,18 @@ class CarbonMonoxideConcentrationMeasurementConverterTest extends BaseMatterConv
verify(mockHandler, times(1)).updateState(eq(1), eq("carbonmonoxideconcentrationmeasurement-measuredvalue"),
eq(UnDefType.NULL));
}
@Test
void testMeasuredValueWithMicrogramUnit() {
mockCluster.measurementUnit = MeasurementUnitEnum.UGM3;
converter = new CarbonMonoxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = CarbonMonoxideConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE;
message.value = 75.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("carbonmonoxideconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(75.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
}
@@ -0,0 +1,197 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.FormaldehydeConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.FormaldehydeConcentrationMeasurementCluster.FeatureMap;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.FormaldehydeConcentrationMeasurementCluster.LevelValueEnum;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.FormaldehydeConcentrationMeasurementCluster.MeasurementUnitEnum;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.client.dto.ws.Path;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.UnDefType;
/**
* Test class for {@link FormaldehydeConcentrationMeasurementConverter}
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
class FormaldehydeConcentrationMeasurementConverterTest extends BaseMatterConverterTest {
@Mock
@NonNullByDefault({})
private FormaldehydeConcentrationMeasurementCluster mockCluster;
@NonNullByDefault({})
private FormaldehydeConcentrationMeasurementConverter converter;
@Override
@BeforeEach
void setUp() {
super.setUp();
mockCluster.measuredValue = 0.03125f;
mockCluster.measurementUnit = MeasurementUnitEnum.PPM;
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, false);
converter = new FormaldehydeConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
}
@Test
void testCreateChannels() {
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(1, channels.size());
Channel channel = channels.keySet().iterator().next();
assertEquals("matter:node:test:12345:1#formaldehydeconcentrationmeasurement-measuredvalue",
channel.getUID().toString());
assertEquals("Number:Dimensionless", channel.getAcceptedItemType());
}
@Test
void testCreateChannelsWithAllFeatures() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new FormaldehydeConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(4, channels.size());
Channel measuredValueChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#formaldehydeconcentrationmeasurement-measuredvalue"))
.findFirst().orElse(null);
assertNotNull(measuredValueChannel);
Channel levelChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#formaldehydeconcentrationmeasurement-levelvalue")).findFirst()
.orElse(null);
assertNotNull(levelChannel);
Channel peakChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#formaldehydeconcentrationmeasurement-peakmeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(peakChannel);
Channel averageChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#formaldehydeconcentrationmeasurement-averagemeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(averageChannel);
}
@Test
void testOnEventWithMeasuredValue() {
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = FormaldehydeConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE;
message.value = 0.0625f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("formaldehydeconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(0.0625f, Units.PARTS_PER_MILLION)));
}
@Test
void testOnEventWithLevelValue() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, false, false);
converter = new FormaldehydeConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = FormaldehydeConcentrationMeasurementCluster.ATTRIBUTE_LEVEL_VALUE;
message.value = 2;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("formaldehydeconcentrationmeasurement-levelvalue"),
eq(new DecimalType(2)));
}
@Test
void testOnEventWithPeakMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, true, false);
converter = new FormaldehydeConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = FormaldehydeConcentrationMeasurementCluster.ATTRIBUTE_PEAK_MEASURED_VALUE;
message.value = 0.0625f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("formaldehydeconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(0.0625f, Units.PARTS_PER_MILLION)));
}
@Test
void testOnEventWithAverageMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, true);
converter = new FormaldehydeConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = FormaldehydeConcentrationMeasurementCluster.ATTRIBUTE_AVERAGE_MEASURED_VALUE;
message.value = 0.03125f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1),
eq("formaldehydeconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(0.03125f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitState() {
mockCluster.measuredValue = 0.03125f;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("formaldehydeconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(0.03125f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitStateWithAllAttributes() {
mockCluster.measuredValue = 0.03125f;
mockCluster.levelValue = LevelValueEnum.LOW;
mockCluster.peakMeasuredValue = 0.125f;
mockCluster.averageMeasuredValue = 0.03125f;
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new FormaldehydeConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("formaldehydeconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(0.03125f, Units.PARTS_PER_MILLION)));
verify(mockHandler, times(1)).updateState(eq(1), eq("formaldehydeconcentrationmeasurement-levelvalue"),
eq(new DecimalType(1)));
verify(mockHandler, times(1)).updateState(eq(1), eq("formaldehydeconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(0.125f, Units.PARTS_PER_MILLION)));
verify(mockHandler, times(1)).updateState(eq(1),
eq("formaldehydeconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(0.03125f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitStateWithNullValue() {
mockCluster.measuredValue = null;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("formaldehydeconcentrationmeasurement-measuredvalue"),
eq(UnDefType.NULL));
}
}
@@ -0,0 +1,199 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.NitrogenDioxideConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.NitrogenDioxideConcentrationMeasurementCluster.FeatureMap;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.NitrogenDioxideConcentrationMeasurementCluster.LevelValueEnum;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.NitrogenDioxideConcentrationMeasurementCluster.MeasurementUnitEnum;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.client.dto.ws.Path;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.UnDefType;
/**
* Test class for {@link NitrogenDioxideConcentrationMeasurementConverter}
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
class NitrogenDioxideConcentrationMeasurementConverterTest extends BaseMatterConverterTest {
@Mock
@NonNullByDefault({})
private NitrogenDioxideConcentrationMeasurementCluster mockCluster;
@NonNullByDefault({})
private NitrogenDioxideConcentrationMeasurementConverter converter;
@Override
@BeforeEach
void setUp() {
super.setUp();
mockCluster.measuredValue = 0.03125f;
mockCluster.measurementUnit = MeasurementUnitEnum.PPM;
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, false);
converter = new NitrogenDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
}
@Test
void testCreateChannels() {
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(1, channels.size());
Channel channel = channels.keySet().iterator().next();
assertEquals("matter:node:test:12345:1#nitrogendioxideconcentrationmeasurement-measuredvalue",
channel.getUID().toString());
assertEquals("Number:Dimensionless", channel.getAcceptedItemType());
}
@Test
void testCreateChannelsWithAllFeatures() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new NitrogenDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(4, channels.size());
Channel measuredValueChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#nitrogendioxideconcentrationmeasurement-measuredvalue"))
.findFirst().orElse(null);
assertNotNull(measuredValueChannel);
Channel levelChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#nitrogendioxideconcentrationmeasurement-levelvalue"))
.findFirst().orElse(null);
assertNotNull(levelChannel);
Channel peakChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#nitrogendioxideconcentrationmeasurement-peakmeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(peakChannel);
Channel averageChannel = channels.keySet().stream().filter(
c -> c.getUID().getId().equals("1#nitrogendioxideconcentrationmeasurement-averagemeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(averageChannel);
}
@Test
void testOnEventWithMeasuredValue() {
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = NitrogenDioxideConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE;
message.value = 0.125f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("nitrogendioxideconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(0.125f, Units.PARTS_PER_MILLION)));
}
@Test
void testOnEventWithLevelValue() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, false, false);
converter = new NitrogenDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = NitrogenDioxideConcentrationMeasurementCluster.ATTRIBUTE_LEVEL_VALUE;
message.value = 1;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("nitrogendioxideconcentrationmeasurement-levelvalue"),
eq(new DecimalType(1)));
}
@Test
void testOnEventWithPeakMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, true, false);
converter = new NitrogenDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = NitrogenDioxideConcentrationMeasurementCluster.ATTRIBUTE_PEAK_MEASURED_VALUE;
message.value = 0.125f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1),
eq("nitrogendioxideconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(0.125f, Units.PARTS_PER_MILLION)));
}
@Test
void testOnEventWithAverageMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, true);
converter = new NitrogenDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = NitrogenDioxideConcentrationMeasurementCluster.ATTRIBUTE_AVERAGE_MEASURED_VALUE;
message.value = 0.0625f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1),
eq("nitrogendioxideconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(0.0625f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitState() {
mockCluster.measuredValue = 0.03125f;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("nitrogendioxideconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(0.03125f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitStateWithAllAttributes() {
mockCluster.measuredValue = 0.03125f;
mockCluster.levelValue = LevelValueEnum.MEDIUM;
mockCluster.peakMeasuredValue = 0.125f;
mockCluster.averageMeasuredValue = 0.03125f;
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new NitrogenDioxideConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("nitrogendioxideconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(0.03125f, Units.PARTS_PER_MILLION)));
verify(mockHandler, times(1)).updateState(eq(1), eq("nitrogendioxideconcentrationmeasurement-levelvalue"),
eq(new DecimalType(2)));
verify(mockHandler, times(1)).updateState(eq(1),
eq("nitrogendioxideconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(0.125f, Units.PARTS_PER_MILLION)));
verify(mockHandler, times(1)).updateState(eq(1),
eq("nitrogendioxideconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(0.03125f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitStateWithNullValue() {
mockCluster.measuredValue = null;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("nitrogendioxideconcentrationmeasurement-measuredvalue"),
eq(UnDefType.NULL));
}
}
@@ -0,0 +1,195 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.OzoneConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.OzoneConcentrationMeasurementCluster.FeatureMap;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.OzoneConcentrationMeasurementCluster.LevelValueEnum;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.OzoneConcentrationMeasurementCluster.MeasurementUnitEnum;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.client.dto.ws.Path;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.UnDefType;
/**
* Test class for {@link OzoneConcentrationMeasurementConverter}
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
class OzoneConcentrationMeasurementConverterTest extends BaseMatterConverterTest {
@Mock
@NonNullByDefault({})
private OzoneConcentrationMeasurementCluster mockCluster;
@NonNullByDefault({})
private OzoneConcentrationMeasurementConverter converter;
@Override
@BeforeEach
void setUp() {
super.setUp();
mockCluster.measuredValue = 0.125f;
mockCluster.measurementUnit = MeasurementUnitEnum.PPM;
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, false);
converter = new OzoneConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
}
@Test
void testCreateChannels() {
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(1, channels.size());
Channel channel = channels.keySet().iterator().next();
assertEquals("matter:node:test:12345:1#ozoneconcentrationmeasurement-measuredvalue",
channel.getUID().toString());
assertEquals("Number:Dimensionless", channel.getAcceptedItemType());
}
@Test
void testCreateChannelsWithAllFeatures() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new OzoneConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(4, channels.size());
Channel measuredValueChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#ozoneconcentrationmeasurement-measuredvalue")).findFirst()
.orElse(null);
assertNotNull(measuredValueChannel);
Channel levelChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#ozoneconcentrationmeasurement-levelvalue")).findFirst()
.orElse(null);
assertNotNull(levelChannel);
Channel peakChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#ozoneconcentrationmeasurement-peakmeasuredvalue")).findFirst()
.orElse(null);
assertNotNull(peakChannel);
Channel averageChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#ozoneconcentrationmeasurement-averagemeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(averageChannel);
}
@Test
void testOnEventWithMeasuredValue() {
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = OzoneConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE;
message.value = 0.125f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("ozoneconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(0.125f, Units.PARTS_PER_MILLION)));
}
@Test
void testOnEventWithLevelValue() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, false, false);
converter = new OzoneConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = OzoneConcentrationMeasurementCluster.ATTRIBUTE_LEVEL_VALUE;
message.value = 2;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("ozoneconcentrationmeasurement-levelvalue"),
eq(new DecimalType(2)));
}
@Test
void testOnEventWithPeakMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, true, false);
converter = new OzoneConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = OzoneConcentrationMeasurementCluster.ATTRIBUTE_PEAK_MEASURED_VALUE;
message.value = 0.25f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("ozoneconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(0.25f, Units.PARTS_PER_MILLION)));
}
@Test
void testOnEventWithAverageMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, true);
converter = new OzoneConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = OzoneConcentrationMeasurementCluster.ATTRIBUTE_AVERAGE_MEASURED_VALUE;
message.value = 0.0625f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("ozoneconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(0.0625f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitState() {
mockCluster.measuredValue = 0.125f;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("ozoneconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(0.125f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitStateWithAllAttributes() {
mockCluster.measuredValue = 0.125f;
mockCluster.levelValue = LevelValueEnum.LOW;
mockCluster.peakMeasuredValue = 0.25f;
mockCluster.averageMeasuredValue = 0.0625f;
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new OzoneConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("ozoneconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(0.125f, Units.PARTS_PER_MILLION)));
verify(mockHandler, times(1)).updateState(eq(1), eq("ozoneconcentrationmeasurement-levelvalue"),
eq(new DecimalType(1)));
verify(mockHandler, times(1)).updateState(eq(1), eq("ozoneconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(0.25f, Units.PARTS_PER_MILLION)));
verify(mockHandler, times(1)).updateState(eq(1), eq("ozoneconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(0.0625f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitStateWithNullValue() {
mockCluster.measuredValue = null;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("ozoneconcentrationmeasurement-measuredvalue"),
eq(UnDefType.NULL));
}
}
@@ -0,0 +1,195 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm10ConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm10ConcentrationMeasurementCluster.FeatureMap;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm10ConcentrationMeasurementCluster.LevelValueEnum;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm10ConcentrationMeasurementCluster.MeasurementUnitEnum;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.client.dto.ws.Path;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.UnDefType;
/**
* Test class for {@link Pm10ConcentrationMeasurementConverter}
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
class Pm10ConcentrationMeasurementConverterTest extends BaseMatterConverterTest {
@Mock
@NonNullByDefault({})
private Pm10ConcentrationMeasurementCluster mockCluster;
@NonNullByDefault({})
private Pm10ConcentrationMeasurementConverter converter;
@Override
@BeforeEach
void setUp() {
super.setUp();
mockCluster.measuredValue = 50.0f;
mockCluster.measurementUnit = MeasurementUnitEnum.UGM3;
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, false);
converter = new Pm10ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
}
@Test
void testCreateChannels() {
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(1, channels.size());
Channel channel = channels.keySet().iterator().next();
assertEquals("matter:node:test:12345:1#pm10concentrationmeasurement-measuredvalue",
channel.getUID().toString());
assertEquals("Number:Dimensionless", channel.getAcceptedItemType());
}
@Test
void testCreateChannelsWithAllFeatures() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new Pm10ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(4, channels.size());
Channel measuredValueChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#pm10concentrationmeasurement-measuredvalue")).findFirst()
.orElse(null);
assertNotNull(measuredValueChannel);
Channel levelChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#pm10concentrationmeasurement-levelvalue")).findFirst()
.orElse(null);
assertNotNull(levelChannel);
Channel peakChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#pm10concentrationmeasurement-peakmeasuredvalue")).findFirst()
.orElse(null);
assertNotNull(peakChannel);
Channel averageChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#pm10concentrationmeasurement-averagemeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(averageChannel);
}
@Test
void testOnEventWithMeasuredValue() {
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = Pm10ConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE;
message.value = 75.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("pm10concentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(75.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testOnEventWithLevelValue() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, false, false);
converter = new Pm10ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = Pm10ConcentrationMeasurementCluster.ATTRIBUTE_LEVEL_VALUE;
message.value = 2;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("pm10concentrationmeasurement-levelvalue"),
eq(new DecimalType(2)));
}
@Test
void testOnEventWithPeakMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, true, false);
converter = new Pm10ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = Pm10ConcentrationMeasurementCluster.ATTRIBUTE_PEAK_MEASURED_VALUE;
message.value = 100.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("pm10concentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(100.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testOnEventWithAverageMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, true);
converter = new Pm10ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = Pm10ConcentrationMeasurementCluster.ATTRIBUTE_AVERAGE_MEASURED_VALUE;
message.value = 45.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("pm10concentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(45.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testInitState() {
mockCluster.measuredValue = 60.0f;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("pm10concentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(60.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testInitStateWithAllAttributes() {
mockCluster.measuredValue = 60.0f;
mockCluster.levelValue = LevelValueEnum.MEDIUM;
mockCluster.peakMeasuredValue = 90.0f;
mockCluster.averageMeasuredValue = 55.0f;
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new Pm10ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("pm10concentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(60.0f, Units.MICROGRAM_PER_CUBICMETRE)));
verify(mockHandler, times(1)).updateState(eq(1), eq("pm10concentrationmeasurement-levelvalue"),
eq(new DecimalType(2)));
verify(mockHandler, times(1)).updateState(eq(1), eq("pm10concentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(90.0f, Units.MICROGRAM_PER_CUBICMETRE)));
verify(mockHandler, times(1)).updateState(eq(1), eq("pm10concentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(55.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testInitStateWithNullValue() {
mockCluster.measuredValue = null;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("pm10concentrationmeasurement-measuredvalue"),
eq(UnDefType.NULL));
}
}
@@ -0,0 +1,194 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm1ConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm1ConcentrationMeasurementCluster.FeatureMap;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm1ConcentrationMeasurementCluster.LevelValueEnum;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm1ConcentrationMeasurementCluster.MeasurementUnitEnum;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.client.dto.ws.Path;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.UnDefType;
/**
* Test class for {@link Pm1ConcentrationMeasurementConverter}
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
class Pm1ConcentrationMeasurementConverterTest extends BaseMatterConverterTest {
@Mock
@NonNullByDefault({})
private Pm1ConcentrationMeasurementCluster mockCluster;
@NonNullByDefault({})
private Pm1ConcentrationMeasurementConverter converter;
@Override
@BeforeEach
void setUp() {
super.setUp();
mockCluster.measuredValue = 25.0f;
mockCluster.measurementUnit = MeasurementUnitEnum.UGM3;
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, false);
converter = new Pm1ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
}
@Test
void testCreateChannels() {
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(1, channels.size());
Channel channel = channels.keySet().iterator().next();
assertEquals("matter:node:test:12345:1#pm1concentrationmeasurement-measuredvalue", channel.getUID().toString());
assertEquals("Number:Dimensionless", channel.getAcceptedItemType());
}
@Test
void testCreateChannelsWithAllFeatures() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new Pm1ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(4, channels.size());
Channel measuredValueChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#pm1concentrationmeasurement-measuredvalue")).findFirst()
.orElse(null);
assertNotNull(measuredValueChannel);
Channel levelChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#pm1concentrationmeasurement-levelvalue")).findFirst()
.orElse(null);
assertNotNull(levelChannel);
Channel peakChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#pm1concentrationmeasurement-peakmeasuredvalue")).findFirst()
.orElse(null);
assertNotNull(peakChannel);
Channel averageChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#pm1concentrationmeasurement-averagemeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(averageChannel);
}
@Test
void testOnEventWithMeasuredValue() {
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = Pm1ConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE;
message.value = 35.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("pm1concentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(35.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testOnEventWithLevelValue() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, false, false);
converter = new Pm1ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = Pm1ConcentrationMeasurementCluster.ATTRIBUTE_LEVEL_VALUE;
message.value = 1;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("pm1concentrationmeasurement-levelvalue"),
eq(new DecimalType(1)));
}
@Test
void testOnEventWithPeakMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, true, false);
converter = new Pm1ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = Pm1ConcentrationMeasurementCluster.ATTRIBUTE_PEAK_MEASURED_VALUE;
message.value = 50.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("pm1concentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(50.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testOnEventWithAverageMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, true);
converter = new Pm1ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = Pm1ConcentrationMeasurementCluster.ATTRIBUTE_AVERAGE_MEASURED_VALUE;
message.value = 28.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("pm1concentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(28.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testInitState() {
mockCluster.measuredValue = 30.0f;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("pm1concentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(30.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testInitStateWithAllAttributes() {
mockCluster.measuredValue = 30.0f;
mockCluster.levelValue = LevelValueEnum.LOW;
mockCluster.peakMeasuredValue = 45.0f;
mockCluster.averageMeasuredValue = 27.0f;
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new Pm1ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("pm1concentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(30.0f, Units.MICROGRAM_PER_CUBICMETRE)));
verify(mockHandler, times(1)).updateState(eq(1), eq("pm1concentrationmeasurement-levelvalue"),
eq(new DecimalType(1)));
verify(mockHandler, times(1)).updateState(eq(1), eq("pm1concentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(45.0f, Units.MICROGRAM_PER_CUBICMETRE)));
verify(mockHandler, times(1)).updateState(eq(1), eq("pm1concentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(27.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testInitStateWithNullValue() {
mockCluster.measuredValue = null;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("pm1concentrationmeasurement-measuredvalue"),
eq(UnDefType.NULL));
}
}
@@ -0,0 +1,195 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm25ConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm25ConcentrationMeasurementCluster.FeatureMap;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm25ConcentrationMeasurementCluster.LevelValueEnum;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.Pm25ConcentrationMeasurementCluster.MeasurementUnitEnum;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.client.dto.ws.Path;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.UnDefType;
/**
* Test class for {@link Pm25ConcentrationMeasurementConverter}
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
class Pm25ConcentrationMeasurementConverterTest extends BaseMatterConverterTest {
@Mock
@NonNullByDefault({})
private Pm25ConcentrationMeasurementCluster mockCluster;
@NonNullByDefault({})
private Pm25ConcentrationMeasurementConverter converter;
@Override
@BeforeEach
void setUp() {
super.setUp();
mockCluster.measuredValue = 35.0f;
mockCluster.measurementUnit = MeasurementUnitEnum.UGM3;
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, false);
converter = new Pm25ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
}
@Test
void testCreateChannels() {
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(1, channels.size());
Channel channel = channels.keySet().iterator().next();
assertEquals("matter:node:test:12345:1#pm25concentrationmeasurement-measuredvalue",
channel.getUID().toString());
assertEquals("Number:Dimensionless", channel.getAcceptedItemType());
}
@Test
void testCreateChannelsWithAllFeatures() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new Pm25ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(4, channels.size());
Channel measuredValueChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#pm25concentrationmeasurement-measuredvalue")).findFirst()
.orElse(null);
assertNotNull(measuredValueChannel);
Channel levelChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#pm25concentrationmeasurement-levelvalue")).findFirst()
.orElse(null);
assertNotNull(levelChannel);
Channel peakChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#pm25concentrationmeasurement-peakmeasuredvalue")).findFirst()
.orElse(null);
assertNotNull(peakChannel);
Channel averageChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#pm25concentrationmeasurement-averagemeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(averageChannel);
}
@Test
void testOnEventWithMeasuredValue() {
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = Pm25ConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE;
message.value = 45.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("pm25concentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(45.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testOnEventWithLevelValue() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, false, false);
converter = new Pm25ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = Pm25ConcentrationMeasurementCluster.ATTRIBUTE_LEVEL_VALUE;
message.value = 2;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("pm25concentrationmeasurement-levelvalue"),
eq(new DecimalType(2)));
}
@Test
void testOnEventWithPeakMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, true, false);
converter = new Pm25ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = Pm25ConcentrationMeasurementCluster.ATTRIBUTE_PEAK_MEASURED_VALUE;
message.value = 65.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("pm25concentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(65.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testOnEventWithAverageMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, true);
converter = new Pm25ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = Pm25ConcentrationMeasurementCluster.ATTRIBUTE_AVERAGE_MEASURED_VALUE;
message.value = 38.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("pm25concentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(38.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testInitState() {
mockCluster.measuredValue = 40.0f;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("pm25concentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(40.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testInitStateWithAllAttributes() {
mockCluster.measuredValue = 40.0f;
mockCluster.levelValue = LevelValueEnum.HIGH;
mockCluster.peakMeasuredValue = 70.0f;
mockCluster.averageMeasuredValue = 35.0f;
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new Pm25ConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("pm25concentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(40.0f, Units.MICROGRAM_PER_CUBICMETRE)));
verify(mockHandler, times(1)).updateState(eq(1), eq("pm25concentrationmeasurement-levelvalue"),
eq(new DecimalType(3)));
verify(mockHandler, times(1)).updateState(eq(1), eq("pm25concentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(70.0f, Units.MICROGRAM_PER_CUBICMETRE)));
verify(mockHandler, times(1)).updateState(eq(1), eq("pm25concentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(35.0f, Units.MICROGRAM_PER_CUBICMETRE)));
}
@Test
void testInitStateWithNullValue() {
mockCluster.measuredValue = null;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("pm25concentrationmeasurement-measuredvalue"),
eq(UnDefType.NULL));
}
}
@@ -0,0 +1,196 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.RadonConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.RadonConcentrationMeasurementCluster.FeatureMap;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.RadonConcentrationMeasurementCluster.LevelValueEnum;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.RadonConcentrationMeasurementCluster.MeasurementUnitEnum;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.client.dto.ws.Path;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.UnDefType;
/**
* Test class for {@link RadonConcentrationMeasurementConverter}
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
class RadonConcentrationMeasurementConverterTest extends BaseMatterConverterTest {
@Mock
@NonNullByDefault({})
private RadonConcentrationMeasurementCluster mockCluster;
@NonNullByDefault({})
private RadonConcentrationMeasurementConverter converter;
@Override
@BeforeEach
void setUp() {
super.setUp();
mockCluster.measuredValue = 100.0f;
mockCluster.measurementUnit = MeasurementUnitEnum.BQM3;
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, false);
converter = new RadonConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
}
@Test
void testCreateChannels() {
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(1, channels.size());
Channel channel = channels.keySet().iterator().next();
assertEquals("matter:node:test:12345:1#radonconcentrationmeasurement-measuredvalue",
channel.getUID().toString());
assertEquals("Number:Dimensionless", channel.getAcceptedItemType());
}
@Test
void testCreateChannelsWithAllFeatures() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new RadonConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(4, channels.size());
Channel measuredValueChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#radonconcentrationmeasurement-measuredvalue")).findFirst()
.orElse(null);
assertNotNull(measuredValueChannel);
Channel levelChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#radonconcentrationmeasurement-levelvalue")).findFirst()
.orElse(null);
assertNotNull(levelChannel);
Channel peakChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#radonconcentrationmeasurement-peakmeasuredvalue")).findFirst()
.orElse(null);
assertNotNull(peakChannel);
Channel averageChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId().equals("1#radonconcentrationmeasurement-averagemeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(averageChannel);
}
@Test
void testOnEventWithMeasuredValue() {
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = RadonConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE;
message.value = 150.0f;
converter.onEvent(message);
// BQM3 is not supported by openHAB Units, so it falls back to dimensionless
verify(mockHandler, times(1)).updateState(eq(1), eq("radonconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(150.0f, Units.ONE)));
}
@Test
void testOnEventWithLevelValue() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, false, false);
converter = new RadonConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = RadonConcentrationMeasurementCluster.ATTRIBUTE_LEVEL_VALUE;
message.value = 3;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("radonconcentrationmeasurement-levelvalue"),
eq(new DecimalType(3)));
}
@Test
void testOnEventWithPeakMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, true, false);
converter = new RadonConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = RadonConcentrationMeasurementCluster.ATTRIBUTE_PEAK_MEASURED_VALUE;
message.value = 200.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("radonconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(200.0f, Units.ONE)));
}
@Test
void testOnEventWithAverageMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, true);
converter = new RadonConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = RadonConcentrationMeasurementCluster.ATTRIBUTE_AVERAGE_MEASURED_VALUE;
message.value = 120.0f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1), eq("radonconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(120.0f, Units.ONE)));
}
@Test
void testInitState() {
mockCluster.measuredValue = 110.0f;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("radonconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(110.0f, Units.ONE)));
}
@Test
void testInitStateWithAllAttributes() {
mockCluster.measuredValue = 110.0f;
mockCluster.levelValue = LevelValueEnum.HIGH;
mockCluster.peakMeasuredValue = 180.0f;
mockCluster.averageMeasuredValue = 95.0f;
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new RadonConcentrationMeasurementConverter(mockCluster, mockHandler, 1, "TestLabel");
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("radonconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(110.0f, Units.ONE)));
verify(mockHandler, times(1)).updateState(eq(1), eq("radonconcentrationmeasurement-levelvalue"),
eq(new DecimalType(3)));
verify(mockHandler, times(1)).updateState(eq(1), eq("radonconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(180.0f, Units.ONE)));
verify(mockHandler, times(1)).updateState(eq(1), eq("radonconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(95.0f, Units.ONE)));
}
@Test
void testInitStateWithNullValue() {
mockCluster.measuredValue = null;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1), eq("radonconcentrationmeasurement-measuredvalue"),
eq(UnDefType.NULL));
}
}
@@ -0,0 +1,210 @@
/*
* Copyright (c) 2010-2026 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.matter.internal.controller.devices.converter;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.TotalVolatileOrganicCompoundsConcentrationMeasurementCluster;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.FeatureMap;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.LevelValueEnum;
import org.openhab.binding.matter.internal.client.dto.cluster.gen.TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.MeasurementUnitEnum;
import org.openhab.binding.matter.internal.client.dto.ws.AttributeChangedMessage;
import org.openhab.binding.matter.internal.client.dto.ws.Path;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelGroupUID;
import org.openhab.core.types.StateDescription;
import org.openhab.core.types.UnDefType;
/**
* Test class for {@link TotalVolatileOrganicCompoundsConcentrationMeasurementConverter}
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
class TotalVolatileOrganicCompoundsConcentrationMeasurementConverterTest extends BaseMatterConverterTest {
@Mock
@NonNullByDefault({})
private TotalVolatileOrganicCompoundsConcentrationMeasurementCluster mockCluster;
@NonNullByDefault({})
private TotalVolatileOrganicCompoundsConcentrationMeasurementConverter converter;
@Override
@BeforeEach
void setUp() {
super.setUp();
mockCluster.measuredValue = 0.5f;
mockCluster.measurementUnit = MeasurementUnitEnum.PPM;
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, false);
converter = new TotalVolatileOrganicCompoundsConcentrationMeasurementConverter(mockCluster, mockHandler, 1,
"TestLabel");
}
@Test
void testCreateChannels() {
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(1, channels.size());
Channel channel = channels.keySet().iterator().next();
assertEquals("matter:node:test:12345:1#totalvolatileorganiccompoundsconcentrationmeasurement-measuredvalue",
channel.getUID().toString());
assertEquals("Number:Dimensionless", channel.getAcceptedItemType());
}
@Test
void testCreateChannelsWithAllFeatures() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new TotalVolatileOrganicCompoundsConcentrationMeasurementConverter(mockCluster, mockHandler, 1,
"TestLabel");
ChannelGroupUID channelGroupUID = new ChannelGroupUID("matter:node:test:12345:1");
Map<Channel, @Nullable StateDescription> channels = converter.createChannels(channelGroupUID);
assertEquals(4, channels.size());
Channel measuredValueChannel = channels.keySet().stream().filter(
c -> c.getUID().getId().equals("1#totalvolatileorganiccompoundsconcentrationmeasurement-measuredvalue"))
.findFirst().orElse(null);
assertNotNull(measuredValueChannel);
Channel levelChannel = channels.keySet().stream().filter(
c -> c.getUID().getId().equals("1#totalvolatileorganiccompoundsconcentrationmeasurement-levelvalue"))
.findFirst().orElse(null);
assertNotNull(levelChannel);
Channel peakChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId()
.equals("1#totalvolatileorganiccompoundsconcentrationmeasurement-peakmeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(peakChannel);
Channel averageChannel = channels.keySet().stream()
.filter(c -> c.getUID().getId()
.equals("1#totalvolatileorganiccompoundsconcentrationmeasurement-averagemeasuredvalue"))
.findFirst().orElse(null);
assertNotNull(averageChannel);
}
@Test
void testOnEventWithMeasuredValue() {
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.ATTRIBUTE_MEASURED_VALUE;
message.value = 1.25f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1),
eq("totalvolatileorganiccompoundsconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(1.25f, Units.PARTS_PER_MILLION)));
}
@Test
void testOnEventWithLevelValue() {
mockCluster.featureMap = new FeatureMap(true, true, false, false, false, false);
converter = new TotalVolatileOrganicCompoundsConcentrationMeasurementConverter(mockCluster, mockHandler, 1,
"TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.ATTRIBUTE_LEVEL_VALUE;
message.value = 2;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1),
eq("totalvolatileorganiccompoundsconcentrationmeasurement-levelvalue"), eq(new DecimalType(2)));
}
@Test
void testOnEventWithPeakMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, true, false);
converter = new TotalVolatileOrganicCompoundsConcentrationMeasurementConverter(mockCluster, mockHandler, 1,
"TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.ATTRIBUTE_PEAK_MEASURED_VALUE;
message.value = 2.5f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1),
eq("totalvolatileorganiccompoundsconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(2.5f, Units.PARTS_PER_MILLION)));
}
@Test
void testOnEventWithAverageMeasuredValue() {
mockCluster.featureMap = new FeatureMap(true, false, false, false, false, true);
converter = new TotalVolatileOrganicCompoundsConcentrationMeasurementConverter(mockCluster, mockHandler, 1,
"TestLabel");
AttributeChangedMessage message = new AttributeChangedMessage();
message.path = new Path();
message.path.attributeName = TotalVolatileOrganicCompoundsConcentrationMeasurementCluster.ATTRIBUTE_AVERAGE_MEASURED_VALUE;
message.value = 0.75f;
converter.onEvent(message);
verify(mockHandler, times(1)).updateState(eq(1),
eq("totalvolatileorganiccompoundsconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(0.75f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitState() {
mockCluster.measuredValue = 0.75f;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1),
eq("totalvolatileorganiccompoundsconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(0.75f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitStateWithAllAttributes() {
mockCluster.measuredValue = 0.75f;
mockCluster.levelValue = LevelValueEnum.MEDIUM;
mockCluster.peakMeasuredValue = 1.5f;
mockCluster.averageMeasuredValue = 0.625f;
mockCluster.featureMap = new FeatureMap(true, true, false, false, true, true);
converter = new TotalVolatileOrganicCompoundsConcentrationMeasurementConverter(mockCluster, mockHandler, 1,
"TestLabel");
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1),
eq("totalvolatileorganiccompoundsconcentrationmeasurement-measuredvalue"),
eq(new QuantityType<>(0.75f, Units.PARTS_PER_MILLION)));
verify(mockHandler, times(1)).updateState(eq(1),
eq("totalvolatileorganiccompoundsconcentrationmeasurement-levelvalue"), eq(new DecimalType(2)));
verify(mockHandler, times(1)).updateState(eq(1),
eq("totalvolatileorganiccompoundsconcentrationmeasurement-peakmeasuredvalue"),
eq(new QuantityType<>(1.5f, Units.PARTS_PER_MILLION)));
verify(mockHandler, times(1)).updateState(eq(1),
eq("totalvolatileorganiccompoundsconcentrationmeasurement-averagemeasuredvalue"),
eq(new QuantityType<>(0.625f, Units.PARTS_PER_MILLION)));
}
@Test
void testInitStateWithNullValue() {
mockCluster.measuredValue = null;
converter.initState();
verify(mockHandler, times(1)).updateState(eq(1),
eq("totalvolatileorganiccompoundsconcentrationmeasurement-measuredvalue"), eq(UnDefType.NULL));
}
}