homebridge-air
Advanced tools
Comparing version 1.0.0-beta.2 to 1.0.0-beta.3
@@ -5,3 +5,3 @@ { | ||
"singular": true, | ||
"customUi": false, | ||
"customUi": true, | ||
"customUiPath": "./dist/homebridge-ui", | ||
@@ -29,5 +29,2 @@ "headerDisplay": "<p align='center'><img width='250px' src='https://raw.githubusercontent.com/donavanbecker/homebridge-air/latest/branding/Homebridge_x_Air.svg'></p>\n\nThe **Homebridge Air** plugin allows you monitor the current AirQuality for your Zip Code from HomeKit and Siri.", | ||
"required": true, | ||
"x-schema-form": { | ||
"type": "email" | ||
}, | ||
"default": "airnow", | ||
@@ -40,2 +37,8 @@ "oneOf": [ | ||
] | ||
}, | ||
{ | ||
"title": "Aqicn", | ||
"enum": [ | ||
"aqicn" | ||
] | ||
} | ||
@@ -52,4 +55,4 @@ ] | ||
}, | ||
"locationName": { | ||
"title": "Location Name", | ||
"city": { | ||
"title": "City", | ||
"type": "string", | ||
@@ -66,3 +69,6 @@ "required": true | ||
"type": "string", | ||
"required": true | ||
"required": false, | ||
"condition": { | ||
"functionBody": "return (model.devices && model.devices[arrayIndices].city && model.devices[arrayIndices].zipCode);" | ||
} | ||
}, | ||
@@ -72,3 +78,6 @@ "firmware": { | ||
"type": "string", | ||
"placeholder": "1.2.8" | ||
"placeholder": "1.2.8", | ||
"condition": { | ||
"functionBody": "return (model.devices && model.devices[arrayIndices].city && model.devices[arrayIndices].zipCode);" | ||
} | ||
}, | ||
@@ -80,3 +89,6 @@ "refreshRate": { | ||
"placeholder": 1800, | ||
"description": "Indicates the number of seconds between polls of the AirNow service." | ||
"description": "Indicates the number of seconds between polls of the AirNow service.", | ||
"condition": { | ||
"functionBody": "return (model.devices && model.devices[arrayIndices].city && model.devices[arrayIndices].zipCode);" | ||
} | ||
}, | ||
@@ -88,2 +100,5 @@ "logging": { | ||
"default": "", | ||
"condition": { | ||
"functionBody": "return (model.devices && model.devices[arrayIndices].city && model.devices[arrayIndices].zipCode);" | ||
}, | ||
"oneOf": [ | ||
@@ -117,6 +132,8 @@ { | ||
"delete": { | ||
"title": "Delete", | ||
"type": "button", | ||
"style": "danger", | ||
"onClick": "delete" | ||
"title": "Delete Device", | ||
"type": "boolean", | ||
"description": "Delete this device from the plugin cache.", | ||
"condition": { | ||
"functionBody": "return (model.devices && model.devices[arrayIndices].city && model.devices[arrayIndices].zipCode);" | ||
} | ||
} | ||
@@ -172,3 +189,3 @@ } | ||
"type": "tabarray", | ||
"title": "{{ value.locationName || 'New Location (Zip Code)' }}", | ||
"title": "{{ value.city || 'New City (Zip Code)' }}", | ||
"expandable": true, | ||
@@ -180,3 +197,3 @@ "expanded": false, | ||
"devices[].apiKey", | ||
"devices[].locationName", | ||
"devices[].city", | ||
"devices[].zipCode", | ||
@@ -208,2 +225,2 @@ "devices[].distance", | ||
] | ||
} | ||
} |
import type { PlatformAccessory } from 'homebridge'; | ||
import type { AirPlatform } from '../platform.js'; | ||
import type { AirQualityDataArray, devicesConfig } from '../settings.js'; | ||
import type { devicesConfig } from '../settings.js'; | ||
import { deviceBase } from './device.js'; | ||
@@ -14,3 +14,3 @@ /** | ||
SensorUpdateInProgress: boolean; | ||
deviceStatus: AirQualityDataArray; | ||
deviceStatus: any; | ||
constructor(platform: AirPlatform, accessory: PlatformAccessory, device: devicesConfig); | ||
@@ -17,0 +17,0 @@ /** |
@@ -5,3 +5,3 @@ import { interval } from 'rxjs'; | ||
import { request } from 'undici'; | ||
import { AirNowUrl } from '../settings.js'; | ||
import { AirNowUrl, AqicnUrl, HomeKitAQI } from '../settings.js'; | ||
import { deviceBase } from './device.js'; | ||
@@ -57,29 +57,47 @@ /** | ||
async parseStatus() { | ||
let aqi = 0; | ||
if (typeof this.deviceStatus[0] === 'undefined') { | ||
this.errorLog('AirNow air quality Configuration Error - Invalid ZipCode for %s.', this.device.provider); | ||
const provider = this.device.provider; | ||
const status = this.deviceStatus[0]; | ||
if (provider === 'airnow' && !status) { | ||
this.errorLog('AirNow air quality Configuration Error - Invalid ZipCode for %s.', provider); | ||
this.AirQualitySensor.StatusFault = this.hap.Characteristic.StatusFault.GENERAL_FAULT; | ||
} | ||
else if (typeof this.deviceStatus[0].AQI === 'undefined') { | ||
this.errorLog('AirNow air quality Observation Error - %s for %s.', striptags(JSON.stringify(this.deviceStatus)), this.device.provider); | ||
else if (provider === 'airnow' && typeof status.AQI === 'undefined') { | ||
this.errorLog('AirNow air quality Observation Error - %s for %s.', striptags(JSON.stringify(this.deviceStatus)), provider); | ||
this.AirQualitySensor.StatusFault = this.hap.Characteristic.StatusFault.GENERAL_FAULT; | ||
} | ||
else { | ||
for (const key in this.deviceStatus) { | ||
switch (this.deviceStatus[key].ParameterName) { | ||
case 'O3': | ||
this.AirQualitySensor.OzoneDensity = Number.parseFloat(this.deviceStatus[key].AQI.toString()); | ||
break; | ||
case 'PM2.5': | ||
this.AirQualitySensor.PM2_5Density = Number.parseFloat(this.deviceStatus[key].AQI.toString()); | ||
break; | ||
case 'PM10': | ||
this.AirQualitySensor.PM10Density = Number.parseFloat(this.deviceStatus[key].AQI.toString()); | ||
break; | ||
else if (provider === 'airnow' || provider === 'aqicn') { | ||
const pollutants = provider === 'airnow' ? ['O3', 'PM2.5', 'PM10'] : ['o3', 'no2', 'so2', 'pm25', 'pm10', 'co']; | ||
pollutants.forEach((pollutant) => { | ||
const param = provider === 'airnow' ? this.deviceStatus.find(p => p.ParameterName === pollutant) : this.deviceStatus.iaqi[pollutant]?.v; | ||
const aqi = provider === 'airnow' ? Number.parseFloat(param.AQI.toString()) : Number.parseFloat(param); | ||
if (aqi !== undefined) { | ||
switch (pollutant.toLowerCase()) { | ||
case 'o3': | ||
this.AirQualitySensor.OzoneDensity = aqi; | ||
break; | ||
case 'pm2.5': | ||
this.AirQualitySensor.PM2_5Density = aqi; | ||
break; | ||
case 'pm10': | ||
this.AirQualitySensor.PM10Density = aqi; | ||
break; | ||
case 'no2': | ||
this.AirQualitySensor.NitrogenDioxideDensity = aqi; | ||
break; | ||
case 'so2': | ||
this.AirQualitySensor.SulphurDioxideDensity = aqi; | ||
break; | ||
case 'co': | ||
this.AirQualitySensor.CarbonMonoxideLevel = aqi; | ||
break; | ||
} | ||
this.AirQualitySensor.AirQuality = HomeKitAQI(Math.max(0, aqi)); | ||
} | ||
aqi = Math.max(0, Number.parseFloat(this.deviceStatus[key].AQI.toString())); // AirNow.gov defaults to MAX returned observation. | ||
} | ||
this.infoLog(`AirNow air quality AQI is: ${aqi.toString()}`); | ||
}); | ||
this.infoLog(`${provider} air quality AQI is: ${this.AirQualitySensor.AirQuality}`); | ||
this.AirQualitySensor.StatusFault = this.hap.Characteristic.StatusFault.NO_FAULT; | ||
} | ||
else { | ||
await this.errorLog('Unknown air quality provider: %s.', provider); | ||
} | ||
} | ||
@@ -91,15 +109,25 @@ /** | ||
try { | ||
const { body, statusCode } = await request(`${AirNowUrl}&zipCode=${this.device.zipCode}&distance=${this.device.distance}&API_KEY=${this.device.apiKey}`); | ||
const response = await body.json(); | ||
await this.debugWarnLog(`statusCode: ${JSON.stringify(statusCode)}`); | ||
await this.debugLog(`respsonse: ${JSON.stringify(response)}`); | ||
if (statusCode !== 200) { | ||
this.errorLog('AirNow air quality Network or Unknown Error from %s.', this.device.provider); | ||
this.AirQualitySensor.StatusFault = this.hap.Characteristic.StatusFault.GENERAL_FAULT; | ||
await this.debugLog(`Error: ${JSON.stringify(response)}`); | ||
await this.apiError(response); | ||
const providerUrls = { | ||
airnow: `${AirNowUrl}&zipCode=${this.device.zipCode}&distance=${this.device.distance}&API_KEY=${this.device.apiKey}`, | ||
aqicn: `${AqicnUrl}${this.device.city}/?token=${this.device.apiKey}`, | ||
}; | ||
const url = providerUrls[this.device.provider]; | ||
if (url) { | ||
const { body, statusCode } = await request(url); | ||
const response = await body.json(); | ||
await this.debugWarnLog(`statusCode: ${JSON.stringify(statusCode)}`); | ||
await this.debugLog(`response: ${JSON.stringify(response)}`); | ||
if (statusCode !== 200) { | ||
this.errorLog(`${this.device.provider === 'airnow' ? 'AirNow' : 'World Air Quality Index'} air quality Network or Unknown Error from %s.`, this.device.provider); | ||
this.AirQualitySensor.StatusFault = this.hap.Characteristic.StatusFault.GENERAL_FAULT; | ||
await this.debugLog(`Error: ${JSON.stringify(response)}`); | ||
await this.apiError(response); | ||
} | ||
else { | ||
this.deviceStatus = this.device.provider === 'aqicn' ? response.data : response; | ||
await this.parseStatus(); | ||
} | ||
} | ||
else { | ||
this.deviceStatus = response; | ||
await this.parseStatus(); | ||
await this.errorLog('Unknown air quality provider: %s.', this.device.provider); | ||
} | ||
@@ -118,58 +146,18 @@ await this.updateHomeKitCharacteristics(); | ||
async updateHomeKitCharacteristics() { | ||
if (this.AirQualitySensor.AirQuality === undefined) { | ||
await this.debugLog(`AirQuality: ${this.AirQualitySensor.AirQuality}`); | ||
} | ||
else { | ||
this.AirQualitySensor.Service.updateCharacteristic(this.hap.Characteristic.AirQuality, this.AirQualitySensor.AirQuality); | ||
await this.debugLog(`updateCharacteristic AirQuality: ${this.AirQualitySensor.AirQuality}`); | ||
} | ||
if (this.AirQualitySensor.OzoneDensity === undefined) { | ||
await this.debugLog(`OzoneDensity: ${this.AirQualitySensor.OzoneDensity}`); | ||
} | ||
else { | ||
this.AirQualitySensor.Service.updateCharacteristic(this.hap.Characteristic.OzoneDensity, this.AirQualitySensor.OzoneDensity); | ||
await this.debugLog(`updateCharacteristic OzoneDensity: ${this.AirQualitySensor.OzoneDensity}`); | ||
} | ||
if (this.AirQualitySensor.NitrogenDioxideDensity === undefined) { | ||
await this.debugLog(`NitrogenDioxideDensity: ${this.AirQualitySensor.NitrogenDioxideDensity}`); | ||
} | ||
else { | ||
this.AirQualitySensor.Service.updateCharacteristic(this.hap.Characteristic.NitrogenDioxideDensity, this.AirQualitySensor.NitrogenDioxideDensity); | ||
await this.debugLog(`updateCharacteristic NitrogenDioxideDensity: ${this.AirQualitySensor.NitrogenDioxideDensity}`); | ||
} | ||
if (this.AirQualitySensor.SulphurDioxideDensity === undefined) { | ||
await this.debugLog(`SulphurDioxideDensity: ${this.AirQualitySensor.SulphurDioxideDensity}`); | ||
} | ||
else { | ||
this.AirQualitySensor.Service.updateCharacteristic(this.hap.Characteristic.SulphurDioxideDensity, this.AirQualitySensor.SulphurDioxideDensity); | ||
await this.debugLog(`updateCharacteristic SulphurDioxideDensity: ${this.AirQualitySensor.SulphurDioxideDensity}`); | ||
} | ||
if (this.AirQualitySensor.PM2_5Density === undefined) { | ||
await this.debugLog(`PM2_5Density: ${this.AirQualitySensor.PM2_5Density}`); | ||
} | ||
else { | ||
this.AirQualitySensor.Service.updateCharacteristic(this.hap.Characteristic.PM2_5Density, this.AirQualitySensor.PM2_5Density); | ||
await this.debugLog(`updateCharacteristic PM2_5Density: ${this.AirQualitySensor.PM2_5Density}`); | ||
} | ||
if (this.AirQualitySensor.PM10Density === undefined) { | ||
await this.debugLog(`PM10Density: ${this.AirQualitySensor.PM10Density}`); | ||
} | ||
else { | ||
this.AirQualitySensor.Service.updateCharacteristic(this.hap.Characteristic.PM10Density, this.AirQualitySensor.PM10Density); | ||
await this.debugLog(`updateCharacteristic PM10Density: ${this.AirQualitySensor.PM10Density}`); | ||
} | ||
if (this.AirQualitySensor.CarbonMonoxideLevel === undefined) { | ||
await this.debugLog(`CarbonMonoxideLevel: ${this.AirQualitySensor.CarbonMonoxideLevel}`); | ||
} | ||
else { | ||
this.AirQualitySensor.Service.updateCharacteristic(this.hap.Characteristic.CarbonMonoxideLevel, this.AirQualitySensor.CarbonMonoxideLevel); | ||
await this.debugLog(`updateCharacteristic CarbonMonoxideLevel: ${this.AirQualitySensor.CarbonMonoxideLevel}`); | ||
} | ||
if (this.AirQualitySensor.StatusFault === undefined) { | ||
await this.debugLog(`StatusFault: ${this.AirQualitySensor.StatusFault}`); | ||
} | ||
else { | ||
this.AirQualitySensor.Service.updateCharacteristic(this.hap.Characteristic.StatusFault, this.AirQualitySensor.StatusFault); | ||
await this.debugLog(`updateCharacteristic StatusFault: ${this.AirQualitySensor.StatusFault}`); | ||
} | ||
// AirQuality | ||
await this.updateCharacteristic(this.AirQualitySensor.Service, this.hap.Characteristic.AirQuality, this.AirQualitySensor.AirQuality, 'AirQuality'); | ||
// OzoneDensity | ||
await this.updateCharacteristic(this.AirQualitySensor.Service, this.hap.Characteristic.OzoneDensity, this.AirQualitySensor.OzoneDensity, 'OzoneDensity'); | ||
// NitrogenDioxideDensity | ||
await this.updateCharacteristic(this.AirQualitySensor.Service, this.hap.Characteristic.NitrogenDioxideDensity, this.AirQualitySensor.NitrogenDioxideDensity, 'NitrogenDioxideDensity'); | ||
// SulphurDioxideDensity | ||
await this.updateCharacteristic(this.AirQualitySensor.Service, this.hap.Characteristic.SulphurDioxideDensity, this.AirQualitySensor.SulphurDioxideDensity, 'SulphurDioxideDensity'); | ||
// PM2_5Density | ||
await this.updateCharacteristic(this.AirQualitySensor.Service, this.hap.Characteristic.PM2_5Density, this.AirQualitySensor.PM2_5Density, 'PM2_5Density'); | ||
// PM10Density | ||
await this.updateCharacteristic(this.AirQualitySensor.Service, this.hap.Characteristic.PM10Density, this.AirQualitySensor.PM10Density, 'PM10Density'); | ||
// CarbonMonoxideLevel | ||
await this.updateCharacteristic(this.AirQualitySensor.Service, this.hap.Characteristic.CarbonMonoxideLevel, this.AirQualitySensor.CarbonMonoxideLevel, 'CarbonMonoxideLevel'); | ||
// StatusFault | ||
await this.updateCharacteristic(this.AirQualitySensor.Service, this.hap.Characteristic.StatusFault, this.AirQualitySensor.StatusFault, 'StatusFault'); | ||
} | ||
@@ -176,0 +164,0 @@ async apiError(e) { |
@@ -1,2 +0,2 @@ | ||
import type { API, HAP, Logging, PlatformAccessory } from 'homebridge'; | ||
import type { API, CharacteristicValue, HAP, Logging, PlatformAccessory, Service } from 'homebridge'; | ||
import type { AirPlatform } from '../platform.js'; | ||
@@ -20,2 +20,13 @@ import type { AirPlatformConfig, devicesConfig } from '../settings.js'; | ||
/** | ||
* Update the characteristic value and log the change. | ||
* | ||
* @param Service Service | ||
* @param Characteristic Characteristic | ||
* @param CharacteristicValue CharacteristicValue | undefined | ||
* @param CharacteristicName string | ||
* @return: void | ||
* | ||
*/ | ||
updateCharacteristic(Service: Service, Characteristic: any, CharacteristicValue: CharacteristicValue | undefined, CharacteristicName: string): Promise<void>; | ||
/** | ||
* Logging for Device | ||
@@ -22,0 +33,0 @@ */ |
@@ -91,2 +91,24 @@ export class deviceBase { | ||
/** | ||
* Update the characteristic value and log the change. | ||
* | ||
* @param Service Service | ||
* @param Characteristic Characteristic | ||
* @param CharacteristicValue CharacteristicValue | undefined | ||
* @param CharacteristicName string | ||
* @return: void | ||
* | ||
*/ | ||
async updateCharacteristic(Service, Characteristic, CharacteristicValue, CharacteristicName) { | ||
if (CharacteristicValue === undefined) { | ||
this.debugLog(`${CharacteristicName}: ${CharacteristicValue}`); | ||
} | ||
else { | ||
Service.updateCharacteristic(Characteristic, CharacteristicValue); | ||
this.debugLog(`updateCharacteristic ${CharacteristicName}: ${CharacteristicValue}`); | ||
this.debugWarnLog(`${CharacteristicName} context before: ${this.accessory.context[CharacteristicName]}`); | ||
this.accessory.context[CharacteristicName] = CharacteristicValue; | ||
this.debugWarnLog(`${CharacteristicName} context after: ${this.accessory.context[CharacteristicName]}`); | ||
} | ||
} | ||
/** | ||
* Logging for Device | ||
@@ -93,0 +115,0 @@ */ |
@@ -114,3 +114,3 @@ import { readFileSync } from 'node:fs'; | ||
for (const device of this.config.devices) { | ||
await this.infoLog(`Discovered ${device.locationName}`); | ||
await this.infoLog(`Discovered ${device.city}`); | ||
this.createAirQualitySensor(device); | ||
@@ -124,3 +124,3 @@ } | ||
async createAirQualitySensor(device) { | ||
const uuid = this.api.hap.uuid.generate(device.locationName + device.apiKey + device.zipCode); | ||
const uuid = this.api.hap.uuid.generate(device.city + device.apiKey + device.zipCode); | ||
// see if an accessory with the same uuid has already been registered and restored from | ||
@@ -134,5 +134,5 @@ // the cached devices we stored in the `configureAccessory` method above | ||
existingAccessory.context.device = device; | ||
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.locationName, 'locationName', device.locationName); | ||
existingAccessory.displayName = await this.validateAndCleanDisplayName(device.city, 'city', device.city); | ||
existingAccessory.context.serialNumber = device.zipCode; | ||
existingAccessory.context.model = `Current Observation by Zip Code`; | ||
existingAccessory.context.model = device.provider === 'airnow' ? 'AirNow' : device.provider === 'aqicn' ? 'Aqicn' : 'Unknown'; | ||
existingAccessory.context.FirmwareRevision = device.firmware ?? await this.getVersion(); | ||
@@ -145,3 +145,3 @@ this.api.updatePlatformAccessories([existingAccessory]); | ||
new AirQualitySensor(this, existingAccessory, device); | ||
await this.debugLog(`${device.locationName} uuid: ${device.locationName + device.apiKey + device.zipCode}`); | ||
await this.debugLog(`${device.city} uuid: ${device.city + device.apiKey + device.zipCode}`); | ||
} | ||
@@ -154,16 +154,16 @@ else { | ||
// create a new accessory | ||
const accessory = new this.api.platformAccessory(device.locationName, uuid); | ||
const accessory = new this.api.platformAccessory(device.city, uuid); | ||
// store a copy of the device object in the `accessory.context` | ||
// the `context` property can be used to store any data about the accessory you may need | ||
accessory.context.device = device; | ||
accessory.displayName = await this.validateAndCleanDisplayName(device.locationName, 'locationName', device.locationName); | ||
accessory.displayName = await this.validateAndCleanDisplayName(device.city, 'city', device.city); | ||
accessory.context.serialNumber = device.zipCode; | ||
accessory.context.model = `Current Observation by Zip Code`; | ||
accessory.context.model = device.provider === 'airnow' ? 'AirNow' : device.provider === 'aqicn' ? 'Aqicn' : 'Unknown'; | ||
accessory.context.FirmwareRevision = device.firmware ?? await this.getVersion(); | ||
// the accessory does not yet exist, so we need to create it | ||
await this.infoLog(`Adding new accessory: ${device.locationName}`); | ||
await this.infoLog(`Adding new accessory: ${device.city}`); | ||
// create the accessory handler for the newly create accessory | ||
// this is imported from `platformAccessory.ts` | ||
new AirQualitySensor(this, accessory, device); | ||
await this.debugLog(`${device.locationName} uuid: ${device.locationName + device.apiKey + device.zipCode}`); | ||
await this.debugLog(`${device.city} uuid: ${device.city + device.apiKey + device.zipCode}`); | ||
// link the accessory to your platform | ||
@@ -174,3 +174,3 @@ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); | ||
else { | ||
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.locationName)}`); | ||
this.debugErrorLog(`Unable to Register new device: ${JSON.stringify(device.city)}`); | ||
} | ||
@@ -177,0 +177,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import type { PlatformConfig } from 'homebridge'; | ||
import { type PlatformConfig } from 'homebridge'; | ||
/** | ||
@@ -14,2 +14,3 @@ * This is the name of the platform that users will use to register the plugin in the Homebridge config.json | ||
export declare const AirNowUrl = "https://www.airnowapi.org/aq/observation/zipCode/current/?format=application/json"; | ||
export declare const AqicnUrl = "http://api.waqi.info/feed/"; | ||
export interface AirPlatformConfig extends PlatformConfig { | ||
@@ -25,3 +26,3 @@ name?: string; | ||
distance?: string; | ||
locationName?: string; | ||
city?: string; | ||
zipCode?: string; | ||
@@ -37,3 +38,3 @@ firmware: string; | ||
} | ||
interface AirQualityData { | ||
interface AirNowAirQualityData { | ||
DateObserved: string; | ||
@@ -50,4 +51,46 @@ HourObserved: number; | ||
} | ||
export type AirQualityDataArray = AirQualityData[]; | ||
export type AirNowAirQualityDataArray = AirNowAirQualityData[]; | ||
export interface AqicnData { | ||
status: string; | ||
data: { | ||
idx: number; | ||
aqi: number; | ||
time: { | ||
s: string; | ||
tz: string; | ||
}; | ||
city: { | ||
name: string; | ||
geo: [number, number]; | ||
url: string; | ||
}; | ||
attributions: { | ||
name: string; | ||
url: string; | ||
}[]; | ||
iaqi: { | ||
pm25: { | ||
v: number; | ||
}; | ||
}; | ||
forecast: { | ||
daily: { | ||
pm25: { | ||
v: number; | ||
}[]; | ||
pm10: { | ||
v: number; | ||
}[]; | ||
o3: { | ||
v: number; | ||
}[]; | ||
uvi: { | ||
v: number; | ||
}[]; | ||
}; | ||
}; | ||
}; | ||
} | ||
export declare function HomeKitAQI(aqi: number): number; | ||
export {}; | ||
//# sourceMappingURL=settings.d.ts.map |
@@ -13,2 +13,26 @@ /** | ||
export const AirNowUrl = 'https://www.airnowapi.org/aq/observation/zipCode/current/?format=application/json'; | ||
export const AqicnUrl = 'http://api.waqi.info/feed/'; | ||
export function HomeKitAQI(aqi) { | ||
if (!aqi) { | ||
return (0); // Error or unknown response (this.hap.Characteristic.AirQuality.UNKNOWN) | ||
} | ||
else if (aqi <= 50) { | ||
return (1); // Return EXCELLENT (this.hap.Characteristic.AirQuality.EXCELLENT) | ||
} | ||
else if (aqi >= 51 && aqi <= 100) { | ||
return (2); // Return GOOD (this.hap.Characteristic.AirQuality.GOOD) | ||
} | ||
else if (aqi >= 101 && aqi <= 150) { | ||
return (3); // Return FAIR (this.hap.Characteristic.AirQuality.FAIR) | ||
} | ||
else if (aqi >= 151 && aqi <= 200) { | ||
return (4); // Return INFERIOR (this.hap.Characteristic.AirQuality.INFERIOR) | ||
} | ||
else if (aqi >= 201) { | ||
return (5); // Return POOR (Homekit only goes to cat 5, so combined the last two AQI cats of Very Unhealty and Hazardous. (this.hap.Characteristic.AirQuality.POOR) | ||
} | ||
else { | ||
return (0); // Error or unknown response. | ||
} | ||
} | ||
//# sourceMappingURL=settings.js.map |
@@ -5,3 +5,3 @@ { | ||
"type": "module", | ||
"version": "1.0.0-beta.2", | ||
"version": "1.0.0-beta.3", | ||
"description": "The AirNow plugin allows you to monitor the current AirQuality for your Zip Code from HomeKit and Siri.", | ||
@@ -33,3 +33,9 @@ "author": { | ||
"air", | ||
"Air Quality" | ||
"Air Quality", | ||
"homebridge", | ||
"airnow", | ||
"aqicn", | ||
"air quality", | ||
"waqi", | ||
"pollution" | ||
], | ||
@@ -62,16 +68,16 @@ "main": "dist/index.js", | ||
"devDependencies": { | ||
"@antfu/eslint-config": "^3.3.2", | ||
"@antfu/eslint-config": "^3.6.2", | ||
"@types/aes-js": "^3.1.4", | ||
"@types/debug": "^4.1.12", | ||
"@types/fs-extra": "^11.0.4", | ||
"@types/jest": "^29.5.12", | ||
"@types/jest": "^29.5.13", | ||
"@types/mdast": "^4.0.4", | ||
"@types/node": "^22.5.4", | ||
"@types/node": "^22.5.5", | ||
"@types/semver": "^7.5.8", | ||
"@types/source-map-support": "^0.5.10", | ||
"@vitest/coverage-v8": "^2.0.5", | ||
"@vitest/coverage-v8": "^2.1.1", | ||
"eslint": "^9.10.0", | ||
"eslint-plugin-format": "^0.1.2", | ||
"homebridge": "^1.8.4", | ||
"homebridge-config-ui-x": "4.57.1", | ||
"homebridge-config-ui-x": "4.58.0", | ||
"jest": "^29.7.0", | ||
@@ -82,7 +88,7 @@ "nodemon": "^3.1.4", | ||
"ts-node": "^10.9.2", | ||
"typedoc": "^0.26.6", | ||
"typescript": "^5.5.4", | ||
"typedoc": "^0.26.7", | ||
"typescript": "^5.6.2", | ||
"typescript-axios-wb": "^1.0.3", | ||
"vitest": "^2.0.5" | ||
"vitest": "^2.1.1" | ||
} | ||
} |
@@ -1,2 +0,1 @@ | ||
<span align="center"> | ||
@@ -13,3 +12,3 @@ | ||
<p>The Homebridge <a href="https://airnow.gove">Air</a> | ||
<p>The Homebridge <a href="https://airnow.gove">Air</a> | ||
plugin allows you monitor the current AirQuality for your Zip Code from HomeKit and Siri. | ||
@@ -39,4 +38,17 @@ </p> | ||
## Supported Air Quality Providers | ||
Currently supports AQI Services: | ||
- [AirNow](https://www.airnow.gov/) which is limited to the USA. A valid ZipCode is required. | ||
- [Aqicn](https://www.aqicn.org/) which has international support, provided by the [World Air Quality Index Project](http://waqi.info/). | ||
Depending on where exactly you would like to monitor AQI, one service may be more appropriate than the other. | ||
## Supported Air Quality Features | ||
This plugin will create an AirQualitySensor element. The Home app works well, but the Eve app seems to show more measurements. Measurements retrieved are PM2.5, PM10, & O3 for AirNow. Aqicn adds NO2, SO2, CO... | ||
This plugin will create an AirQualitySensor element. The Home app works well, but the Eve app seems to show more measurements. Measurements retrieved are PM2.5, PM10, & O3 for AirNow. Aqicn adds NO2, SO2, CO... | ||
## Thanks | ||
Thank you to [ToddGreenfield](https://github.com/ToddGreenfield) for the the work done on the accesorry based plugin [homebridge-airnow](https://github.com/ToddGreenfield/homebridge-airnow/blob/master/README.md). |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
322351
2961
53