diff --git a/CHANGELOG.md b/CHANGELOG.md index a015c0b..32da66c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ ### 2.2.0-beta +* Add support for WH26 and WN30 +* Renamed WH31 and WH34 to WN31 and WN34 respectively + + +### 2.2.0-beta + * Add support for WH41, WH43, WH45, WH46, and WH57 * Implement Air Quality, Carbon Dioxide, and Lightning sensors * Minor adjustments to thresholds for low battery indication diff --git a/README.md b/README.md index ed4bd30..b285e12 100644 --- a/README.md +++ b/README.md @@ -114,20 +114,22 @@ This plugin currently supports the Ecowitt devices shown in the table below. If | Device | Description | Service Types| Product Image | | -------- | ------- | ------- | ------ | -| GW1000 / GW1100 | WiFi Weather Station Gateway | | GW1000 | -| GW1200 | WiFi Weather Station Gateway | | GW1200 | -| GW2000 | WiFi Weather Station Gateway | | GW2000 | +| GW1000 / GW1100 | WiFi Weather Station Gateway | | GW1000 | +| GW1200 | WiFi Weather Station Gateway | | GW1200 | +| GW2000 | WiFi Weather Station Gateway | | GW2000 | | HP2550 (and variants) | 7" TFT Color Display Console | | HP2550 | -| HP2560 (and variants) | 7" TFT Color Display Console with Indoor Sensor Antenna | | HP2560 | -| HP3500 (and variants) | 4.3" TFT Color Display Console | | HP3500 | -| WH25 | Indoor Temperature, Humidity and Barometric Sensor | | WH25 | -| WH31 / WN31 (All variants)| Multi-Channel Temperature and Humidity Sensor | | WH31 | -| WH34 / WN34 (All variants)| Multi-Channel Temperature Sensor | | WH34 | +| HP2560 (and variants) | 7" TFT Color Display Console with Indoor Sensor Antenna | | HP2560 | +| HP3500 (and variants) | 4.3" TFT Color Display Console | | HP3500 | +| WH25 | Indoor Temperature, Humidity and Barometric Sensor | | WH25 | +| WH26| Outdoor Temperature and Humidity Sensor | | WH26 | +| WN30 | Thermometer with Probe | | WN30 | +| WN31 / WH31 (and EP variants) | Multi-Channel Temperature and Humidity Sensor | | WN31 | +| WN34 (S, D, and L variants) | Multi-Channel Temperature Sensor | | WN34 | | WH40 | Self-Emptying Rain Collector Rainfall Sensor | | WH40 | | WH41 / WH43 | PM2.5 Air Quality Sensor Monitor Outdoor | | WH41 | | WH45 | 5-in-1 PM2.5 / PM10 / CO₂ Air Quality Sensor | | WH45 | | WH46 | 7-in-1 PM1.0 / PM2.5 / PM4.0 / PM10 / CO₂ Air Quality Sensor | | WH46 | -| WH51 (All variants)| Wireless Soil Moisture Sensor | | WH51 | +| WH51 (and L variant)| Wireless Soil Moisture Sensor | | WH51 | | WH55 | Water Leak Detection Sensor with Loud Audio Alarm | | WH55 | | WH57 | Lightning Detection Sensor | | WH57 | | WH65 | Solar Powered 7-in-1 Outdoor Station | | WH65 | @@ -166,7 +168,7 @@ It's recommended to configure the plugin through the Plugin Config UI on the Hom | units.distance | `mi` | The units to display distance such as lightning strike distance. Possible values are:

`mi`: Miles
`km`: Kilometers | | units.temperature | `fh` | The units to display temperature. Possible values are:

`fh`: Fahrenheit
`ce`: Celcius | | thresholds | `{}` | A mapping of a weather data property to the trigger threshold for that property. By default no thresholds are set. Trigger thresholds should be specified in the units selected under the `units` configuration block. Possible keys are:

`windSpeed`
`windGustSpeed`
`windMaxDailySpeed`
`rainRate`
`rainEventTotal`
`rainHourlyTotal`
`rainDailyTotal`
`rainWeeklyTotal`
`rainMonthlyTotal`
`rainYearlyTotal`
`uvIndex`
`lightningEvents`
`lightningDistance *`
`lightningTime *`

\*The value of the weather data property must be greater than the threshold to trigger the accessory (motion detected), except for `lightningDistance` and `lightningTime` which are triggered when the weather data property is less than the threshold. | -| hidden | `{}` | A mapping of a weather data property or device to whether it should be displayed. By default no weather data or devices are hidden. Possible keys to hide weather data are:

`windDirection`
`windSpeed`
`windGustSpeed`
`windMaxDailySpeed`
`rainRate`
`rainEventTotal`
`rainHourlyTotal`
`rainDailyTotal`
`rainWeeklyTotal`
`rainMonthlyTotal`
`rainYearlyTotal`
`solarRadiation`
`uvIndex`
`temperature`
`humdity`
`indoorTemperature`
`indoorHumdity`
`soilMoisture`
`dewPoint`
`waterLeak`
`airQualityPM25`
`airQualityPM25Avg`
`airQualityPM10`
`airQualityPM10Avg`
`carbonDioxide`
`carbonDioxideAvg`
`lightningEvents`
`lightningDistance`
`lightningTime`

Possible keys to hide devices are:

`GW1000`
`GW2000`
`HP2560`
`WH25`
`WH31`
`WH34`
`WH40`
`WH41`
`WH45`
`WH46`
`WH51`
`WH55`
`WH57`
`WS85`
| +| hidden | `{}` | A mapping of a weather data property or device to whether it should be displayed. By default no weather data or devices are hidden. Possible keys to hide weather data are:

`windDirection`
`windSpeed`
`windGustSpeed`
`windMaxDailySpeed`
`rainRate`
`rainEventTotal`
`rainHourlyTotal`
`rainDailyTotal`
`rainWeeklyTotal`
`rainMonthlyTotal`
`rainYearlyTotal`
`solarRadiation`
`uvIndex`
`temperature`
`humdity`
`indoorTemperature`
`indoorHumdity`
`soilMoisture`
`dewPoint`
`waterLeak`
`airQualityPM25`
`airQualityPM25Avg`
`airQualityPM10`
`airQualityPM10Avg`
`carbonDioxide`
`carbonDioxideAvg`
`lightningEvents`
`lightningDistance`
`lightningTime`

Possible keys to hide devices are:

`GW1000`
`GW2000`
`HP2560`
`WH25`
`WH26`
`WN30`
`WN31`
`WN34`
`WH40`
`WH41`
`WH45`
`WH46`
`WH51`
`WH55`
`WH57`
`WS85`
| | nameOverrides | `[]` | A list of key value pairs that specifies the override name for an accessory service. Each override takes on the form:

