This repository has been archived by the owner on Nov 7, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(sensor): add humidity & temperature sensor
- Loading branch information
1 parent
e93fc81
commit f730905
Showing
7 changed files
with
171 additions
and
2 deletions.
There are no files selected for viewing
43 changes: 43 additions & 0 deletions
43
packages/home-assistant-matter-hub/core/src/aspects/humidity-measurement-aspect.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { ClusterServer, RelativeHumidityMeasurementCluster } from '@project-chip/matter.js/cluster'; | ||
import { Device } from '@project-chip/matter.js/device'; | ||
|
||
import { HomeAssistantMatterEntity } from '@/models/index.js'; | ||
|
||
import { AspectBase } from './aspect-base.js'; | ||
|
||
export class HumidityMeasurementAspect extends AspectBase { | ||
constructor( | ||
private readonly device: Device, | ||
entity: HomeAssistantMatterEntity, | ||
) { | ||
super('HumidityMeasurementAspect', entity); | ||
|
||
device.addClusterServer( | ||
ClusterServer( | ||
RelativeHumidityMeasurementCluster, | ||
{ | ||
minMeasuredValue: null, | ||
maxMeasuredValue: null, | ||
measuredValue: this.getMeasuredValue(entity.state), | ||
}, | ||
{}, | ||
), | ||
); | ||
} | ||
|
||
async update(entity: HomeAssistantMatterEntity): Promise<void> { | ||
const cluster = this.device.getClusterServer(RelativeHumidityMeasurementCluster)!; | ||
const value = this.getMeasuredValue(entity.state); | ||
if (value != null && cluster.getMeasuredValueAttribute() !== value) { | ||
this.log.debug('FROM HA: %s changed measured value to %s', this.entityId, value); | ||
cluster.setMeasuredValueAttribute(value); | ||
} | ||
} | ||
|
||
getMeasuredValue(state: string) { | ||
if (state != null) { | ||
return +state * 100; | ||
} | ||
return null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
packages/home-assistant-matter-hub/core/src/aspects/temperature-measurement-aspect.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { ClusterServer, TemperatureMeasurementCluster } from '@project-chip/matter.js/cluster'; | ||
import { Device } from '@project-chip/matter.js/device'; | ||
|
||
import { HomeAssistantMatterEntity } from '@/models/index.js'; | ||
|
||
import { AspectBase } from './aspect-base.js'; | ||
|
||
export class TemperatureMeasurementAspect extends AspectBase { | ||
private unitOfMeasurement: string | undefined; | ||
|
||
constructor( | ||
private readonly device: Device, | ||
entity: HomeAssistantMatterEntity, | ||
) { | ||
super('TemperatureMeasurementAspect', entity); | ||
this.unitOfMeasurement = entity.attributes.unit_of_measurement; | ||
device.addClusterServer( | ||
ClusterServer( | ||
TemperatureMeasurementCluster, | ||
{ | ||
minMeasuredValue: null, | ||
maxMeasuredValue: null, | ||
measuredValue: this.getTemperatureInCelsius(entity), | ||
}, | ||
{}, | ||
), | ||
); | ||
} | ||
|
||
async update(entity: HomeAssistantMatterEntity): Promise<void> { | ||
const cluster = this.device.getClusterServer(TemperatureMeasurementCluster)!; | ||
const value = this.getTemperatureInCelsius(entity); | ||
if (value != null && cluster.getMeasuredValueAttribute() !== value) { | ||
this.log.debug('FROM HA: %s changed measured value to %s', this.entityId, value); | ||
cluster.setMeasuredValueAttribute(value); | ||
} | ||
} | ||
|
||
getTemperatureInCelsius(entity: HomeAssistantMatterEntity): number | null { | ||
if (entity.state == null) { | ||
return null; | ||
} | ||
|
||
const temperature = +entity.state * 100; | ||
switch (this.unitOfMeasurement) { | ||
case '°C': | ||
return temperature; | ||
case '°F': | ||
return ((temperature - 32) * 5) / 9; | ||
case 'K': | ||
return temperature - 273.15; | ||
default: | ||
this.log.warn('Unsupported unit of measurement for temperature: %s', this.unitOfMeasurement); | ||
return null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
packages/home-assistant-matter-hub/core/src/devices/sensor-device.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { Device, DeviceTypeDefinition, DeviceTypes } from '@project-chip/matter.js/device'; | ||
|
||
import { IdentifyAspect, HumidityMeasurementAspect, TemperatureMeasurementAspect } from '@/aspects/index.js'; | ||
import { AspectBase } from '@/aspects/index.js'; | ||
import { DeviceBase, DeviceBaseConfig } from '@/devices/index.js'; | ||
import { HomeAssistantMatterEntity } from '@/models/index.js'; | ||
|
||
import { EntityDomain } from './index.js'; | ||
import { UnsupportedDeviceClassError } from './utils/unsupported-device-class-error.js'; | ||
|
||
// https://www.home-assistant.io/integrations/sensor/ | ||
enum SensorDeviceClass { | ||
Humidity = 'humidity', | ||
Temperature = 'temperature', | ||
} | ||
|
||
interface InternalSensorDeviceConfig { | ||
deviceType: DeviceTypeDefinition; | ||
createAspects: (device: Device, entity: HomeAssistantMatterEntity) => AspectBase[]; | ||
} | ||
|
||
const humiditySensor: InternalSensorDeviceConfig = { | ||
deviceType: DeviceTypes.HUMIDITY_SENSOR, | ||
createAspects: (device, entity) => [new HumidityMeasurementAspect(device, entity)], | ||
}; | ||
|
||
const temperatureSensor: InternalSensorDeviceConfig = { | ||
deviceType: DeviceTypes.TEMPERATURE_SENSOR, | ||
createAspects: (device, entity) => [new TemperatureMeasurementAspect(device, entity)], | ||
}; | ||
|
||
const deviceClassConfigs: Record<SensorDeviceClass, InternalSensorDeviceConfig> = { | ||
[SensorDeviceClass.Humidity]: humiditySensor, | ||
[SensorDeviceClass.Temperature]: temperatureSensor, | ||
}; | ||
|
||
export class SensorDevice extends DeviceBase { | ||
private static getConfig(entity: HomeAssistantMatterEntity): InternalSensorDeviceConfig { | ||
if (entity.attributes.device_class) { | ||
const config = deviceClassConfigs[entity.attributes.device_class as SensorDeviceClass]; | ||
if (config) { | ||
return config; | ||
} | ||
} | ||
throw new UnsupportedDeviceClassError(EntityDomain.sensor, entity.attributes.device_class ?? '<unknown>'); | ||
} | ||
|
||
constructor(entity: HomeAssistantMatterEntity, config: DeviceBaseConfig) { | ||
const deviceTypeConfig = SensorDevice.getConfig(entity); | ||
super(entity, deviceTypeConfig.deviceType, config); | ||
this.addAspect(new IdentifyAspect(this.matter, entity)); | ||
deviceTypeConfig.createAspects(this.matter, entity).forEach((v) => this.addAspect(v)); | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
packages/home-assistant-matter-hub/core/src/devices/utils/unsupported-device-class-error.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
export class UnsupportedDeviceClassError extends Error { | ||
public domain: string; | ||
public deviceClass: string; | ||
constructor(domain: string, deviceClass: string) { | ||
super(`Device class "${deviceClass}" for domain "${domain}" is not supported!`); | ||
this.domain = domain; | ||
this.deviceClass = deviceClass; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters