homebridge-weather-plus-with-pws-sync
Version:
A comprehensive weather plugin for homekit with current observations, forecasts and history.
405 lines (360 loc) • 16.4 kB
JavaScript
/* jshint asi: true, esversion: 6, laxbreak: true, laxcomma: true, node: true, undef: true, unused: true */
const underscore = require('underscore');
const inherits = require('util').inherits,
CustomUUID = {
// Eve UUID
AirPressure: 'E863F10F-079E-48FF-8F27-9C2605A29F52',
// Eve recognized UUIDs
CloudCover: '64392fed-1401-4f7a-9adb-1710dd6e3897',
Condition: 'cd65a9ab-85ad-494a-b2bd-2f380084134d',
ConditionCategory: 'cd65a9ab-85ad-494a-b2bd-2f380084134c',
DewPoint: '095c46e2-278e-4e3c-b9e7-364622a0f501',
ForecastDay: '57f1d4b2-0e7e-4307-95b5-808750e2c1c7',
ObservationStation: 'd1b2787d-1fc4-4345-a20e-7b5a74d693ed',
ObservationTime: '234fd9f1-1d33-4128-b622-d052f0c402af',
Ozone: 'bbeffddd-1bcd-4d75-b7cd-b57a90a04d13',
Rain1h: '10c88f40-7ec4-478c-8d5a-bd0c3cce14b7',
RainBool: 'f14eb1ad-e000-4ef4-a54f-0cf07b2e7be7',
RainDay: 'ccc04890-565b-4376-b39a-3113341d9e0f',
RainChance: 'fc01b24f-cf7e-4a74-90db-1b427af1ffa3',
SnowBool: 'f14eb1ad-e000-4ce6-bd0e-384f9ec4d5dd',
SolarRadiation: '1819a23e-ecab-4d39-b29a-7364d299310b',
SunriseTime: '0d96f60e-3688-487e-8cee-d75f05bb3008',
SunsetTime: '3de24ee0-a288-4e15-a5a8-ead2451b727c',
TemperatureMin: '707b78ca-51ab-4dc9-8630-80a58f07e419',
TemperatureApparent: 'c1283352-3d12-4777-acd5-4734760f1ac8',
UVIndex: '05ba0fe0-b848-4226-906d-5b64272e05ce',
Visibility: 'd24ecc1e-6fad-4fb5-8137-5af88bd5e857',
WindDirection: '46f1284c-1912-421b-82f5-eb75008b167e',
WindSpeed: '49C8AE5A-A3A5-41AB-BF1F-12D5654F9F41',
WindSpeedMax: '6b8861e5-d6f3-425c-83b6-069945ffd1f1'
};
let CustomCharacteristic = {};
// A more accurate way of rounding decimals in Javascript compared to the usual multiply & divide
// See https://www.jacklmoore.com/notes/rounding-in-javascript/ for explanation
function round(value, decimals) {
return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
}
module.exports = function (Characteristic, units) {
units = // rainfail temperature visibility windspeed airpressure
{
ca: 'ca', // mm celsius kilometers km/hour hPa
imperial: 'imperial',
us: 'imperial', // inches fahrenheit miles miles/hour hPa
si: 'si',
metric: 'si', // mm celsius kilometers m/second hPa
sitorr: 'sitorr', // mm celsius kilometers m/second mmhg
uk: 'uk' // mm celsius miles miles/hour hPa
}[units.toLowerCase()];
if (!units) units = 'si';
let rainfallProps = (max) => {
var range = (units !== 'imperial') ? {unit: 'mm', maxValue: max, minValue: 0, minStep: 0.1}
: {unit: 'in', maxValue: Math.round(max / 25.4), minValue: 0, minStep: 0.01};
return underscore.extend(
{
format: Characteristic.Formats.FLOAT
, perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
}, range);
};
let rainfallValue = (val) => {
return (units !== 'imperial') ? val : round(val / 25.4, 2);
};
let temperatureValue = (celsius) => {
return units === 'imperial' ? (round(celsius * 1.8, 1)) + 32 : celsius;
};
let temperatureProps = (min, max) => {
var range = {
unit: units === 'imperial' ? 'fahrenheit' : Characteristic.Units.CELSIUS,
minValue: temperatureValue(min),
maxValue: temperatureValue(max)
};
return underscore.extend(
{
format: Characteristic.Formats.FLOAT
, minStep: 0.1
, perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
}, range);
};
let km2mi = (km) => {
return Math.round(km / 1.60934);
};
let visibilityProps = (max) => {
var range = ((units === 'si') || (units === 'sitorr') || (units === 'ca')) ? {
unit: 'km',
maxValue: max,
minValue: 0
}
: {unit: 'mi', maxValue: km2mi(max), minValue: 0};
return underscore.extend(
{
format: Characteristic.Formats.UINT8
, minStep: 1
, perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
}, range);
};
let visibilityValue = (val) => {
return ((units === 'si') || (units === 'sitorr') || (units === 'ca')) ? val : km2mi(val);
};
let mtos2kmh = (m) => {
return (round((m * 3600) / 1000, 2));
};
let mtos2mih = (m) => {
return (round((m * 3600) / 1609.34, 2));
};
let windspeedProps = (max) => {
var range = ((units === 'si') || (units === 'sitorr')) ? {unit: 'm/s', maxValue: max, minValue: 0}
: (units === 'ca') ? {unit: 'km/h', maxValue: mtos2kmh(max), minValue: 0}
: {unit: 'mph', maxValue: mtos2mih(max), minValue: 0};
return underscore.extend(
{
format: Characteristic.Formats.UINT8
, minStep: 0.1
, perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
}, range);
};
let windspeedValue = (val) => {
return ((units === 'si') || (units === 'sitorr')) ? val
: (units === 'ca') ? mtos2kmh(val)
: mtos2mih(val);
};
let hpa2mmhg = (hpa) => {
return (round(hpa / 1.3332, 0));
};
let airpressureProps = (min, max) => {
let range = (units === 'sitorr') ? {unit: 'mmhg', maxValue: hpa2mmhg(max), minValue: hpa2mmhg(min)}
: {unit: 'hPa', maxValue: max, minValue: min};
return underscore.extend(
{
format: Characteristic.Formats.UINT16
, minStep: 1
, perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
}, range);
};
let airpressureValue = (val) => {
return (units === 'sitorr') ? hpa2mmhg(val) : val;
};
CustomCharacteristic.AirPressure = function () {
Characteristic.call(this, 'Air Pressure', CustomUUID.AirPressure);
this.setProps(airpressureProps(700, 1100));
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.AirPressure, Characteristic);
CustomCharacteristic.AirPressure._unitvalue = airpressureValue;
CustomCharacteristic.CloudCover = function () {
Characteristic.call(this, 'Cloud Cover', CustomUUID.CloudCover);
this.setProps({
format: Characteristic.Formats.UINT8,
unit: Characteristic.Units.PERCENTAGE,
maxValue: 100,
minValue: 0,
minStep: 1,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.CloudCover, Characteristic);
CustomCharacteristic.Condition = function () {
Characteristic.call(this, 'Weather Condition', CustomUUID.Condition);
this.setProps({
format: Characteristic.Formats.STRING,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.Condition, Characteristic);
CustomCharacteristic.ConditionCategory = function () {
Characteristic.call(this, 'Weather Condition Category', CustomUUID.ConditionCategory);
this.setProps({
format: Characteristic.Formats.UINT8,
maxValue: 9,
minValue: 0,
minStep: 1,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.ConditionCategory, Characteristic);
CustomCharacteristic.DewPoint = function () {
Characteristic.call(this, 'Dew Point', CustomUUID.DewPoint);
this.setProps(temperatureProps(-50, 100));
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.DewPoint, Characteristic);
CustomCharacteristic.ForecastDay = function () {
Characteristic.call(this, 'Day', CustomUUID.ForecastDay);
this.setProps({
format: Characteristic.Formats.STRING,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.ForecastDay, Characteristic);
CustomCharacteristic.ObservationStation = function () {
Characteristic.call(this, 'Station', CustomUUID.ObservationStation);
this.setProps({
format: Characteristic.Formats.STRING,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.ObservationStation, Characteristic);
CustomCharacteristic.ObservationTime = function () {
Characteristic.call(this, 'Observation Time', CustomUUID.ObservationTime);
this.setProps({
format: Characteristic.Formats.STRING,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.ObservationTime, Characteristic);
CustomCharacteristic.Ozone = function () {
Characteristic.call(this, 'Ozone', CustomUUID.Ozone);
this.setProps({
format: Characteristic.Formats.UINT16,
unit: 'DU',
maxValue: 500,
minValue: 0,
minStep: 1,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.Ozone, Characteristic);
CustomCharacteristic.Rain1h = function () {
Characteristic.call(this, 'Rain Last Hour', CustomUUID.Rain1h);
this.setProps(rainfallProps(50));
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.Rain1h, Characteristic);
CustomCharacteristic.Rain1h._unitvalue = rainfallValue;
// Sensor if its raining
// True: It is raining at the moment (current conditions). It will rain on the day (forecast)
// False: It is not raining at the moment (current conditions). It will not rain on the day (forecast)
CustomCharacteristic.RainBool = function () {
Characteristic.call(this, 'Rain', CustomUUID.RainBool);
this.setProps({
format: Characteristic.Formats.BOOL,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.RainBool, Characteristic);
CustomCharacteristic.RainChance = function () {
Characteristic.call(this, 'Rain Chance', CustomUUID.RainChance);
this.setProps({
format: Characteristic.Formats.UINT8,
unit: Characteristic.Units.PERCENTAGE,
maxValue: 100,
minValue: 0,
minStep: 1,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.RainChance, Characteristic);
CustomCharacteristic.RainDay = function () {
Characteristic.call(this, 'Rain All Day', CustomUUID.RainDay);
this.setProps(rainfallProps(500));
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.RainDay, Characteristic);
CustomCharacteristic.RainDay._unitvalue = rainfallValue;
// Sensor if its snowing
// True: It is snowing at the moment (current conditions). It will snow on the day (forecast)
// False: It is not snowing at the moment (current conditions). It will not snow on the day (forecast)
CustomCharacteristic.SnowBool = function () {
Characteristic.call(this, 'Snow', CustomUUID.SnowBool);
this.setProps({
format: Characteristic.Formats.BOOL,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.SnowBool, Characteristic);
CustomCharacteristic.SolarRadiation = function () {
Characteristic.call(this, 'Solar Radiation', CustomUUID.SolarRadiation);
this.setProps({
format: Characteristic.Formats.UINT16,
unit: "W/m²",
maxValue: 2000,
minValue: 0,
minStep: 1,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.SolarRadiation, Characteristic);
CustomCharacteristic.SunriseTime = function () {
Characteristic.call(this, 'Sunrise', CustomUUID.SunriseTime);
this.setProps({
format: Characteristic.Formats.STRING,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.SunriseTime, Characteristic);
CustomCharacteristic.SunsetTime = function () {
Characteristic.call(this, 'Sunset', CustomUUID.SunsetTime);
this.setProps({
format: Characteristic.Formats.STRING,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.SunsetTime, Characteristic);
CustomCharacteristic.TemperatureMin = function () {
Characteristic.call(this, 'Temperature Min', CustomUUID.TemperatureMin);
this.setProps(temperatureProps(-50, 100));
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.TemperatureMin, Characteristic);
CustomCharacteristic.TemperatureApparent = function () {
Characteristic.call(this, 'Apparent temperature', CustomUUID.TemperatureApparent);
this.setProps(temperatureProps(-50, 100));
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.TemperatureApparent, Characteristic);
CustomCharacteristic.UVIndex = function () {
Characteristic.call(this, 'UV Index', CustomUUID.UVIndex);
this.setProps({
format: Characteristic.Formats.UINT8,
maxValue: 12,
minValue: 0,
minStep: 1,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.UVIndex, Characteristic);
CustomCharacteristic.Visibility = function () {
Characteristic.call(this, 'Visibility', CustomUUID.Visibility);
this.setProps(visibilityProps(100));
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.Visibility, Characteristic);
CustomCharacteristic.Visibility._unitvalue = visibilityValue;
CustomCharacteristic.WindDirection = function () {
Characteristic.call(this, 'Wind Direction', CustomUUID.WindDirection);
this.setProps({
format: Characteristic.Formats.STRING,
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
});
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.WindDirection, Characteristic);
CustomCharacteristic.WindSpeed = function () {
Characteristic.call(this, 'Wind Speed', CustomUUID.WindSpeed);
this.setProps(windspeedProps(100));
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.WindSpeed, Characteristic);
CustomCharacteristic.WindSpeed._unitvalue = windspeedValue;
CustomCharacteristic.WindSpeedMax = function () {
Characteristic.call(this, 'Wind Speed Max', CustomUUID.WindSpeedMax);
this.setProps(windspeedProps(100));
this.value = this.getDefaultValue();
};
inherits(CustomCharacteristic.WindSpeedMax, Characteristic);
CustomCharacteristic.WindSpeedMax._unitvalue = windspeedValue;
return CustomCharacteristic;
};