`{"key": "", "value", "
The service identifier is specified in the form `YYYY(CHZ)` or if an accessory has multiple services the weather data property should be included in the identifier `YYYY(CHZ):`.

`YYYY` is the device id (e.g. WH41)
`(CHZ)` is the optional channel id if the device uses a channel.

The weather data property can be set to any of the weather data keys indicated in `hidden` | | additional.staticNames | `false` | Set to `true` to not show the weather metric value in the service names of the accessory so that the service names do not change. | | additional.validateMac | `true` | Check that the MAC address in each data report matches the MAC address specified for the plugin, and do not process the data report if it does not match. | diff --git a/config.schema.json b/config.schema.json index 2103048..2ac794f 100644 --- a/config.schema.json +++ b/config.schema.json @@ -371,13 +371,23 @@ "type": "boolean", "required": false }, - "WH31": { - "title": "WH31", + "WH26": { + "title": "WH26", "type": "boolean", "required": false }, - "WH34": { - "title": "WH34", + "WN30": { + "title": "WN30", + "type": "boolean", + "required": false + }, + "WN31": { + "title": "WN31", + "type": "boolean", + "required": false + }, + "WN34": { + "title": "WN34", "type": "boolean", "required": false }, @@ -663,22 +673,24 @@ "hidden.GW2000", "hidden.HP2560", "hidden.WH25", - "hidden.WH31" + "hidden.WH26", + "hidden.WN30" ] }, { "type": "flex", "items": [ - "hidden.WH34", + "hidden.WN31", + "hidden.WN34", "hidden.WH40", "hidden.WH41", - "hidden.WH45", - "hidden.WH46" + "hidden.WH45" ] }, { "type": "flex", "items": [ + "hidden.WH46", "hidden.WH51", "hidden.WH55", "hidden.WH57", diff --git a/docs/assets/WH26.jpeg b/docs/assets/WH26.jpeg new file mode 100644 index 0000000..c7141ce Binary files /dev/null and b/docs/assets/WH26.jpeg differ diff --git a/docs/assets/WN30.jpeg b/docs/assets/WN30.jpeg new file mode 100644 index 0000000..b193264 Binary files /dev/null and b/docs/assets/WN30.jpeg differ diff --git a/docs/assets/WH31.jpeg b/docs/assets/WN31.jpeg similarity index 100% rename from docs/assets/WH31.jpeg rename to docs/assets/WN31.jpeg diff --git a/package.json b/package.json index 8f85b54..9a4e9d0 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "private": false, "displayName": "Homebridge Ecowitt Weather Sensors", "name": "homebridge-ecowitt-weather-sensors", - "version": "2.2.0-beta", + "version": "2.3.0-beta", "description": "Complete HomeKit support for Ecowitt Weather Sensors through Homebrige", "license": "Apache-2.0", "icon": "https://raw.githubusercontent.com/rhockenbury/homebridge-ecowitt-weather-sensors/master/docs/assets/ecowitt-logo.png", diff --git a/src/EcowittAccessory.ts b/src/EcowittAccessory.ts index aaa8056..720da1c 100644 --- a/src/EcowittAccessory.ts +++ b/src/EcowittAccessory.ts @@ -5,8 +5,10 @@ import * as utils from './Utils'; //------------------------------------------------------------------------------ export class EcowittAccessory { - public requiredData: string[] = []; - public optionalData: string[] = []; + public requiredData: string[] = []; // fields that must be provided + public optionalData: string[] = []; // fields that are used if available + public unusedData: string[] = []; // fields that are not used / displayed + protected readonly accessoryId: string; protected readonly shortServiceId: string; diff --git a/src/EcowittPlatform.ts b/src/EcowittPlatform.ts index fa1526f..f4bb38f 100644 --- a/src/EcowittPlatform.ts +++ b/src/EcowittPlatform.ts @@ -14,7 +14,9 @@ import { GW1000 } from './devices/GW1000'; import { GW2000 } from './devices/GW2000'; import { HP2560} from './devices/HP2560'; import { WH25 } from './devices/WH25'; -import { WH31 } from './devices/WH31'; +import { WH26 } from './devices/WH26'; +import { WN30 } from './devices/WN30'; +import { WN31 } from './devices/WN31'; import { WH40 } from './devices/WH40'; import { WH41 } from './devices/WH41'; import { WH45 } from './devices/WH45'; @@ -23,7 +25,7 @@ import { WH51 } from './devices/WH51'; import { WH55 } from './devices/WH55'; import { WH57 } from './devices/WH57'; //import { WH65 } from './devices/WH65'; -import { WH34 } from './devices/WH34'; +import { WN34 } from './devices/WN34'; import { WS85 } from './devices/WS85'; import * as utils from './Utils'; @@ -129,19 +131,27 @@ export class EcowittPlatform implements DynamicPlatformPlugin { this.dataReportServer.use(bodyParser.json()); this.dataReportServer.use(bodyParser.urlencoded({ extended: true })); - this.dataReportServer.post(encodedPath, (req: Request, res: Response) => { + this.dataReportServer.post(encodedPath, (req: Request, res: Response, next: Next) => { this.log.debug(`Received request for ${req.method} ${req.path} from ${req.socket.remoteAddress}`); - this.onDataReport(req.body); + try { + this.onDataReport(req.body); + } catch (err) { + next(err); + } res.send(); }); - this.dataReportServer.all('*', (req: Request, res: Response) => { + this.dataReportServer.all('*', (req: Request, res: Response, next: Next) => { if (utils.falsy(this.config?.additional?.acceptAnyPath)) { this.log.warn(`Received request for ${req.method} ${req.path} from ${req.socket.remoteAddress}. ` + `Configure the Ecowitt base station to send data reports to POST ${encodedPath}`); } else { this.log.debug(`Received request for ${req.method} ${req.path} from ${req.socket.remoteAddress}`); - this.onDataReport(req.body); + try { + this.onDataReport(req.body); + } catch (err) { + next(err); + } } res.send(); }); @@ -343,9 +353,6 @@ export class EcowittPlatform implements DynamicPlatformPlugin { this.log.warn(`Base station was not detected from the data report. Please file a bug report at ${utils.BUG_REPORT_LINK}`); } - // if (!utils.includesAny(hidden, ['WH65']) && !utils.includesAll(hidden, WH65.properties)) { - // this.addSensorType(dataReport.wh65batt !== undefined, 'WH65'); - // } if (!utils.includesAny(hidden, ['WS85']) && !utils.includesAll(hidden, WS85.properties)) { // NOTE: Typo in WS-85 as it responds with wh85batt instead of expected ws85batt. @@ -355,24 +362,47 @@ export class EcowittPlatform implements DynamicPlatformPlugin { ); } - if (!utils.includesAny(hidden, ['WH25']) && !utils.includesAll(hidden, WH25.properties)) { - this.addSensorType(dataReport.wh25batt !== undefined, 'WH25'); + // if (!utils.includesAny(hidden, ['WH65']) && !utils.includesAll(hidden, WH65.properties)) { + // this.addSensorType(dataReport.wh65batt !== undefined, 'WH65'); + // } + + if (!utils.includesAny(hidden, ['WH57']) && !utils.includesAll(hidden, WH57.properties)) { + this.addSensorType(dataReport.wh57batt !== undefined, 'WH57'); } - if (!utils.includesAny(hidden, ['WH31']) && !utils.includesAll(hidden, WH31.properties)) { + if (!utils.includesAny(hidden, ['WH55']) && !utils.includesAll(hidden, WH55.properties)) { + for (let channel = 1; channel <= 4; channel++) { + if (!utils.includesAny(hidden, [`WH55CH${channel}`])) { + this.addSensorType( + dataReport[`leakbatt${channel}`] !== undefined, + 'WH55', + channel, + ); + } + } + } + + if (!utils.includesAny(hidden, ['WH51']) && !utils.includesAll(hidden, WH51.properties)) { for (let channel = 1; channel <= 8; channel++) { - if (!utils.includesAny(hidden, [`WH31CH${channel}`])) { + if (!utils.includesAny(hidden, [`WH51CH${channel}`])) { this.addSensorType( - dataReport[`batt${channel}`] !== undefined, - 'WH31', + dataReport[`soilbatt${channel}`] !== undefined, + 'WH51', channel, ); } } } - if (!utils.includesAny(hidden, ['WH40']) && !utils.includesAll(hidden, WH40.properties)) { - this.addSensorType(dataReport.wh40batt !== undefined, 'WH40'); + // + // WH45 and WH46 are the same, except WH45 does not have PM1.0 and PM4.0 + // + if (!utils.includesAny(hidden, ['WH46']) && !utils.includesAll(hidden, WH46.properties)) { + this.addSensorType(dataReport.co2_batt !== undefined && dataReport.pm1_co2 !== undefined, 'WH46'); + } + + if (!utils.includesAny(hidden, ['WH45']) && !utils.includesAll(hidden, WH45.properties)) { + this.addSensorType(dataReport.co2_batt !== undefined && dataReport.pm1_co2 === undefined, 'WH45'); } if (!utils.includesAny(hidden, ['WH41']) && !utils.includesAll(hidden, WH41.properties)) { @@ -387,54 +417,57 @@ export class EcowittPlatform implements DynamicPlatformPlugin { } } - if (!utils.includesAny(hidden, ['WH45']) && !utils.includesAll(hidden, WH45.properties)) { - this.addSensorType(dataReport.co2_batt !== undefined && dataReport.pm1_co2 === undefined, 'WH45'); - } - - if (!utils.includesAny(hidden, ['WH46']) && !utils.includesAll(hidden, WH46.properties)) { - this.addSensorType(dataReport.co2_batt !== undefined && dataReport.pm1_co2 !== undefined, 'WH46'); + if (!utils.includesAny(hidden, ['WH40']) && !utils.includesAll(hidden, WH40.properties)) { + this.addSensorType(dataReport.wh40batt !== undefined, 'WH40'); } - if (!utils.includesAny(hidden, ['WH51']) && !utils.includesAll(hidden, WH51.properties)) { + if (!utils.includesAny(hidden, ['WN34']) && !utils.includesAll(hidden, WN34.properties)) { for (let channel = 1; channel <= 8; channel++) { - if (!utils.includesAny(hidden, [`WH51CH${channel}`])) { + if (!utils.includesAny(hidden, [`WN34CH${channel}`])) { this.addSensorType( - dataReport[`soilbatt${channel}`] !== undefined, - 'WH51', + dataReport[`tf_batt${channel}`] !== undefined, + 'WN34', channel, ); } } } - if (!utils.includesAny(hidden, ['WH55']) && !utils.includesAll(hidden, WH55.properties)) { - for (let channel = 1; channel <= 4; channel++) { - if (!utils.includesAny(hidden, [`WH55CH${channel}`])) { + // + // WN31 and WN30 are the same, except WN30 does not have humidity + // + if (!utils.includesAny(hidden, ['WN31']) && !utils.includesAll(hidden, WN31.properties)) { + for (let channel = 1; channel <= 8; channel++) { + if (!utils.includesAny(hidden, [`WN31CH${channel}`])) { this.addSensorType( - dataReport[`leakbatt${channel}`] !== undefined, - 'WH55', + dataReport[`batt${channel}`] !== undefined && dataReport[`humidity${channel}`] !== undefined, + 'WN31', channel, ); } } } - if (!utils.includesAny(hidden, ['WH57']) && !utils.includesAll(hidden, WH57.properties)) { - this.addSensorType(dataReport.wh57batt !== undefined, 'WH57'); - } - - if (!utils.includesAny(hidden, ['WH34']) && !utils.includesAll(hidden, WH34.properties)) { + if (!utils.includesAny(hidden, ['WN30']) && !utils.includesAll(hidden, WN30.properties)) { for (let channel = 1; channel <= 8; channel++) { - if (!utils.includesAny(hidden, [`WH34CH${channel}`])) { + if (!utils.includesAny(hidden, [`WN30CH${channel}`])) { this.addSensorType( - dataReport[`tf_batt${channel}`] !== undefined, - 'WH34', + dataReport[`batt${channel}`] !== undefined && dataReport[`humidity${channel}`] === undefined, + 'WN30', channel, ); } } } + if (!utils.includesAny(hidden, ['WH26']) && !utils.includesAll(hidden, WH26.properties)) { + this.addSensorType(dataReport.wh26batt !== undefined, 'WH26'); + } + + if (!utils.includesAny(hidden, ['WH25']) && !utils.includesAll(hidden, WH25.properties)) { + this.addSensorType(dataReport.wh25batt !== undefined, 'WH25'); + } + if (this.baseStationInfo.sensors.length === 0) { this.log.warn('No devices discovered from data report. Verify plugin configuration with docs ' + `at ${utils.GATEWAY_SETUP_LINK}, and/or file a feature request to support your Ecowitt devices at ${utils.FEATURE_REQ_LINK}`); @@ -473,9 +506,9 @@ export class EcowittPlatform implements DynamicPlatformPlugin { ]); } - if (typeof sensor.accessory !== 'undefined' && sensor.accessory.optionalData.length > 0) { + if (typeof sensor.accessory !== 'undefined' && sensor.accessory.unusedData.length > 0) { this.log.info(`Note that accessory ${sensor.type} does not currently display the following ` + - `data: ${sensor.accessory.optionalData}`); + `data: ${sensor.accessory.unusedData}`); } if (typeof sensor.accessory !== 'undefined') { @@ -553,8 +586,20 @@ export class EcowittPlatform implements DynamicPlatformPlugin { sensor.accessory = new WH25(this, accessory); break; - case 'WH31': - sensor.accessory = new WH31(this, accessory, sensor.channel); + case 'WH26': + sensor.accessory = new WH26(this, accessory); + break; + + case 'WN30': + sensor.accessory = new WN30(this, accessory, sensor.channel); + break; + + case 'WN31': + sensor.accessory = new WN31(this, accessory, sensor.channel); + break; + + case 'WN34': + sensor.accessory = new WN34(this, accessory, sensor.channel); break; case 'WH40': @@ -589,10 +634,6 @@ export class EcowittPlatform implements DynamicPlatformPlugin { // sensor.accessory = new WH65(this, accessory); // break; - case 'WH34': - sensor.accessory = new WH34(this, accessory, sensor.channel); - break; - case 'WS85': sensor.accessory = new WS85(this, accessory); break; diff --git a/src/Utils.ts b/src/Utils.ts index 17cc334..9a9c1f7 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -440,11 +440,11 @@ export function v1ConfigRemapper(v1Config: any): PlatformConfig { } if (truthy(v1Config?.th?.hide)) { - v2Config.hidden['WH31'] = true; + v2Config.hidden['WN31'] = true; } if (truthy(v1Config?.tf?.hide)) { - v2Config.hidden['WH34'] = true; + v2Config.hidden['WN34'] = true; } if (truthy(v1Config?.soil?.hide)) { @@ -581,14 +581,14 @@ export function v1ConfigRemapper(v1Config: any): PlatformConfig { // name overrides for (let channel = 1; channel <= 8; channel++) { if (v1Config?.th?.[`name${channel}`]) { - v2Config.nameOverrides.push({'key': `WH31CH${channel}:temperature`, 'value': v1Config?.th?.[`name${channel}`]}); - v2Config.nameOverrides.push({'key': `WH31CH${channel}:humidity`, 'value': v1Config?.th?.[`name${channel}`]}); + v2Config.nameOverrides.push({'key': `WN31CH${channel}:temperature`, 'value': v1Config?.th?.[`name${channel}`]}); + v2Config.nameOverrides.push({'key': `WN31CH${channel}:humidity`, 'value': v1Config?.th?.[`name${channel}`]}); } } for (let channel = 1; channel <= 8; channel++) { if (v1Config?.tf?.[`name${channel}`]) { - v2Config.nameOverrides.push({'key': `WH34CH${channel}:temperature`, 'value': v1Config?.tf?.[`name${channel}`]}); + v2Config.nameOverrides.push({'key': `WN34CH${channel}:temperature`, 'value': v1Config?.tf?.[`name${channel}`]}); } } diff --git a/src/devices/GW1000.ts b/src/devices/GW1000.ts index eb60564..830874d 100644 --- a/src/devices/GW1000.ts +++ b/src/devices/GW1000.ts @@ -18,10 +18,10 @@ export class GW1000 extends EcowittAccessory { protected readonly accessory: PlatformAccessory, protected readonly modelName: string, ) { - super(platform, accessory, `${modelName}`, `Ecowitt Gateway ${modelName}`); + super(platform, accessory, `${modelName}`, `${modelName} Gateway`); this.requiredData = ['tempinf', 'humidityin']; - this.optionalData = ['baromrelin', 'baromabsin']; + this.unusedData = ['baromrelin', 'baromabsin']; const hideConfig = this.platform.config?.hidden || {}; const hidden = Object.keys(hideConfig).filter(k => !!hideConfig[k]); diff --git a/src/devices/GW2000.ts b/src/devices/GW2000.ts index 495081d..23a7878 100644 --- a/src/devices/GW2000.ts +++ b/src/devices/GW2000.ts @@ -18,10 +18,10 @@ export class GW2000 extends EcowittAccessory { protected readonly accessory: PlatformAccessory, protected readonly modelName: string, ) { - super(platform, accessory, `${modelName}`, `Ecowitt Gateway ${modelName}`); + super(platform, accessory, `${modelName}`, `${modelName} Gateway`); this.requiredData = ['tempinf', 'humidityin']; - this.optionalData = ['baromrelin', 'baromabsin']; + this.unusedData = ['baromrelin', 'baromabsin']; const hideConfig = this.platform.config?.hidden || {}; const hidden = Object.keys(hideConfig).filter(k => !!hideConfig[k]); diff --git a/src/devices/HP2560.ts b/src/devices/HP2560.ts index 2af481b..823888b 100644 --- a/src/devices/HP2560.ts +++ b/src/devices/HP2560.ts @@ -18,10 +18,10 @@ export class HP2560 extends EcowittAccessory { protected readonly accessory: PlatformAccessory, protected readonly modelName: string, ) { - super(platform, accessory, `${modelName}`, `Ecowitt Gateway ${modelName}`); + super(platform, accessory, `${modelName}`, `${modelName} Gateway`); this.requiredData = ['tempinf', 'humidityin']; - this.optionalData = ['baromrelin', 'baromabsin']; + this.unusedData = ['baromrelin', 'baromabsin']; const hideConfig = this.platform.config?.hidden || {}; const hidden = Object.keys(hideConfig).filter(k => !!hideConfig[k]); diff --git a/src/devices/WH25.ts b/src/devices/WH25.ts index 013cbc6..9b468d6 100644 --- a/src/devices/WH25.ts +++ b/src/devices/WH25.ts @@ -18,10 +18,10 @@ export class WH25 extends EcowittAccessory { protected readonly platform: EcowittPlatform, protected readonly accessory: PlatformAccessory, ) { - super(platform, accessory, 'WH25', 'Indoor Thermo Hygro Baro Sensor'); + super(platform, accessory, 'WH25', 'WH25 Indoor Thermo Hygro Baro Sensor'); this.requiredData = ['wh25batt', 'tempinf', 'humidityin']; - this.optionalData = ['baromrelin', 'baromabsin']; + this.unusedData = ['baromrelin', 'baromabsin']; this.battery = this.addBattery('', false); diff --git a/src/devices/WH26.ts b/src/devices/WH26.ts new file mode 100644 index 0000000..098e5af --- /dev/null +++ b/src/devices/WH26.ts @@ -0,0 +1,71 @@ +import { Service, PlatformAccessory } from 'homebridge'; +import { EcowittPlatform } from './../EcowittPlatform'; +import { EcowittAccessory } from './../EcowittAccessory'; +import { TemperatureSensor } from './../sensors/TemperatureSensor'; +import { HumiditySensor } from './../sensors/HumiditySensor'; +import * as utils from './../Utils'; + +//------------------------------------------------------------------------------ + +export class WH26 extends EcowittAccessory { + static readonly properties: string[] = ['temperature', 'humidity']; + + protected battery: Service; + protected temperature: TemperatureSensor | undefined; + protected humidity: HumiditySensor | undefined; + + constructor( + protected readonly platform: EcowittPlatform, + protected readonly accessory: PlatformAccessory, + ) { + super(platform, accessory, 'WH26', 'WH26 Outdoor Thermo Hygro Sensor'); + + this.requiredData = ['wh26batt', 'tempf', 'humidity']; + + this.battery = this.addBattery('', false); + + const hideConfig = this.platform.config?.hidden || {}; + const hidden = Object.keys(hideConfig).filter(k => !!hideConfig[k]); + + if (!utils.includesAny(hidden, ['temperature', `${this.shortServiceId}:temperature`])) { + const temperatureName = utils.lookup(this.platform.config?.nameOverrides, `${this.shortServiceId}:temperature`); + this.temperature = new TemperatureSensor(platform, accessory, `${this.accessoryId}:temperature`, temperatureName || 'Temperature'); + } else { + this.temperature = new TemperatureSensor(platform, accessory, `${this.accessoryId}:temperature`, 'Temperature'); + this.temperature.removeService(); + this.temperature = undefined; + } + + if (!utils.includesAny(hidden, ['humidity', `${this.shortServiceId}:humidity`])) { + const humidityName = utils.lookup(this.platform.config?.nameOverrides, `${this.shortServiceId}:humidity`); + this.humidity = new HumiditySensor(platform, accessory, `${this.accessoryId}:humidity`, humidityName || 'Humidity'); + } else { + this.humidity = new HumiditySensor(platform, accessory, `${this.accessoryId}:humidity`, 'Humidity'); + this.humidity.removeService(); + this.humidity = undefined; + } + } + + //---------------------------------------------------------------------------- + + public update(dataReport) { + if (!utils.includesAll(Object.keys(dataReport), this.requiredData)) { + throw new Error(`Update on ${this.accessoryId} requires data ${this.requiredData}`); + } else { + this.platform.log.debug(`Updating accessory ${this.accessoryId}`); + } + + const lowBattery = dataReport['wh26batt'] === '1'; + this.updateStatusLowBattery(this.battery, lowBattery); + + this.temperature?.update( + parseFloat(dataReport['tempf']), + dataReport.dateutc, + ); + + this.humidity?.update( + parseFloat(dataReport['humidity']), + dataReport.dateutc, + ); + } +} diff --git a/src/devices/WH40.ts b/src/devices/WH40.ts index d561d09..87cbc90 100644 --- a/src/devices/WH40.ts +++ b/src/devices/WH40.ts @@ -21,7 +21,7 @@ export class WH40 extends EcowittAccessory { protected readonly platform: EcowittPlatform, protected readonly accessory: PlatformAccessory, ) { - super(platform, accessory, 'WH40', 'Rainfall Sensor'); + super(platform, accessory, 'WH40', 'WH40 Rainfall Sensor'); this.requiredData = [ 'rainbatt', 'rainratein', 'eventrainin', 'hourlyrainin', 'dailyrainin', diff --git a/src/devices/WH41.ts b/src/devices/WH41.ts index 4bb5fa1..aa1ea73 100644 --- a/src/devices/WH41.ts +++ b/src/devices/WH41.ts @@ -18,7 +18,7 @@ export class WH41 extends EcowittAccessory { protected readonly accessory: PlatformAccessory, protected channel: number, ) { - super(platform, accessory, 'WH41', 'PM2.5 Air Quality Sensor', channel); + super(platform, accessory, 'WH41', 'WH41 PM2.5 Air Quality Sensor', channel); this.requiredData = [`pm25batt${this.channel}`, `pm25_ch${this.channel}`, `pm25_avg_24h_ch${this.channel}`]; diff --git a/src/devices/WH45.ts b/src/devices/WH45.ts index a2fbfb4..c1d180d 100644 --- a/src/devices/WH45.ts +++ b/src/devices/WH45.ts @@ -28,7 +28,7 @@ export class WH45 extends EcowittAccessory { protected readonly platform: EcowittPlatform, protected readonly accessory: PlatformAccessory, ) { - super(platform, accessory, 'WH45', '5-in-1 Air Quality Sensor'); + super(platform, accessory, 'WH45', 'WH45 5-in-1 Air Quality Sensor'); this.requiredData = ['co2_batt', 'tf_co2', 'humi_co2', 'pm25_co2', 'pm25_24h_co2', 'pm10_co2', 'pm10_24h_co2', 'co2', 'co2_24h']; diff --git a/src/devices/WH46.ts b/src/devices/WH46.ts index 0526df3..d006ffa 100644 --- a/src/devices/WH46.ts +++ b/src/devices/WH46.ts @@ -29,11 +29,11 @@ export class WH46 extends EcowittAccessory { protected readonly platform: EcowittPlatform, protected readonly accessory: PlatformAccessory, ) { - super(platform, accessory, 'WH46', '7-in-1 Air Quality Sensor'); + super(platform, accessory, 'WH46', 'WH46 7-in-1 Air Quality Sensor'); this.requiredData = ['co2_batt', 'tf_co2', 'humi_co2', 'pm25_co2', 'pm25_24h_co2', 'pm10_co2', 'pm10_24h_co2', 'co2', 'co2_24h']; - this.optionalData = ['pm1_co2', 'pm1_24h_co2', 'pm4_co2', 'pm4_24h_co2']; + this.unusedData = ['pm1_co2', 'pm1_24h_co2', 'pm4_co2', 'pm4_24h_co2']; this.battery = this.addBattery('', true); diff --git a/src/devices/WH51.ts b/src/devices/WH51.ts index 90250eb..19d1d95 100644 --- a/src/devices/WH51.ts +++ b/src/devices/WH51.ts @@ -17,10 +17,10 @@ export class WH51 extends EcowittAccessory { protected readonly accessory: PlatformAccessory, protected channel: number, ) { - super(platform, accessory, 'WH51', 'Soil Moisture Sensor', channel); + super(platform, accessory, 'WH51', 'WH51 Soil Moisture Sensor', channel); this.requiredData = [`soilbatt${this.channel}`, `soilmoisture${this.channel}`]; - this.optionalData = [`soilad${this.channel}`]; + this.unusedData = [`soilad${this.channel}`]; this.battery = this.addBattery('', false); diff --git a/src/devices/WH55.ts b/src/devices/WH55.ts index 788a814..e65d5c1 100644 --- a/src/devices/WH55.ts +++ b/src/devices/WH55.ts @@ -17,7 +17,7 @@ export class WH55 extends EcowittAccessory { protected readonly accessory: PlatformAccessory, protected channel: number, ) { - super(platform, accessory, 'WH55', 'Water Leak Sensor', channel); + super(platform, accessory, 'WH55', 'WH55 Water Leak Sensor', channel); this.requiredData = [`leakbatt${this.channel}`, `leak_ch${this.channel}`]; diff --git a/src/devices/WH57.ts b/src/devices/WH57.ts index 5e2e6ae..399be83 100644 --- a/src/devices/WH57.ts +++ b/src/devices/WH57.ts @@ -16,7 +16,7 @@ export class WH57 extends EcowittAccessory { protected readonly platform: EcowittPlatform, protected readonly accessory: PlatformAccessory, ) { - super(platform, accessory, 'WH57', 'Lightning Sensor'); + super(platform, accessory, 'WH57', 'WH57 Lightning Sensor'); this.requiredData = ['wh57batt', 'lightning', 'lightning_num', 'lightning_time']; diff --git a/src/devices/WN30.ts b/src/devices/WN30.ts new file mode 100644 index 0000000..a0dc085 --- /dev/null +++ b/src/devices/WN30.ts @@ -0,0 +1,56 @@ +import { Service, PlatformAccessory } from 'homebridge'; +import { EcowittPlatform } from './../EcowittPlatform'; +import { EcowittAccessory } from './../EcowittAccessory'; +import { TemperatureSensor } from './../sensors/TemperatureSensor'; +import * as utils from './../Utils'; + +//------------------------------------------------------------------------------ + +export class WN30 extends EcowittAccessory { + static readonly properties: string[] = ['temperature']; + + protected battery: Service; + protected temperature: TemperatureSensor | undefined; + + constructor( + protected readonly platform: EcowittPlatform, + protected readonly accessory: PlatformAccessory, + protected channel: number, + ) { + super(platform, accessory, 'WN30', 'WN30 Thermo Sensor', channel); + + this.requiredData = [`batt${this.channel}`, `temp${this.channel}f`]; + + this.battery = this.addBattery('', false); + + const hideConfig = this.platform.config?.hidden || {}; + const hidden = Object.keys(hideConfig).filter(k => !!hideConfig[k]); + + if (!utils.includesAny(hidden, ['temperature', `${this.shortServiceId}:temperature`])) { + const temperatureName = utils.lookup(this.platform.config?.nameOverrides, `${this.shortServiceId}:temperature`); + this.temperature = new TemperatureSensor(platform, accessory, `${this.accessoryId}:temperature`, temperatureName || 'Temperature'); + } else { + this.temperature = new TemperatureSensor(platform, accessory, `${this.accessoryId}:temperature`, 'Temperature'); + this.temperature.removeService(); + this.temperature = undefined; + } + } + + //---------------------------------------------------------------------------- + + public update(dataReport) { + if (!utils.includesAll(Object.keys(dataReport), this.requiredData)) { + throw new Error(`Update on ${this.accessoryId} requires data ${this.requiredData}`); + } else { + this.platform.log.debug(`Updating accessory ${this.accessoryId}`); + } + + const lowBattery = dataReport[`batt${this.channel}`] === '1'; + this.updateStatusLowBattery(this.battery, lowBattery); + + this.temperature?.update( + parseFloat(dataReport[`temp${this.channel}f`]), + dataReport.dateutc, + ); + } +} diff --git a/src/devices/WH31.ts b/src/devices/WN31.ts similarity index 95% rename from src/devices/WH31.ts rename to src/devices/WN31.ts index bfa4729..f2378e7 100644 --- a/src/devices/WH31.ts +++ b/src/devices/WN31.ts @@ -7,7 +7,7 @@ import * as utils from './../Utils'; //------------------------------------------------------------------------------ -export class WH31 extends EcowittAccessory { +export class WN31 extends EcowittAccessory { static readonly properties: string[] = ['temperature', 'humidity']; protected battery: Service; @@ -19,7 +19,7 @@ export class WH31 extends EcowittAccessory { protected readonly accessory: PlatformAccessory, protected channel: number, ) { - super(platform, accessory, 'WH31', 'Thermo Hygro Sensor', channel); + super(platform, accessory, 'WN31', 'WN31 Thermo Hygro Sensor', channel); this.requiredData = [`batt${this.channel}`, `temp${this.channel}f`, `humidity${this.channel}`]; diff --git a/src/devices/WH34.ts b/src/devices/WN34.ts similarity index 95% rename from src/devices/WH34.ts rename to src/devices/WN34.ts index d3c6ea8..14e6168 100644 --- a/src/devices/WH34.ts +++ b/src/devices/WN34.ts @@ -6,7 +6,7 @@ import * as utils from './../Utils'; //------------------------------------------------------------------------------ -export class WH34 extends EcowittAccessory { +export class WN34 extends EcowittAccessory { static readonly properties: string[] = ['temperature']; protected battery: Service; @@ -17,7 +17,7 @@ export class WH34 extends EcowittAccessory { protected readonly accessory: PlatformAccessory, protected channel: number, ) { - super(platform, accessory, 'WH34', 'Thermo Sensor', channel); + super(platform, accessory, 'WN34', 'WN34 Thermo Sensor', channel); this.requiredData = [`tf_batt${this.channel}`, `tf_ch${this.channel}`]; diff --git a/src/devices/WS85.ts b/src/devices/WS85.ts index cccc495..e6d0666 100644 --- a/src/devices/WS85.ts +++ b/src/devices/WS85.ts @@ -29,15 +29,15 @@ export class WS85 extends EcowittAccessory { protected readonly platform: EcowittPlatform, protected readonly accessory: PlatformAccessory, ) { - super(platform, accessory, 'WS85', 'Weather Station'); + super(platform, accessory, 'WS85', 'WS85 3-in-1 Solar Weather Sensor'); this.requiredData = [ 'wh85batt', 'winddir', 'windspeedmph', 'windgustmph', 'maxdailygust', 'rrain_piezo', 'erain_piezo', 'hrain_piezo', 'drain_piezo', 'wrain_piezo', 'mrain_piezo', 'yrain_piezo', ]; - - this.optionalData = ['ws85cap_volt', 'ws85_ver']; + this.optionalData = ['ws85cap_volt']; + this.unusedData = ['ws85_ver']; this.battery = this.addBattery('', false); diff --git a/tests/configs/v2Full.json b/tests/configs/v2Full.json index 10e4b3b..94dbe68 100644 --- a/tests/configs/v2Full.json +++ b/tests/configs/v2Full.json @@ -7,67 +7,67 @@ }, "nameOverrides": [ { - "key": "WH31CH1", + "key": "WN31CH1", "value": "THERM/HYDRO NAME1VALUE" }, { - "key": "WH31CH2", + "key": "WN31CH2", "value": "THERM/HYDRO NAME2VALUE" }, { - "key": "WH31CH3", + "key": "WN31CH3", "value": "THERM/HYDRO NAME3VALUE" }, { - "key": "WH31CH4", + "key": "WN31CH4", "value": "THERM/HYDRO NAME4VALUE" }, { - "key": "WH31CH5", + "key": "WN31CH5", "value": "THERM/HYDRO NAME5VALUE" }, { - "key": "WH31CH6", + "key": "WN31CH6", "value": "THERM/HYDRO NAME6VALUE" }, { - "key": "WH31CH7", + "key": "WN31CH7", "value": "THERM/HYDRO NAME7VALUE" }, { - "key": "WH31CH8", + "key": "WN31CH8", "value": "THERM/HYDRO NAME8VALUE" }, { - "key": "WH34CH1", + "key": "WN34CH1", "value": "THERM NAME1VALUE" }, { - "key": "WH34CH2", + "key": "WN34CH2", "value": "THERM NAME2VALUE" }, { - "key": "WH34CH3", + "key": "WN34CH3", "value": "THERM NAME3VALUE" }, { - "key": "WH34CH4", + "key": "WN34CH4", "value": "THERM NAME4VALUE" }, { - "key": "WH34CH5", + "key": "WN34CH5", "value": "THERM NAME5VALUE" }, { - "key": "WH34CH6", + "key": "WN34CH6", "value": "THERM NAME6VALUE" }, { - "key": "WH34CH7", + "key": "WN34CH7", "value": "THERM NAME7VALUE" }, { - "key": "WH34CH8", + "key": "WN34CH8", "value": "THERM NAME8VALUE" }, { diff --git a/tests/synthetic/data/gw1000_wh26_wh31multi_wh51.json b/tests/synthetic/data/gw1000_wh51_wn31multi_wh26.json similarity index 100% rename from tests/synthetic/data/gw1000_wh26_wh31multi_wh51.json rename to tests/synthetic/data/gw1000_wh51_wn31multi_wh26.json diff --git a/tests/synthetic/data/gw1000_ws65_wh51multi_wh31multi_wh55_wh57.json b/tests/synthetic/data/gw1000_wh65_wh57_wh55_wh51multi_wn31multi.json similarity index 100% rename from tests/synthetic/data/gw1000_ws65_wh51multi_wh31multi_wh55_wh57.json rename to tests/synthetic/data/gw1000_wh65_wh57_wh55_wh51multi_wn31multi.json diff --git a/tests/synthetic/data/gw1000_wh31multi_wh26.json b/tests/synthetic/data/gw1000_wn31multi_wh26.json similarity index 100% rename from tests/synthetic/data/gw1000_wh31multi_wh26.json rename to tests/synthetic/data/gw1000_wn31multi_wh26.json diff --git a/tests/synthetic/data/gw1100_wn30multi.json b/tests/synthetic/data/gw1100_wn30multi.json new file mode 100644 index 0000000..efadcb4 --- /dev/null +++ b/tests/synthetic/data/gw1100_wn30multi.json @@ -0,0 +1,18 @@ +{ + "PASSKEY": "528C8E6CD4A3C6598999A0E9DF15AD32", + "stationtype": "GW1100B_V2.3.4", + "runtime": "5524430", + "heap": "25748", + "dateutc": "2024-09-13 23:47:04", + "tempinf": "77.90", + "humidityin": "40", + "baromrelin": "29.577", + "baromabsin": "29.577", + "temp1f": "37.58", + "temp2f": "-2.56", + "batt1": "0", + "batt2": "0", + "freq": "915M", + "model": "GW1100B", + "interval": "20" +} diff --git a/tests/synthetic/data/gw2000_ws90_wh65_wh57_wh55multi_wh45_wh41_wn35_wh34_wh31multi_wh26.json b/tests/synthetic/data/gw2000_ws90_wh65_wh57_wh51multi_wh45_wh41_wn35_wn34_wn31multi_wh26.json similarity index 100% rename from tests/synthetic/data/gw2000_ws90_wh65_wh57_wh55multi_wh45_wh41_wn35_wh34_wh31multi_wh26.json rename to tests/synthetic/data/gw2000_ws90_wh65_wh57_wh51multi_wh45_wh41_wn35_wn34_wn31multi_wh26.json diff --git a/tests/synthetic/data/hp2550_wh65_wh51multi_wh41_wh31multi_wh25.json b/tests/synthetic/data/hp2550_wh65_wh51multi_wh41_wn31multi_wh25.json similarity index 100% rename from tests/synthetic/data/hp2550_wh65_wh51multi_wh41_wh31multi_wh25.json rename to tests/synthetic/data/hp2550_wh65_wh51multi_wh41_wn31multi_wh25.json diff --git a/tests/synthetic/data/hp2561_wh65_wh31multi.json b/tests/synthetic/data/hp2561_wh65_wn31multi.json similarity index 100% rename from tests/synthetic/data/hp2561_wh65_wh31multi.json rename to tests/synthetic/data/hp2561_wh65_wn31multi.json diff --git a/tests/synthetic/data/ws3800_wh80_ws85_wh65_wh57_wh55_wh51_wh45_wh41multi_wn35_wh34multi_wh31multi_wh26_wh25.json b/tests/synthetic/data/ws3800_ws85_ws80_wh65_wh57_wh55_wh51multi_wh45_wh41multi_wn35_wn34multi_wn31multi_wn30_wh26_wh25.json similarity index 100% rename from tests/synthetic/data/ws3800_wh80_ws85_wh65_wh57_wh55_wh51_wh45_wh41multi_wn35_wh34multi_wh31multi_wh26_wh25.json rename to tests/synthetic/data/ws3800_ws85_ws80_wh65_wh57_wh55_wh51multi_wh45_wh41multi_wn35_wn34multi_wn31multi_wn30_wh26_wh25.json diff --git a/tests/synthetic/run.spec.ts b/tests/synthetic/run.spec.ts index 423de73..35cf8c4 100644 --- a/tests/synthetic/run.spec.ts +++ b/tests/synthetic/run.spec.ts @@ -7,48 +7,49 @@ let testData = null; let platform = null; describe('Platform should be configured with accessories', () => { - // NOTE: WH26 not supported - it('gw1000_wh26_wh31multi_wh51 sensors are created', (done) => { - testData = require('./data/gw1000_wh26_wh31multi_wh51.json'); + + it('gw1000_wh51_wn31multi_wh26 sensors are created', (done) => { + testData = require('./data/gw1000_wh51_wn31multi_wh26.json'); platform = createPlatform("synthetic"); platform.onDataReport(testData); - expect(platform.baseStationInfo.sensors.length).to.equal(5); + expect(platform.baseStationInfo.sensors.length).to.equal(6); expect(platform.baseStationInfo.sensors[0].type).to.equal("GW1000"); - expect(platform.baseStationInfo.sensors[1].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[2].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[3].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[4].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[1].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[2].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[3].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[4].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[5].type).to.equal("WH26"); done(); }); - // NOTE: WH26 not supported - it('gw1000_wh31multi_wh26 sensors are created', (done) => { - testData = require('./data/gw1000_wh31multi_wh26.json'); + // NOTE: WH65 not supported + it('gw1000_wh65_wh57_wh55_wh51multi_wn31multi sensors are created', (done) => { + testData = require('./data/gw1000_wh65_wh57_wh55_wh51multi_wn31multi.json'); platform = createPlatform("synthetic"); platform.onDataReport(testData); - expect(platform.baseStationInfo.sensors.length).to.equal(5) + expect(platform.baseStationInfo.sensors.length).to.equal(8); expect(platform.baseStationInfo.sensors[0].type).to.equal("GW1000"); - expect(platform.baseStationInfo.sensors[1].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[2].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[3].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[4].type).to.equal("WH31"); + expect(platform.baseStationInfo.sensors[1].type).to.equal("WH57"); + expect(platform.baseStationInfo.sensors[2].type).to.equal("WH55"); + expect(platform.baseStationInfo.sensors[3].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[4].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[5].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[6].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[7].type).to.equal("WN31"); done(); }); - // NOTE: WH65 not supported - it('gw1000_ws65_wh51multi_wh31multi_wh55_wh57 sensors are created', (done) => { - testData = require('./data/gw1000_ws65_wh51multi_wh31multi_wh55_wh57.json'); + it('gw1000_wn31multi_wh26 sensors are created', (done) => { + testData = require('./data/gw1000_wn31multi_wh26.json'); platform = createPlatform("synthetic"); platform.onDataReport(testData); - expect(platform.baseStationInfo.sensors.length).to.equal(8); + expect(platform.baseStationInfo.sensors.length).to.equal(6) expect(platform.baseStationInfo.sensors[0].type).to.equal("GW1000"); - expect(platform.baseStationInfo.sensors[1].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[2].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[3].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[4].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[5].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[6].type).to.equal("WH55"); - expect(platform.baseStationInfo.sensors[7].type).to.equal("WH57"); + expect(platform.baseStationInfo.sensors[1].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[2].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[3].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[4].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[5].type).to.equal("WH26"); done(); }); @@ -71,6 +72,7 @@ describe('Platform should be configured with accessories', () => { done(); }); + // NOTE: WH65 not supported it('gw1100_wh65_wh51 sensors are created', (done) => { testData = require('./data/gw1100_wh65_wh51.json'); @@ -82,6 +84,17 @@ describe('Platform should be configured with accessories', () => { done(); }); + it('gw1100_wn30multi sensors are created', (done) => { + testData = require('./data/gw1100_wn30multi.json'); + platform = createPlatform("synthetic"); + platform.onDataReport(testData); + expect(platform.baseStationInfo.sensors.length).to.equal(3) + expect(platform.baseStationInfo.sensors[0].type).to.equal("GW1100"); + expect(platform.baseStationInfo.sensors[1].type).to.equal("WN30"); + expect(platform.baseStationInfo.sensors[2].type).to.equal("WN30"); + done(); + }); + it('gw1200_wh46 sensors are created', (done) => { testData = require('./data/gw1200_wh46.json'); platform = createPlatform("synthetic"); @@ -126,32 +139,33 @@ describe('Platform should be configured with accessories', () => { done(); }); - // NOTE: WS90, WH65, WN35, WH26 not supported - it('gw2000_ws90_wh65_wh57_wh55multi_wh45_wh41_wn35_wh34_wh31multi_wh26 sensors are created', (done) => { - testData = require('./data/gw2000_ws90_wh65_wh57_wh55multi_wh45_wh41_wn35_wh34_wh31multi_wh26.json'); + // // NOTE: WS90, WH65, WN35 not supported + it('w2000_ws90_wh65_wh57_wh51multi_wh45_wh41_wn35_wn34_wn31multi_wh26 sensors are created', (done) => { + testData = require('./data/gw2000_ws90_wh65_wh57_wh51multi_wh45_wh41_wn35_wn34_wn31multi_wh26.json'); platform = createPlatform("synthetic"); platform.onDataReport(testData); - expect(platform.baseStationInfo.sensors.length).to.equal(20); + expect(platform.baseStationInfo.sensors.length).to.equal(21); expect(platform.baseStationInfo.sensors[0].type).to.equal("GW2000"); - expect(platform.baseStationInfo.sensors[1].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[2].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[3].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[4].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[5].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[6].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[7].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[8].type).to.equal("WH31"); + expect(platform.baseStationInfo.sensors[1].type).to.equal("WH57"); + expect(platform.baseStationInfo.sensors[2].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[3].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[4].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[5].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[6].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[7].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[8].type).to.equal("WH45"); expect(platform.baseStationInfo.sensors[9].type).to.equal("WH41"); - expect(platform.baseStationInfo.sensors[10].type).to.equal("WH45"); - expect(platform.baseStationInfo.sensors[11].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[12].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[13].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[14].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[15].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[16].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[17].type).to.equal("WH57"); - expect(platform.baseStationInfo.sensors[18].type).to.equal("WH34"); - expect(platform.baseStationInfo.sensors[19].type).to.equal("WH34"); + expect(platform.baseStationInfo.sensors[10].type).to.equal("WN34"); + expect(platform.baseStationInfo.sensors[11].type).to.equal("WN34"); + expect(platform.baseStationInfo.sensors[12].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[13].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[14].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[15].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[16].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[17].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[18].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[19].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[20].type).to.equal("WH26"); done(); }); @@ -165,33 +179,33 @@ describe('Platform should be configured with accessories', () => { done(); }); - // NOTE: WH65, WH41 not supported - it('hp2550_wh65_wh51multi_wh41_wh31multi_wh25 sensors are created', (done) => { - testData = require('./data/hp2550_wh65_wh51multi_wh41_wh31multi_wh25.json'); + // NOTE: WH65 not supported + it('hp2550_wh65_wh51multi_wh41_wn31multi_wh25 sensors are created', (done) => { + testData = require('./data/hp2550_wh65_wh51multi_wh41_wn31multi_wh25.json'); platform = createPlatform("synthetic"); platform.onDataReport(testData); expect(platform.baseStationInfo.sensors.length).to.equal(7); - expect(platform.baseStationInfo.sensors[0].type).to.equal("WH25"); - expect(platform.baseStationInfo.sensors[1].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[2].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[3].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[4].type).to.equal("WH41"); - expect(platform.baseStationInfo.sensors[5].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[6].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[0].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[1].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[2].type).to.equal("WH41"); + expect(platform.baseStationInfo.sensors[3].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[4].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[5].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[6].type).to.equal("WH25"); done(); }); // NOTE: WH65 not supported - it('hp2560_wh65_wh31multi sensors are created', (done) => { - testData = require('./data/hp2561_wh65_wh31multi.json'); + it('hp2560_wh65_wn31multi sensors are created', (done) => { + testData = require('./data/hp2561_wh65_wn31multi.json'); platform = createPlatform("synthetic"); platform.onDataReport(testData); expect(platform.baseStationInfo.sensors.length).to.equal(5); expect(platform.baseStationInfo.sensors[0].type).to.equal("HP2561"); - expect(platform.baseStationInfo.sensors[1].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[2].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[3].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[4].type).to.equal("WH31"); + expect(platform.baseStationInfo.sensors[1].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[2].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[3].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[4].type).to.equal("WN31"); done(); }); @@ -223,34 +237,35 @@ describe('Platform should be configured with accessories', () => { done(); }); - // NOTE: WS3800, WH80, WH65, WN35, WH26 not supported - it('ws3800_wh80_ws85_wh65_wh57_wh55_wh51_wh45_wh41multi_wn35_wh34multi_wh31multi_wh26_wh25 sensors are created', (done) => { - testData = require('./data/ws3800_wh80_ws85_wh65_wh57_wh55_wh51_wh45_wh41multi_wn35_wh34multi_wh31multi_wh26_wh25.json'); + // NOTE: WS3800, WH80, WH65, WN35 not supported + it('ws3800_ws85_ws80_wh65_wh57_wh55_wh51multi_wh45_wh41multi_wn35_wn34multi_wn31multi_wn30_wh26_wh25 sensors are created', (done) => { + testData = require('./data/ws3800_ws85_ws80_wh65_wh57_wh55_wh51multi_wh45_wh41multi_wn35_wn34multi_wn31multi_wn30_wh26_wh25.json'); platform = createPlatform("synthetic"); platform.onDataReport(testData); - expect(platform.baseStationInfo.sensors.length).to.equal(22); + expect(platform.baseStationInfo.sensors.length).to.equal(23); expect(platform.baseStationInfo.sensors[0].type).to.equal("WS85"); - expect(platform.baseStationInfo.sensors[1].type).to.equal("WH25"); - expect(platform.baseStationInfo.sensors[2].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[3].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[4].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[5].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[6].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[7].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[8].type).to.equal("WH31"); - expect(platform.baseStationInfo.sensors[9].type).to.equal("WH41"); + expect(platform.baseStationInfo.sensors[1].type).to.equal("WH57"); + expect(platform.baseStationInfo.sensors[2].type).to.equal("WH55"); + expect(platform.baseStationInfo.sensors[3].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[4].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[5].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[6].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[7].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[8].type).to.equal("WH51"); + expect(platform.baseStationInfo.sensors[9].type).to.equal("WH45"); expect(platform.baseStationInfo.sensors[10].type).to.equal("WH41"); - expect(platform.baseStationInfo.sensors[11].type).to.equal("WH45"); - expect(platform.baseStationInfo.sensors[12].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[13].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[14].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[15].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[16].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[17].type).to.equal("WH51"); - expect(platform.baseStationInfo.sensors[18].type).to.equal("WH55"); - expect(platform.baseStationInfo.sensors[19].type).to.equal("WH57"); - expect(platform.baseStationInfo.sensors[20].type).to.equal("WH34"); - expect(platform.baseStationInfo.sensors[21].type).to.equal("WH34"); + expect(platform.baseStationInfo.sensors[11].type).to.equal("WH41"); + expect(platform.baseStationInfo.sensors[12].type).to.equal("WN34"); + expect(platform.baseStationInfo.sensors[13].type).to.equal("WN34"); + expect(platform.baseStationInfo.sensors[14].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[15].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[16].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[17].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[18].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[19].type).to.equal("WN31"); + expect(platform.baseStationInfo.sensors[20].type).to.equal("WN30"); + expect(platform.baseStationInfo.sensors[21].type).to.equal("WH26"); + expect(platform.baseStationInfo.sensors[22].type).to.equal("WH25"); done(); }); }); diff --git a/tests/unit/devices/WH26.spec.ts b/tests/unit/devices/WH26.spec.ts new file mode 100644 index 0000000..328dd59 --- /dev/null +++ b/tests/unit/devices/WH26.spec.ts @@ -0,0 +1,87 @@ +import { expect } from 'chai'; +import { WH26 } from './../../../src/devices/WH26'; +import { createPlatform, api } from './../../driver'; + +//------------------------------------------------------------------------------ + +let platform = null; +let accessory = null; +let sensor = null; + +const dataReport = { + "dateutc": "2024-07-24 19:04:22", + "tempf": "80.78", + "humidity": "49", + "wh26batt": "0", +}; + +const configs = ["v1Default", "v1Full", "v2Default", "v2Full"]; + +configs.forEach(config => { + describe(`WH26 device should be configured ${config}`, () => { + before('Initialize device', () => { + platform = createPlatform(config); + accessory = new api.platformAccessory('Accessory', "5746853e-4fee-4e47-97dd-53065ef1de03") + device = new WH26(platform, accessory); + }); + + beforeEach('Reset config', () => { + platform.config.nameOverrides = []; + platform.config.hidden = {}; + }); + + it('Services are created', (done) => { + expect(device.battery).to.not.be.undefined; + expect(device.temperature).to.not.be.undefined; + expect(device.humidity).to.not.be.undefined; + expect(device.battery.displayName).to.equal(''); + expect(device.temperature.service.displayName).to.equal("Temperature"); + expect(device.humidity.service.displayName).to.equal("Humidity"); + done(); + }); + + it('Update is called successfully', (done) => { + device.update(dataReport); + + expect(device.battery.characteristics[0].value).to.equal(0); // low batt + expect(device.humidity.service.characteristics[0].value).to.equal("Humidity 49 %") + expect(device.temperature.service.characteristics[0].value).to.equal("Temperature 80.60°F") + done(); + }); + + it('Services are created with name overrides', (done) => { + platform.config.nameOverrides[0] = {"key": "WH26:temperature", "value": "Test Temperature Name"}; + platform.config.nameOverrides[1] = {"key": "WH26:humidity", "value": "Test Humidity Name"}; + + device = new WH26(platform, accessory); + + expect(device.temperature).to.not.be.undefined; + expect(device.humidity).to.not.be.undefined; + expect(device.temperature.service.characteristics[0].value).to.equal("Test Temperature Name"); + expect(device.humidity.service.characteristics[0].value).to.equal("Test Humidity Name"); + done(); + }); + + it('Services are not created when hidden with general override', (done) => { + platform.config.hidden["temperature"] = true; + platform.config.hidden["humidity"] = true; + + device = new WH26(platform, accessory); + + expect(device.temperature).to.be.undefined; + expect(device.humidity).to.be.undefined; + done(); + }); + + it('Services are not created when hidden with device-specific override', (done) => { + platform.config.hidden["WH26:temperature"] = true; + platform.config.hidden["WH26:humidity"] = true; + + device = new WH26(platform, accessory); + + expect(device.temperature).to.be.undefined; + expect(device.humidity).to.be.undefined; + done(); + }); + }); +}); diff --git a/tests/unit/devices/WN30.spec.ts b/tests/unit/devices/WN30.spec.ts new file mode 100644 index 0000000..579c2d3 --- /dev/null +++ b/tests/unit/devices/WN30.spec.ts @@ -0,0 +1,76 @@ +import { expect } from 'chai'; +import { WN30 } from './../../../src/devices/WN30'; +import { createPlatform, api } from './../../driver'; + +//------------------------------------------------------------------------------ + +let platform = null; +let accessory = null; +let sensor = null; + +const dataReport = { + "dateutc": "2024-07-24 19:04:22", + "temp1f": "80.78", + "batt1": "1" +}; + +const configs = ["v1Default", "v1Full", "v2Default", "v2Full"]; + +configs.forEach(config => { + describe(`WN30 device should be configured ${config}`, () => { + before('Initialize device', () => { + platform = createPlatform(config); + accessory = new api.platformAccessory('Accessory', "5746853e-4fee-4e47-97dd-53065ef1de03") + device = new WN30(platform, accessory, 1); + }); + + beforeEach('Reset config', () => { + platform.config.nameOverrides = []; + platform.config.hidden = {}; + }); + + it('Services are created', (done) => { + expect(device.battery).to.not.be.undefined; + expect(device.temperature).to.not.be.undefined; + expect(device.battery.displayName).to.equal(''); + expect(device.temperature.service.displayName).to.equal("Temperature"); + done(); + }); + + it('Update is called successfully', (done) => { + device.update(dataReport); + + expect(device.battery.characteristics[0].value).to.equal(1); // low batt + expect(device.temperature.service.characteristics[0].value).to.equal("Temperature 80.60°F") + done(); + }); + + it('Services are created with name overrides', (done) => { + platform.config.nameOverrides[0] = {"key": "WN30CH1:temperature", "value": "Test Temperature Name"}; + + device = new WN30(platform, accessory, 1); + + expect(device.temperature).to.not.be.undefined; + expect(device.temperature.service.characteristics[0].value).to.equal("Test Temperature Name"); + done(); + }); + + it('Services are not created when hidden with general override', (done) => { + platform.config.hidden["temperature"] = true; + + device = new WN30(platform, accessory, 1); + + expect(device.temperature).to.be.undefined; + done(); + }); + + it('Services are not created when hidden with device-specific override', (done) => { + platform.config.hidden["WN30CH1:temperature"] = true; + + device = new WN30(platform, accessory, 1); + + expect(device.temperature).to.be.undefined; + done(); + }); + }); +}); diff --git a/tests/unit/devices/WH31.spec.ts b/tests/unit/devices/WN31.spec.ts similarity index 82% rename from tests/unit/devices/WH31.spec.ts rename to tests/unit/devices/WN31.spec.ts index a978737..a2e1423 100644 --- a/tests/unit/devices/WH31.spec.ts +++ b/tests/unit/devices/WN31.spec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { WH31 } from './../../../src/devices/WH31'; +import { WN31 } from './../../../src/devices/WN31'; import { createPlatform, api } from './../../driver'; //------------------------------------------------------------------------------ @@ -18,11 +18,11 @@ const dataReport = { const configs = ["v1Default", "v1Full", "v2Default", "v2Full"]; configs.forEach(config => { - describe(`WH31 device should be configured ${config}`, () => { + describe(`WN31 device should be configured ${config}`, () => { before('Initialize device', () => { platform = createPlatform(config); accessory = new api.platformAccessory('Accessory', "5746853e-4fee-4e47-97dd-53065ef1de03") - device = new WH31(platform, accessory, 1); + device = new WN31(platform, accessory, 1); }); beforeEach('Reset config', () => { @@ -50,10 +50,10 @@ configs.forEach(config => { }); it('Services are created with name overrides', (done) => { - platform.config.nameOverrides[0] = {"key": "WH31CH1:temperature", "value": "Test Temperature Name"}; - platform.config.nameOverrides[1] = {"key": "WH31CH1:humidity", "value": "Test Humidity Name"}; + platform.config.nameOverrides[0] = {"key": "WN31CH1:temperature", "value": "Test Temperature Name"}; + platform.config.nameOverrides[1] = {"key": "WN31CH1:humidity", "value": "Test Humidity Name"}; - device = new WH31(platform, accessory, 1); + device = new WN31(platform, accessory, 1); expect(device.temperature).to.not.be.undefined; expect(device.humidity).to.not.be.undefined; @@ -66,7 +66,7 @@ configs.forEach(config => { platform.config.hidden["temperature"] = true; platform.config.hidden["humidity"] = true; - device = new WH31(platform, accessory, 1); + device = new WN31(platform, accessory, 1); expect(device.temperature).to.be.undefined; expect(device.humidity).to.be.undefined; @@ -74,10 +74,10 @@ configs.forEach(config => { }); it('Services are not created when hidden with device-specific override', (done) => { - platform.config.hidden["WH31CH1:temperature"] = true; - platform.config.hidden["WH31CH1:humidity"] = true; + platform.config.hidden["WN31CH1:temperature"] = true; + platform.config.hidden["WN31CH1:humidity"] = true; - device = new WH31(platform, accessory, 1); + device = new WN31(platform, accessory, 1); expect(device.temperature).to.be.undefined; expect(device.humidity).to.be.undefined; diff --git a/tests/unit/devices/WH34.spec.ts b/tests/unit/devices/WN34.spec.ts similarity index 82% rename from tests/unit/devices/WH34.spec.ts rename to tests/unit/devices/WN34.spec.ts index bb193ed..06f2352 100644 --- a/tests/unit/devices/WH34.spec.ts +++ b/tests/unit/devices/WN34.spec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { WH34 } from './../../../src/devices/WH34'; +import { WN34 } from './../../../src/devices/WN34'; import { createPlatform, api } from './../../driver'; //------------------------------------------------------------------------------ @@ -17,11 +17,11 @@ const dataReport = { const configs = ["v1Default", "v1Full", "v2Default", "v2Full"]; configs.forEach(config => { - describe(`WH34 device should be configured ${config}`, () => { + describe(`WN34 device should be configured ${config}`, () => { before('Initialize device', () => { platform = createPlatform(config); accessory = new api.platformAccessory('Accessory', "5746853e-4fee-4e47-97dd-53065ef1de03") - device = new WH34(platform, accessory, 1); + device = new WN34(platform, accessory, 1); }); beforeEach('Reset config', () => { @@ -47,9 +47,9 @@ configs.forEach(config => { }); it('Services are created with name overrides', (done) => { - platform.config.nameOverrides[0] = {"key": "WH34CH1:temperature", "value": "Test Temperature Name"}; + platform.config.nameOverrides[0] = {"key": "WN34CH1:temperature", "value": "Test Temperature Name"}; - device = new WH34(platform, accessory, 1); + device = new WN34(platform, accessory, 1); expect(device.temperature).to.not.be.undefined; expect(device.temperature.service.characteristics[0].value).to.equal("Test Temperature Name"); @@ -59,16 +59,16 @@ configs.forEach(config => { it('Services are not created when hidden with general override', (done) => { platform.config.hidden["temperature"] = true; - device = new WH34(platform, accessory, 1); + device = new WN34(platform, accessory, 1); expect(device.temperature).to.be.undefined; done(); }); it('Services are not created when hidden with device-specific override', (done) => { - platform.config.hidden["WH34CH1:temperature"] = true; + platform.config.hidden["WN34CH1:temperature"] = true; - device = new WH34(platform, accessory, 1); + device = new WN34(platform, accessory, 1); expect(device.temperature).to.be.undefined; done();