@@ -48,43 +48,64 @@ interface SensorConfig {
4848class AirGradientPlatform implements DynamicPlatformPlugin {
4949 public readonly log : Logging ;
5050 public readonly api : API ;
51- public readonly accessories : PlatformAccessory [ ] = [ ] ;
51+
52+ // Keep a stable map of cached and newly-created accessories by UUID
53+ private readonly accessories = new Map < string , PlatformAccessory > ( ) ;
54+
55+ // Persist sensor configs to act on them after didFinishLaunching
56+ private readonly sensorConfigs : SensorConfig [ ] = [ ] ;
5257
5358 constructor ( log : Logging , config : PlatformConfig , api : API ) {
5459 this . log = log ;
5560 this . api = api ;
5661
5762 hap = api . hap ;
5863
59- if ( config . sensors ) {
64+ if ( Array . isArray ( config ? .sensors ) ) {
6065 for ( const sensorConfig of config . sensors as SensorConfig [ ] ) {
61- this . log . info ( 'Initializing sensor with serial number:' , sensorConfig . serialno ) ;
62- this . addAccessory ( sensorConfig ) ;
66+ if ( sensorConfig ?. serialno ) {
67+ this . sensorConfigs . push ( sensorConfig ) ;
68+ this . log . info ( 'Queued sensor for init with serial number:' , sensorConfig . serialno ) ;
69+ }
6370 }
6471 }
6572
66- api . on ( 'didFinishLaunching' , ( ) => {
73+ // Only manipulate accessories after Homebridge has finished launching, so cache restore happens first.
74+ this . api . on ( 'didFinishLaunching' , ( ) => {
6775 this . log . info ( 'Did finish launching' ) ;
68- } ) ;
69- }
70-
71- addAccessory ( sensorConfig : SensorConfig ) {
72- const uuid = hap . uuid . generate ( sensorConfig . serialno ) ;
73- const existingAccessory = this . accessories . find ( accessory => accessory . UUID === uuid ) ;
7476
75- if ( existingAccessory ) {
76- this . log . info ( 'Restoring existing accessory from cache:' , existingAccessory . displayName ) ;
77- new AirGradientSensor ( this , existingAccessory , sensorConfig ) ;
78- } else {
79- this . log . info ( 'Adding new accessory for serial number:' , sensorConfig . serialno ) ;
80- const accessory = new this . api . platformAccessory ( `AirGradient Sensor ${ sensorConfig . serialno } ` , uuid ) ;
81- new AirGradientSensor ( this , accessory , sensorConfig ) ;
82- this . api . registerPlatformAccessories ( 'homebridge-airgradient' , 'AirGradientPlatform' , [ accessory ] ) ;
83- }
77+ for ( const sensorConfig of this . sensorConfigs ) {
78+ const uuid = hap . uuid . generate ( sensorConfig . serialno ) ;
79+ const cached = this . accessories . get ( uuid ) ;
80+
81+ if ( cached ) {
82+ this . log . info ( 'Restoring existing accessory from cache:' , cached . displayName ) ;
83+ if ( ! cached . context . serial ) {
84+ cached . context . serial = sensorConfig . serialno ;
85+ }
86+ new AirGradientSensor ( this , cached , sensorConfig ) ;
87+ } else {
88+ this . log . info ( 'Adding new accessory for serial number:' , sensorConfig . serialno ) ;
89+ const accessory = new this . api . platformAccessory (
90+ `AirGradient Sensor ${ sensorConfig . serialno } ` ,
91+ uuid ,
92+ ) ;
93+ accessory . context . serial = sensorConfig . serialno ;
94+ new AirGradientSensor ( this , accessory , sensorConfig ) ;
95+ this . api . registerPlatformAccessories (
96+ 'homebridge-airgradient' ,
97+ 'AirGradientPlatform' ,
98+ [ accessory ] ,
99+ ) ;
100+
101+ this . accessories . set ( uuid , accessory ) ;
102+ }
103+ }
104+ } ) ;
84105 }
85106
86107 configureAccessory ( accessory : PlatformAccessory ) {
87- this . accessories . push ( accessory ) ;
108+ this . accessories . set ( accessory . UUID , accessory ) ;
88109 }
89110}
90111
@@ -135,7 +156,44 @@ class AirGradientSensor {
135156 this . serviceHumid = this . accessory . getService ( hap . Service . HumiditySensor ) ||
136157 this . accessory . addService ( hap . Service . HumiditySensor ) ;
137158
138- this . updateCharacteristics ( ) ;
159+ // Ensure all optional characteristics exist (getCharacteristic ensures creation for optionals)
160+ this . service . getCharacteristic ( hap . Characteristic . AirQuality ) ;
161+ this . service . getCharacteristic ( hap . Characteristic . PM2_5Density ) ;
162+ this . service . getCharacteristic ( hap . Characteristic . PM10Density ) ;
163+
164+ if ( ! this . service . testCharacteristic ( hap . Characteristic . VOCDensity ) ) {
165+ this . service . addCharacteristic ( hap . Characteristic . VOCDensity ) ;
166+ }
167+ if ( ! this . service . testCharacteristic ( hap . Characteristic . NitrogenDioxideDensity ) ) {
168+ this . service . addCharacteristic ( hap . Characteristic . NitrogenDioxideDensity ) ;
169+ }
170+
171+ this . serviceCO2 . getCharacteristic ( hap . Characteristic . CarbonDioxideDetected ) ;
172+ this . serviceCO2 . getCharacteristic ( hap . Characteristic . CarbonDioxideLevel ) ;
173+
174+ // Initialize safe placeholder values so the Home hub never sees "missing" nodes
175+
176+ this . service . updateCharacteristic (
177+ hap . Characteristic . AirQuality ,
178+ ( hap . Characteristic . AirQuality as any ) . UNKNOWN ?? hap . Characteristic . AirQuality . FAIR ,
179+ ) ;
180+ this . service . updateCharacteristic ( hap . Characteristic . PM2_5Density , 0 ) ;
181+ this . service . updateCharacteristic ( hap . Characteristic . PM10Density , 0 ) ;
182+ this . service . updateCharacteristic ( hap . Characteristic . VOCDensity , 0 ) ;
183+ this . service . updateCharacteristic ( hap . Characteristic . NitrogenDioxideDensity , 0 ) ;
184+
185+ this . serviceCO2 . updateCharacteristic (
186+ hap . Characteristic . CarbonDioxideDetected ,
187+ hap . Characteristic . CarbonDioxideDetected . CO2_LEVELS_NORMAL ,
188+ ) ;
189+ this . serviceCO2 . updateCharacteristic ( hap . Characteristic . CarbonDioxideLevel , 0 ) ;
190+
191+ this . serviceTemp . getCharacteristic ( hap . Characteristic . CurrentTemperature ) ;
192+ this . serviceTemp . updateCharacteristic ( hap . Characteristic . CurrentTemperature , 0 ) ;
193+
194+ this . serviceHumid . getCharacteristic ( hap . Characteristic . CurrentRelativeHumidity ) ;
195+ this . serviceHumid . updateCharacteristic ( hap . Characteristic . CurrentRelativeHumidity , 0 ) ;
196+
139197 this . updateData ( ) ;
140198 }
141199
0 commit comments