homebridge-ecowitt-weather-sensors
Version:
Homebridge support for your Fine Offset weather station (Ecowitt, Ambient, Froggit, GoGen, and more)
827 lines • 29.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.v2ConfigKeys = exports.v1ConfigKeys = exports.UNKNOWN = exports.UNDERGROUND = exports.AMBIENT = exports.ECOWITT = exports.CHAR_INTENSITY_UUID = exports.CHAR_INTENSITY_NAME = exports.CHAR_TIME_UUID = exports.CHAR_TIME_NAME = exports.CHAR_VALUE_UUID = exports.CHAR_VALUE_NAME = exports.MIGRATION_GUIDE_LINK = exports.GATEWAY_SETUP_LINK = exports.FEATURE_REQ_LINK = exports.BUG_REPORT_LINK = void 0;
exports.boundRange = boundRange;
exports.truthy = truthy;
exports.falsy = falsy;
exports.lookup = lookup;
exports.includesAll = includesAll;
exports.includesAny = includesAny;
exports.toCelcius = toCelcius;
exports.toFahrenheit = toFahrenheit;
exports.tohPa = tohPa;
exports.toMile = toMile;
exports.toKts = toKts;
exports.toKph = toKph;
exports.toMps = toMps;
exports.toBeafort = toBeafort;
exports.toWindSector = toWindSector;
exports.toRainIntensity = toRainIntensity;
exports.toAirQuality = toAirQuality;
exports.toUVRiskLevel = toUVRiskLevel;
exports.v1ConfigTest = v1ConfigTest;
exports.dataReportTranslator = dataReportTranslator;
exports.v27ConfigRemapper = v27ConfigRemapper;
exports.v211ConfigRemapper = v211ConfigRemapper;
exports.v1ConfigRemapper = v1ConfigRemapper;
// eslint-disable-next-line @typescript-eslint/no-var-requires
const merge = require('deepmerge');
// external help links
exports.BUG_REPORT_LINK = 'https://bit.ly/3yklrWZ';
exports.FEATURE_REQ_LINK = 'https://bit.ly/4fzeAtj';
exports.GATEWAY_SETUP_LINK = 'https://bit.ly/3YGnYVU';
exports.MIGRATION_GUIDE_LINK = 'https://bit.ly/4d4K8oh';
//------------------------------------------------------------------------------
// custom characteristics name and uuid
exports.CHAR_VALUE_NAME = 'Value';
exports.CHAR_VALUE_UUID = 'dc87b6c3-84ab-41a6-ae13-69fea759ee39';
exports.CHAR_TIME_NAME = 'Last Updated';
exports.CHAR_TIME_UUID = 'd1130039-59df-4b0e-a8ba-8527c854e3fa';
exports.CHAR_INTENSITY_NAME = 'Intensity';
exports.CHAR_INTENSITY_UUID = 'fdd76937-37bb-49f2-b1a0-0705fe548782';
//------------------------------------------------------------------------------
// protocol types
exports.ECOWITT = 'Ecowitt';
exports.AMBIENT = 'Ambient';
exports.UNDERGROUND = 'Underground';
//------------------------------------------------------------------------------
exports.UNKNOWN = 'Unknown';
//------------------------------------------------------------------------------
// config keys
exports.v1ConfigKeys = ['mac', 'port', 'path', 'unregister', 'ws', 'thbin', 'th', 'tf', 'soil', 'leak', 'pm25', 'lightning'];
exports.v2ConfigKeys = ['baseStation', 'nameOverrides', 'additional', 'thresholds', 'hidden', 'units'];
//------------------------------------------------------------------------------
function boundRange(percent, lowerBound = 0, upperBound = 100) {
return Math.max(lowerBound, Math.min(upperBound, percent));
}
//------------------------------------------------------------------------------
function truthy(val) {
if (typeof val === 'undefined') {
return false;
}
return String(val).toLowerCase() === 'true' || String(val).toLowerCase() === '1' || String(val).toLowerCase() === 'enabled';
}
//------------------------------------------------------------------------------
function falsy(val) {
if (typeof val === 'undefined') {
return true;
}
return String(val).toLowerCase() === 'false' || String(val).toLowerCase() === '0' || String(val).toLowerCase() === 'disabled';
}
//------------------------------------------------------------------------------
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function lookup(object, key) {
if (typeof object === 'undefined' || typeof key === 'undefined') {
return undefined;
}
let obj = {};
if (Array.isArray(object)) {
object.forEach(x => obj[x.key] = x.value);
}
else {
obj = object;
}
const lowKey = key.toLowerCase();
const index = Object.keys(obj).find(k => k.toLowerCase() === lowKey);
if (typeof index === 'undefined') {
return undefined;
}
else {
return obj[index];
}
}
//------------------------------------------------------------------------------
function includesAll(arr, values) {
const lowArr = arr.map(name => name.toLowerCase());
const lowVal = values.map(name => name.toLowerCase());
return lowVal.every(k => lowArr.includes(k));
}
//------------------------------------------------------------------------------
function includesAny(arr, values) {
const lowArr = arr.map(name => name.toLowerCase());
const lowVal = values.map(name => name.toLowerCase());
return lowVal.some(k => lowArr.includes(k));
}
//------------------------------------------------------------------------------
function toCelcius(fahrenheit) {
return ((parseFloat(fahrenheit) - 32.0) * 5.0) / 9.0;
}
//------------------------------------------------------------------------------
function toFahrenheit(celcius) {
return ((9.0 / 5.0) * parseFloat(celcius)) + 32.0;
}
//------------------------------------------------------------------------------
function tohPa(inHg) {
return parseFloat(inHg) * 33.8638;
}
//------------------------------------------------------------------------------
function toMile(km) {
return parseFloat(km) * 0.6214;
}
//------------------------------------------------------------------------------
const kWindSectors = [
'N',
'NNE',
'NE',
'ENE',
'E',
'ESE',
'SE',
'SSE',
'S',
'SSW',
'SW',
'WSW',
'W',
'WNW',
'NW',
'NNW',
];
// upper limits for each scale threshold
const kBeaufortScale = [
{
force: 0,
description: 'Calm',
kts: 1,
mph: 1,
kph: 2,
mps: 0.5,
},
{
force: 1,
description: 'Light Air',
kts: 3,
mph: 3,
kph: 5,
mps: 1.5,
},
{
force: 2,
description: 'Light Breeze',
kts: 6,
mph: 7,
kph: 11,
mps: 3.3,
},
{
force: 3,
description: 'Gentle Breeze',
kts: 10,
mph: 12,
kph: 19,
mps: 5.5,
},
{
force: 4,
description: 'Moderate Breeze',
kts: 16,
mph: 18,
kph: 28,
mps: 7.9,
},
{
force: 5,
description: 'Fresh Breeze',
kts: 21,
mph: 24,
kph: 38,
mps: 10.7,
},
{
force: 6,
description: 'Strong Breeze',
kts: 27,
mph: 31,
kph: 49,
mps: 13.8,
},
{
force: 7,
description: 'Near Gale',
kts: 33,
mph: 38,
kph: 61,
mps: 17.1,
},
{
force: 8,
description: 'Gale',
kts: 40,
mph: 46,
kph: 74,
mps: 20.7,
},
{
force: 9,
description: 'Strong Gale',
kts: 47,
mph: 54,
kph: 88,
mps: 24.4,
},
{
force: 10,
description: 'Storm',
kts: 55,
mph: 63,
kph: 102,
mps: 28.4,
},
{
force: 11,
description: 'Violent Storm',
kts: 63,
mph: 72,
kph: 117,
mps: 32.6,
},
{
force: 12,
description: 'Hurricane',
kts: Number.POSITIVE_INFINITY,
mph: Number.POSITIVE_INFINITY,
kph: Number.POSITIVE_INFINITY,
mps: Number.POSITIVE_INFINITY,
},
];
//------------------------------------------------------------------------------
function toKts(mph) {
return parseFloat(mph) * 0.86897624;
}
//------------------------------------------------------------------------------
function toKph(mph) {
return parseFloat(mph) * 1.609344;
}
//------------------------------------------------------------------------------
function toMps(mph) {
return parseFloat(mph) * 0.44704;
}
//------------------------------------------------------------------------------
function toBeafort(mph) {
let beaufort = kBeaufortScale.find((scale) => mph <= scale.mph);
if (!beaufort) {
beaufort = kBeaufortScale[kBeaufortScale.length - 1];
}
return beaufort;
}
//------------------------------------------------------------------------------
function toWindSector(degrees) {
if (typeof degrees !== 'number' || isNaN(degrees)) {
return 'NaN';
}
const index = Math.round((degrees % 360) / 24.0);
let sectorName = kWindSectors[index];
if (!sectorName) {
sectorName = 'None';
}
return sectorName;
}
//------------------------------------------------------------------------------
// classifcations from MANOBS (Manual of Surface Weather Observations)
function toRainIntensity(ratemm) {
if (ratemm <= 0) {
return 'None';
}
else if (ratemm <= 2.5) {
return 'Light';
}
else if (ratemm <= 7.5) {
return 'Moderate';
}
else if (ratemm <= 50.0) {
return 'Heavy';
}
else {
return 'Violent';
}
}
// european air quality index - https://ecmwf-projects.github.io/copernicus-training-cams/proc-aq-index.html
const airQualityScale = [
{
scale: 1,
description: 'Excellent',
pm10: 20,
pm25: 10,
},
{
scale: 2,
description: 'Good',
pm10: 40,
pm25: 20,
},
{
scale: 3,
description: 'Fair',
pm10: 50,
pm25: 25,
},
{
scale: 4,
description: 'Inferior',
pm10: 100,
pm25: 50,
},
{
scale: 5,
description: 'Poor',
pm10: Number.POSITIVE_INFINITY,
pm25: Number.POSITIVE_INFINITY,
},
];
//------------------------------------------------------------------------------
function toAirQuality(pm, pmType) {
let airQuality = airQualityScale.find((scale) => pm <= scale[pmType]);
if (!airQuality) {
airQuality = airQualityScale[airQualityScale.length - 1];
}
return airQuality;
}
// https://en.wikipedia.org/wiki/Ultraviolet_index
const uvIndexScale = [
{
level: 2,
risk: 'Low',
},
{
level: 5,
risk: 'Moderate',
},
{
level: 7,
risk: 'High',
},
{
level: 10,
risk: 'Very High',
},
{
level: Number.POSITIVE_INFINITY,
risk: 'Extreme',
},
];
//------------------------------------------------------------------------------
function toUVRiskLevel(index) {
let uvRating = uvIndexScale.find((scale) => index <= scale.level);
if (!uvRating) {
uvRating = uvIndexScale[uvIndexScale.length - 1];
}
return uvRating;
}
//------------------------------------------------------------------------------
function v1ConfigTest(v1Config) {
if (includesAny(Object.keys(v1Config), exports.v1ConfigKeys)) {
return true;
}
return false;
}
//------------------------------------------------------------------------------
// convert ambient data report to ecowitt data report
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function dataReportTranslator(ambDataReport) {
const ecoDataReport = JSON.parse(JSON.stringify(ambDataReport));
let key, value;
const wh65Prop = ['tempf', 'humidity', 'solarradiation', 'uv', 'winddir', 'windspeedmph',
'windgustmph', 'maxdailygust', 'eventrainin', 'hourlyrainin', 'dailyrainin',
'weeklyrainin', 'monthlyrainin']; // omit 'yearlyrainin'
const wh67Prop = ['tempf', 'humidity', 'winddir', 'windspeedmph',
'windgustmph', 'maxdailygust', 'eventrainin', 'hourlyrainin', 'dailyrainin',
'weeklyrainin', 'monthlyrainin']; // omit 'yearlyrainin'
const wh80Prop = ['tempf', 'humidity', 'solarradiation', 'uv', 'winddir', 'windspeedmph',
'windgustmph', 'maxdailygust'];
const wh90Prop = ['tempf', 'humidity', 'solarradiation', 'uv', 'winddir', 'windspeedmph',
'windgustmph', 'maxdailygust', 'rrain_piezo', 'erain_piezo', 'hrain_piezo',
'drain_piezo', 'wrain_piezo', 'mrain_piezo', 'yrain_piezo'];
for (const entry of Object.entries(ambDataReport)) {
key = entry[0];
value = entry[1];
// battout maps to the sensor array battery which depends on the product bundle
if (key === 'battout') {
if (ambDataReport.stationtype === undefined) {
ecoDataReport.stationtype = 'AMBWeather';
}
// wh40 and wh80/wh90 can look like wh65/wh67
const wh40Exists = ambDataReport.battrain !== undefined;
if (!wh40Exists && includesAll(Object.keys(ecoDataReport), wh65Prop)) { // must be WS2000, or WS2902
ecoDataReport.wh65batt = value; // wh65 default
if (ambDataReport.battin !== undefined) { // WS2000 comes with WH25 for indoor
ecoDataReport.model = 'HP2550'; // WS2000
}
else {
ecoDataReport.model = 'WS2900'; // WS2902
}
delete ecoDataReport.battout;
continue;
}
if (!wh40Exists && includesAll(Object.keys(ecoDataReport), wh67Prop)) { // must be WS1965
ecoDataReport.wh65batt = value; // wh67 default
ecoDataReport.model = 'WN1920';
delete ecoDataReport.battout;
continue;
}
if (includesAll(Object.keys(ecoDataReport), wh90Prop)) { // must be WS4000
ecoDataReport.wh90batt = value; // wh90 default
ecoDataReport.model = 'HP2550';
delete ecoDataReport.battout;
continue;
}
if (includesAll(Object.keys(ecoDataReport), wh80Prop)) { // must be WS5000
ecoDataReport.wh80batt = value; // wh80 default
ecoDataReport.model = 'HP2550';
delete ecoDataReport.battout;
continue;
}
// if no sensor array matched, then assume outdoor TH sensor
if (ecoDataReport.battout !== undefined) {
delete ecoDataReport.battout;
ecoDataReport.wh26batt = value;
ecoDataReport.model = exports.UNKNOWN;
}
}
// indoor temp/humdity sensor - wh25
if (key === 'battin') {
delete ecoDataReport.battin;
ecoDataReport.wh25batt = value;
}
// rain detector - wh40
if (key === 'battrain') {
delete ecoDataReport.battrain;
ecoDataReport.wh40batt = value;
}
// pm25 outdoor sensor - wh41, ch1
if (key === 'batt_25') {
delete ecoDataReport[key];
ecoDataReport.pm25batt1 = value;
}
if (key === 'pm25') {
delete ecoDataReport[key];
ecoDataReport.pm25_ch1 = value;
}
if (key === 'pm25_24hr') {
delete ecoDataReport[key];
ecoDataReport.pm25_avg_24h_ch1 = value;
}
// pm25 indoor sensor - wh43, ch2
if (key === 'batt_25in') {
delete ecoDataReport[key];
ecoDataReport.pm25batt2 = value;
}
if (key === 'pm25_in') {
delete ecoDataReport[key];
ecoDataReport.pm25_ch2 = value;
}
if (key === 'pm25_in_24hr') {
delete ecoDataReport[key];
ecoDataReport.pm25_avg_24h_ch2 = value;
}
// air quality sensor - wh45
if (key.startsWith('batt_co2')) {
delete ecoDataReport[key];
ecoDataReport[key.replace('batt_co2', 'co2_batt')] = value;
}
if (key === 'pm_in_temp_aqin') {
delete ecoDataReport[key];
ecoDataReport.tf_co2 = value;
}
if (key === 'pm_in_humidity_aqin') {
delete ecoDataReport[key];
ecoDataReport.humi_co2 = value;
}
if (key === 'pm10_in_aqin') {
delete ecoDataReport[key];
ecoDataReport.pm10_co2 = value;
}
if (key === 'pm10_in_24h_aqin') {
delete ecoDataReport[key];
ecoDataReport.pm10_24h_co2 = value;
}
if (key === 'pm25_in_aqin') {
delete ecoDataReport[key];
ecoDataReport.pm25_co2 = value;
}
if (key === 'pm25_in_24h_aqin') {
delete ecoDataReport[key];
ecoDataReport.pm25_24h_co2 = value;
}
if (key === 'co2_in_aqin') {
delete ecoDataReport[key];
ecoDataReport.co2 = value;
}
if (key === 'co2_in_24h_aqin') {
delete ecoDataReport[key];
ecoDataReport.co2_24h = value;
}
// soil moisture sensor - wh51
if (key.startsWith('battsm')) {
delete ecoDataReport[key];
ecoDataReport[key.replace('battsm', 'soilbatt')] = value;
}
if (key.startsWith('soilhum')) {
delete ecoDataReport[key];
ecoDataReport[key.replace('soilhum', 'soilmoisture')] = value;
}
// leak sensor - wh55
if (key.startsWith('batleak')) {
delete ecoDataReport[key];
ecoDataReport[key.replace('batleak', 'leakbatt')] = value;
}
if (key.startsWith('leak')) {
delete ecoDataReport[key];
ecoDataReport[key.replace('leak', 'leak_ch')] = value;
}
// lightning sensor - wh57
if (key === 'batt_lightning') {
delete ecoDataReport.batt_lightning;
ecoDataReport.wh57batt = value;
}
if (key === 'lightning_distance') {
delete ecoDataReport.lightning_distance;
ecoDataReport.lightning = value;
}
if (key === 'lightning_day') {
delete ecoDataReport.lightning_day;
ecoDataReport.lightning_num = value;
}
if (key === 'lightning_hour' && ambDataReport.lightning_day === undefined) {
delete ecoDataReport.lightning_hour;
ecoDataReport.lightning_num = value;
}
// leaf wetness sensor - wn35
if (key.startsWith('batt_lw')) {
delete ecoDataReport[key];
ecoDataReport[key.replace('batt_lw', 'leaf_batt')] = value;
}
if (key.startsWith('leafwetness')) {
delete ecoDataReport[key];
ecoDataReport[key.replace('leafwetness', 'leafwetness_ch')] = value;
}
}
// set model if not detected
if (ecoDataReport.model === undefined) {
ecoDataReport.model = exports.UNKNOWN;
}
return ecoDataReport;
}
//------------------------------------------------------------------------------
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function v27ConfigRemapper(config) {
const remappedConfig = JSON.parse(JSON.stringify(config));
let key, value;
// hidden
if (config.hidden !== undefined) {
for (const entry of Object.entries(config.hidden)) {
key = entry[0];
value = entry[1];
if (key === 'GW1000' || key === 'GW2000' || key === 'GW3000' || key === 'HP2560') {
delete remappedConfig.hidden[key];
remappedConfig.hidden.BASE = value;
}
}
}
// nameoverride
if (config.nameOverrides !== undefined) {
for (let i = 0; i < config.nameOverrides.length; i++) {
key = config.nameOverrides[i].key.split(':');
value = config.nameOverrides[i].value;
if (key[0] === 'GW1000' || key[0] === 'GW2000' || key[0] === 'GW3000' || key[0] === 'HP2560') {
remappedConfig.nameOverrides[i].key = `BASE:${key[1]}`;
}
}
}
return remappedConfig;
}
//------------------------------------------------------------------------------
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function v211ConfigRemapper(config) {
const remappedConfig = JSON.parse(JSON.stringify(config));
let key, value;
// advanced settings, convert true/false strings to enabled/disabled
if (config.additional !== undefined) {
for (const entry of Object.entries(config.additional)) {
key = entry[0];
value = entry[1];
if (value === 'true') {
remappedConfig.additional[key] = 'enabled';
}
if (value === 'false') {
remappedConfig.additional[key] = 'disabled';
}
}
}
// units, distance converted to lightningDistance, and add laserDistance
if (config.units !== undefined) {
let laserDistance = 'in';
if (config.units.distance !== undefined) {
delete remappedConfig.units.distance;
remappedConfig.units.lightningDistance = config.units.distance;
if (config.units.distance === 'km') { // set to metric if lightningDistance in metrics
laserDistance = 'mm';
}
}
if (config.units.laserDistance === undefined) {
remappedConfig.units.laserDistance = laserDistance;
}
}
return remappedConfig;
}
//------------------------------------------------------------------------------
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function v1ConfigRemapper(v1Config) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const v2Config = {
'baseStation': {},
'nameOverrides': [],
'additional': {},
'thresholds': {},
'hidden': {},
'customHidden': [],
'units': {},
'platform': 'Ecowitt',
};
// base station
if (v1Config?.mac) {
v2Config.baseStation.mac = v1Config.mac;
}
if (v1Config?.port) {
v2Config.baseStation.port = v1Config.port;
}
if (v1Config?.path) {
v2Config.baseStation.path = v1Config.path;
}
// units
if (v1Config?.ws?.wind?.units) {
v2Config.units.wind = v1Config?.ws?.wind?.units;
}
if (v1Config?.ws?.rain?.units) {
v2Config.units.rain = v1Config?.ws?.rain?.units;
}
if (v1Config?.lightning?.units) {
v2Config.units.lightningDistance = v1Config?.lightning?.units;
}
v2Config.units.temperature = 'fh';
// hidden
if (truthy(v1Config?.thbin?.hide)) {
v2Config.hidden['GW1000'] = true;
v2Config.hidden['GW2000'] = true;
v2Config.hidden['HP2560'] = true;
}
if (truthy(v1Config?.ws?.hide)) {
v2Config.hidden['WS85'] = true;
v2Config.hidden['WH65'] = true;
}
if (truthy(v1Config?.th?.hide)) {
v2Config.hidden['WN31'] = true;
}
if (truthy(v1Config?.tf?.hide)) {
v2Config.hidden['WN34'] = true;
}
if (truthy(v1Config?.soil?.hide)) {
v2Config.hidden['WH51'] = true;
}
if (truthy(v1Config?.leak?.hide)) {
v2Config.hidden['WH55'] = true;
}
if (truthy(v1Config?.pm25?.hide)) {
v2Config.hidden['WH41'] = true;
}
if (truthy(v1Config?.lightning?.hide)) {
v2Config.hidden['WH57'] = true;
}
if (truthy(v1Config?.ws?.uv?.hide)) {
v2Config.hidden.uvIndex = true;
}
if (truthy(v1Config?.ws?.solarradiation?.hide)) {
v2Config.hidden.solarRadiation = true;
}
const rainHide = v1Config?.ws?.rain?.hide;
if (Array.isArray(rainHide)) {
if (rainHide.includes('Rate')) {
v2Config.hidden.rainRate = true;
}
if (rainHide.includes('Event')) {
v2Config.hidden.rainEventTotal = true;
}
if (rainHide.includes('Hourly')) {
v2Config.hidden.rainHourlyTotal = true;
}
if (rainHide.includes('Daily')) {
v2Config.hidden.rainDailyTotal = true;
}
if (rainHide.includes('Weekly')) {
v2Config.hidden.rainWeeklyTotal = true;
}
if (rainHide.includes('Monthly')) {
v2Config.hidden.rainMonthlyTotal = true;
}
if (rainHide.includes('Yearly')) {
v2Config.hidden.rainYearlyTotal = true;
}
}
const windHide = v1Config?.ws?.wind?.hide;
if (Array.isArray(windHide)) {
if (windHide.includes('Direction')) {
v2Config.hidden.windDirection = true;
}
if (windHide.includes('Speed')) {
v2Config.hidden.windSpeed = true;
}
if (windHide.includes('Gust')) {
v2Config.hidden.windGustSpeed = true;
}
if (windHide.includes('MaxDailyGust')) {
v2Config.hidden.windMaxDailySpeed = true;
}
}
// thresholds
if (v1Config?.ws?.uv?.threshold) {
v2Config.thresholds.uvIndex = v1Config?.ws?.uv?.threshold;
}
const windUnits = v2Config.units.wind;
if (v1Config?.ws?.wind?.speedThreshold) {
const threshold = boundRange(v1Config?.ws?.wind?.speedThreshold, 0, 11);
v2Config.thresholds.windSpeed = kBeaufortScale[threshold][windUnits];
}
if (v1Config?.ws?.wind?.gustThreshold) {
const threshold = boundRange(v1Config?.ws?.wind?.gustThreshold, 0, 11);
v2Config.thresholds.windGustSpeed = kBeaufortScale[threshold][windUnits];
}
if (v1Config?.ws?.wind?.maxDailyGustThreshold) {
const threshold = boundRange(v1Config?.ws?.wind?.maxDailyGustThreshold, 0, 11);
v2Config.thresholds.windMaxDailySpeed = kBeaufortScale[threshold][windUnits];
}
const rainUnits = v2Config.units.rain;
if (v1Config?.ws?.rain?.rateThreshold) {
v2Config.thresholds.rainRate = rainUnits === 'mm' ? v1Config?.ws?.rain?.rateThreshold :
parseFloat((v1Config?.ws?.rain?.rateThreshold / 25.4).toFixed(3));
}
if (v1Config?.ws?.rain?.eventThreshold) {
v2Config.thresholds.rainEventTotal = rainUnits === 'mm' ? v1Config?.ws?.rain?.eventThreshold :
parseFloat((v1Config?.ws?.rain?.eventThreshold / 25.4).toFixed(3));
}
if (v1Config?.ws?.rain?.hourlyThreshold) {
v2Config.thresholds.rainHourlyTotal = rainUnits === 'mm' ? v1Config?.ws?.rain?.hourlyThreshold :
parseFloat((v1Config?.ws?.rain?.hourlyThreshold / 25.4).toFixed(3));
}
if (v1Config?.ws?.rain?.dailyThreshold) {
v2Config.thresholds.rainDailyTotal = rainUnits === 'mm' ? v1Config?.ws?.rain?.dailyThreshold :
parseFloat((v1Config?.ws?.rain?.dailyThreshold / 25.4).toFixed(3));
}
if (v1Config?.ws?.rain?.weeklyThreshold) {
v2Config.thresholds.rainWeeklyTotal = rainUnits === 'mm' ? v1Config?.ws?.rain?.weeklyThreshold :
parseFloat((v1Config?.ws?.rain?.weeklyThreshold / 25.4).toFixed(3));
}
if (v1Config?.ws?.rain?.monthlyThreshold) {
v2Config.thresholds.rainMonthlyTotal = rainUnits === 'mm' ? v1Config?.ws?.rain?.monthlyThreshold :
parseFloat((v1Config?.ws?.rain?.monthlyThreshold / 25.4).toFixed(3));
}
if (v1Config?.ws?.rain?.yearlyThreshold) {
v2Config.thresholds.rainYearlyTotal = rainUnits === 'mm' ? v1Config?.ws?.rain?.yearlyThreshold :
parseFloat((v1Config?.ws?.rain?.yearlyThreshold / 25.4).toFixed(3));
}
// name overrides
for (let channel = 1; channel <= 8; channel++) {
if (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': `WN34CH${channel}:temperature`, 'value': v1Config?.tf?.[`name${channel}`] });
}
}
for (let channel = 1; channel <= 4; channel++) {
if (v1Config?.pm25?.[`name${channel}`]) {
v2Config.nameOverrides.push({ 'key': `WH41CH${channel}:airQualityPM25`, 'value': v1Config?.pm25?.[`name${channel}`] });
v2Config.nameOverrides.push({ 'key': `WH41CH${channel}:airQualityPM25Avg`, 'value': v1Config?.pm25?.[`name${channel}`] });
}
}
for (let channel = 1; channel <= 8; channel++) {
if (v1Config?.soil?.[`name${channel}`]) {
v2Config.nameOverrides.push({ 'key': `WH51CH${channel}:soilMoisture`, 'value': v1Config?.soil?.[`name${channel}`] });
}
}
for (let channel = 1; channel <= 4; channel++) {
if (v1Config?.leak?.[`name${channel}`]) {
v2Config.nameOverrides.push({ 'key': `WH55CH${channel}:waterLeak`, 'value': v1Config?.leak?.[`name${channel}`] });
}
}
// advanced
if (v1Config?.ws?.solarradiation?.luxFactor) {
v2Config.additional.luxFactor = v1Config?.ws?.solarradiation?.luxFactor || 126.7;
}
v2Config.additional.staticNames = 'disabled';
v2Config.additional.validateMac = 'enabled';
v2Config.additional.acceptAnyPath = 'disabled';
v2Config.additional.validateTimestamp = 'enabled';
v2Config.additional.removeStaleDevices = 'enabled';
// ensure nameOverrides is array so v1 v2 merge concats overrides
if (!Array.isArray(v1Config?.nameOverrides)) {
v1Config.nameOverrides = [];
}
// v1config may be partially or fully migrated to v2
exports.v1ConfigKeys.forEach(v => delete v1Config[v]); // remove all migrated keys from v1
let mergedConfig = merge(v2Config, v1Config); // merge, v1 wins conflicts
mergedConfig = Object.fromEntries(exports.v2ConfigKeys.map(key => [key, mergedConfig[key]])); // retain only valid v2 keys
return mergedConfig;
}
//# sourceMappingURL=Utils.js.map