matterbridge-hass
Version:
Matterbridge hass plugin
1,059 lines • 53.9 kB
JavaScript
import { EventEmitter } from 'node:events';
import { readFileSync } from 'node:fs';
import { AnsiLogger, CYAN, db, debugStringify, er, rs } from 'matterbridge/logger';
import { hasParameter } from 'matterbridge/utils';
import WebSocket from 'ws';
export var SelectService;
(function (SelectService) {
SelectService["SELECT_FIRST"] = "select_first";
SelectService["SELECT_LAST"] = "select_last";
SelectService["SELECT_NEXT"] = "select_next";
SelectService["SELECT_OPTION"] = "select_option";
SelectService["SELECT_PREVIOUS"] = "select_previous";
})(SelectService || (SelectService = {}));
export var SelectAttribute;
(function (SelectAttribute) {
SelectAttribute["CYCLE"] = "cycle";
SelectAttribute["OPTIONS"] = "options";
SelectAttribute["OPTION"] = "option";
})(SelectAttribute || (SelectAttribute = {}));
export var MediaPlayerService;
(function (MediaPlayerService) {
MediaPlayerService["BROWSE_MEDIA"] = "browse_media";
MediaPlayerService["CLEAR_PLAYLIST"] = "clear_playlist";
MediaPlayerService["JOIN"] = "join";
MediaPlayerService["MEDIA_NEXT_TRACK"] = "media_next_track";
MediaPlayerService["MEDIA_PAUSE"] = "media_pause";
MediaPlayerService["MEDIA_PLAY"] = "media_play";
MediaPlayerService["MEDIA_PLAY_PAUSE"] = "media_play_pause";
MediaPlayerService["MEDIA_PREVIOUS_TRACK"] = "media_previous_track";
MediaPlayerService["MEDIA_SEEK"] = "media_seek";
MediaPlayerService["MEDIA_STOP"] = "media_stop";
MediaPlayerService["PLAY_MEDIA"] = "play_media";
MediaPlayerService["REPEAT_SET"] = "repeat_set";
MediaPlayerService["SEARCH_MEDIA"] = "search_media";
MediaPlayerService["SELECT_SOUND_MODE"] = "select_sound_mode";
MediaPlayerService["SELECT_SOURCE"] = "select_source";
MediaPlayerService["SHUFFLE_SET"] = "shuffle_set";
MediaPlayerService["TOGGLE"] = "toggle";
MediaPlayerService["TURN_OFF"] = "turn_off";
MediaPlayerService["TURN_ON"] = "turn_on";
MediaPlayerService["UNJOIN"] = "unjoin";
MediaPlayerService["VOLUME_DOWN"] = "volume_down";
MediaPlayerService["VOLUME_MUTE"] = "volume_mute";
MediaPlayerService["VOLUME_SET"] = "volume_set";
MediaPlayerService["VOLUME_UP"] = "volume_up";
})(MediaPlayerService || (MediaPlayerService = {}));
export var MediaPlayerAttribute;
(function (MediaPlayerAttribute) {
MediaPlayerAttribute["APP_ID"] = "app_id";
MediaPlayerAttribute["APP_NAME"] = "app_name";
MediaPlayerAttribute["ENTITY_PICTURE_LOCAL"] = "entity_picture_local";
MediaPlayerAttribute["GROUP_MEMBERS"] = "group_members";
MediaPlayerAttribute["INPUT_SOURCE"] = "source";
MediaPlayerAttribute["INPUT_SOURCE_LIST"] = "source_list";
MediaPlayerAttribute["MEDIA_ALBUM_ARTIST"] = "media_album_artist";
MediaPlayerAttribute["MEDIA_ALBUM_NAME"] = "media_album_name";
MediaPlayerAttribute["MEDIA_ANNOUNCE"] = "announce";
MediaPlayerAttribute["MEDIA_ARTIST"] = "media_artist";
MediaPlayerAttribute["MEDIA_CHANNEL"] = "media_channel";
MediaPlayerAttribute["MEDIA_CONTENT_ID"] = "media_content_id";
MediaPlayerAttribute["MEDIA_CONTENT_TYPE"] = "media_content_type";
MediaPlayerAttribute["MEDIA_DURATION"] = "media_duration";
MediaPlayerAttribute["MEDIA_ENQUEUE"] = "enqueue";
MediaPlayerAttribute["MEDIA_EPISODE"] = "media_episode";
MediaPlayerAttribute["MEDIA_EXTRA"] = "extra";
MediaPlayerAttribute["MEDIA_FILTER_CLASSES"] = "media_filter_classes";
MediaPlayerAttribute["MEDIA_IMAGE_REMOTELY_ACCESSIBLE"] = "media_image_remotely_accessible";
MediaPlayerAttribute["MEDIA_IMAGE_URL"] = "media_image_url";
MediaPlayerAttribute["MEDIA_PLAYLIST"] = "media_playlist";
MediaPlayerAttribute["MEDIA_POSITION"] = "media_position";
MediaPlayerAttribute["MEDIA_POSITION_UPDATED_AT"] = "media_position_updated_at";
MediaPlayerAttribute["MEDIA_REPEAT"] = "repeat";
MediaPlayerAttribute["MEDIA_SEARCH_QUERY"] = "search_query";
MediaPlayerAttribute["MEDIA_SEASON"] = "media_season";
MediaPlayerAttribute["MEDIA_SEEK_POSITION"] = "seek_position";
MediaPlayerAttribute["MEDIA_SERIES_TITLE"] = "media_series_title";
MediaPlayerAttribute["MEDIA_SHUFFLE"] = "shuffle";
MediaPlayerAttribute["MEDIA_TITLE"] = "media_title";
MediaPlayerAttribute["MEDIA_TRACK"] = "media_track";
MediaPlayerAttribute["MEDIA_VOLUME_LEVEL"] = "volume_level";
MediaPlayerAttribute["MEDIA_VOLUME_MUTED"] = "is_volume_muted";
MediaPlayerAttribute["SOUND_MODE"] = "sound_mode";
MediaPlayerAttribute["SOUND_MODE_LIST"] = "sound_mode_list";
})(MediaPlayerAttribute || (MediaPlayerAttribute = {}));
export var MediaPlayerState;
(function (MediaPlayerState) {
MediaPlayerState["OFF"] = "off";
MediaPlayerState["ON"] = "on";
MediaPlayerState["IDLE"] = "idle";
MediaPlayerState["PLAYING"] = "playing";
MediaPlayerState["PAUSED"] = "paused";
MediaPlayerState["STANDBY"] = "standby";
MediaPlayerState["BUFFERING"] = "buffering";
})(MediaPlayerState || (MediaPlayerState = {}));
export var MediaClass;
(function (MediaClass) {
MediaClass["ALBUM"] = "album";
MediaClass["APP"] = "app";
MediaClass["ARTIST"] = "artist";
MediaClass["CHANNEL"] = "channel";
MediaClass["COMPOSER"] = "composer";
MediaClass["CONTRIBUTING_ARTIST"] = "contributing_artist";
MediaClass["DIRECTORY"] = "directory";
MediaClass["EPISODE"] = "episode";
MediaClass["GAME"] = "game";
MediaClass["GENRE"] = "genre";
MediaClass["IMAGE"] = "image";
MediaClass["MOVIE"] = "movie";
MediaClass["MUSIC"] = "music";
MediaClass["PLAYLIST"] = "playlist";
MediaClass["PODCAST"] = "podcast";
MediaClass["SEASON"] = "season";
MediaClass["TRACK"] = "track";
MediaClass["TV_SHOW"] = "tv_show";
MediaClass["URL"] = "url";
MediaClass["VIDEO"] = "video";
})(MediaClass || (MediaClass = {}));
export var MediaType;
(function (MediaType) {
MediaType["ALBUM"] = "album";
MediaType["APP"] = "app";
MediaType["APPS"] = "apps";
MediaType["ARTIST"] = "artist";
MediaType["CHANNEL"] = "channel";
MediaType["CHANNELS"] = "channels";
MediaType["COMPOSER"] = "composer";
MediaType["CONTRIBUTING_ARTIST"] = "contributing_artist";
MediaType["EPISODE"] = "episode";
MediaType["GAME"] = "game";
MediaType["GENRE"] = "genre";
MediaType["IMAGE"] = "image";
MediaType["MOVIE"] = "movie";
MediaType["MUSIC"] = "music";
MediaType["PLAYLIST"] = "playlist";
MediaType["PODCAST"] = "podcast";
MediaType["SEASON"] = "season";
MediaType["TRACK"] = "track";
MediaType["TVSHOW"] = "tvshow";
MediaType["URL"] = "url";
MediaType["VIDEO"] = "video";
})(MediaType || (MediaType = {}));
export var RepeatMode;
(function (RepeatMode) {
RepeatMode["ALL"] = "all";
RepeatMode["OFF"] = "off";
RepeatMode["ONE"] = "one";
})(RepeatMode || (RepeatMode = {}));
export var MediaPlayerDeviceClass;
(function (MediaPlayerDeviceClass) {
MediaPlayerDeviceClass["TV"] = "tv";
MediaPlayerDeviceClass["SPEAKER"] = "speaker";
MediaPlayerDeviceClass["RECEIVER"] = "receiver";
})(MediaPlayerDeviceClass || (MediaPlayerDeviceClass = {}));
export var MediaPlayerEnqueue;
(function (MediaPlayerEnqueue) {
MediaPlayerEnqueue["ADD"] = "add";
MediaPlayerEnqueue["NEXT"] = "next";
MediaPlayerEnqueue["PLAY"] = "play";
MediaPlayerEnqueue["REPLACE"] = "replace";
})(MediaPlayerEnqueue || (MediaPlayerEnqueue = {}));
export var MediaPlayerEntityFeature;
(function (MediaPlayerEntityFeature) {
MediaPlayerEntityFeature[MediaPlayerEntityFeature["PAUSE"] = 1] = "PAUSE";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["SEEK"] = 2] = "SEEK";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["VOLUME_SET"] = 4] = "VOLUME_SET";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["VOLUME_MUTE"] = 8] = "VOLUME_MUTE";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["PREVIOUS_TRACK"] = 16] = "PREVIOUS_TRACK";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["NEXT_TRACK"] = 32] = "NEXT_TRACK";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["TURN_ON"] = 128] = "TURN_ON";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["TURN_OFF"] = 256] = "TURN_OFF";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["PLAY_MEDIA"] = 512] = "PLAY_MEDIA";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["VOLUME_STEP"] = 1024] = "VOLUME_STEP";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["SELECT_SOURCE"] = 2048] = "SELECT_SOURCE";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["STOP"] = 4096] = "STOP";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["CLEAR_PLAYLIST"] = 8192] = "CLEAR_PLAYLIST";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["PLAY"] = 16384] = "PLAY";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["SHUFFLE_SET"] = 32768] = "SHUFFLE_SET";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["SELECT_SOUND_MODE"] = 65536] = "SELECT_SOUND_MODE";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["BROWSE_MEDIA"] = 131072] = "BROWSE_MEDIA";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["REPEAT_SET"] = 262144] = "REPEAT_SET";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["GROUPING"] = 524288] = "GROUPING";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["MEDIA_ANNOUNCE"] = 1048576] = "MEDIA_ANNOUNCE";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["MEDIA_ENQUEUE"] = 2097152] = "MEDIA_ENQUEUE";
MediaPlayerEntityFeature[MediaPlayerEntityFeature["SEARCH_MEDIA"] = 4194304] = "SEARCH_MEDIA";
})(MediaPlayerEntityFeature || (MediaPlayerEntityFeature = {}));
export var LightEntityFeature;
(function (LightEntityFeature) {
LightEntityFeature[LightEntityFeature["EFFECT"] = 4] = "EFFECT";
LightEntityFeature[LightEntityFeature["FLASH"] = 8] = "FLASH";
LightEntityFeature[LightEntityFeature["TRANSITION"] = 32] = "TRANSITION";
})(LightEntityFeature || (LightEntityFeature = {}));
export var ColorMode;
(function (ColorMode) {
ColorMode["UNKNOWN"] = "unknown";
ColorMode["ONOFF"] = "onoff";
ColorMode["BRIGHTNESS"] = "brightness";
ColorMode["COLOR_TEMP"] = "color_temp";
ColorMode["HS"] = "hs";
ColorMode["XY"] = "xy";
ColorMode["RGB"] = "rgb";
ColorMode["RGBW"] = "rgbw";
ColorMode["RGBWW"] = "rgbww";
ColorMode["WHITE"] = "white";
})(ColorMode || (ColorMode = {}));
export const ATTR_COLOR_MODE = 'color_mode';
export const ATTR_SUPPORTED_COLOR_MODES = 'supported_color_modes';
export const ATTR_TRANSITION = 'transition';
export const ATTR_RGB_COLOR = 'rgb_color';
export const ATTR_RGBW_COLOR = 'rgbw_color';
export const ATTR_RGBWW_COLOR = 'rgbww_color';
export const ATTR_XY_COLOR = 'xy_color';
export const ATTR_HS_COLOR = 'hs_color';
export const ATTR_COLOR_TEMP_KELVIN = 'color_temp_kelvin';
export const ATTR_MIN_COLOR_TEMP_KELVIN = 'min_color_temp_kelvin';
export const ATTR_MAX_COLOR_TEMP_KELVIN = 'max_color_temp_kelvin';
export const ATTR_COLOR_NAME = 'color_name';
export const ATTR_WHITE = 'white';
export const DEFAULT_MIN_KELVIN = 2000;
export const DEFAULT_MAX_KELVIN = 6535;
export const DIRECTION_FORWARD = 'forward';
export const DIRECTION_REVERSE = 'reverse';
export var FanEntityFeature;
(function (FanEntityFeature) {
FanEntityFeature[FanEntityFeature["SET_SPEED"] = 1] = "SET_SPEED";
FanEntityFeature[FanEntityFeature["OSCILLATE"] = 2] = "OSCILLATE";
FanEntityFeature[FanEntityFeature["DIRECTION"] = 4] = "DIRECTION";
FanEntityFeature[FanEntityFeature["PRESET_MODE"] = 8] = "PRESET_MODE";
FanEntityFeature[FanEntityFeature["TURN_OFF"] = 16] = "TURN_OFF";
FanEntityFeature[FanEntityFeature["TURN_ON"] = 32] = "TURN_ON";
})(FanEntityFeature || (FanEntityFeature = {}));
export var ValveEntityFeature;
(function (ValveEntityFeature) {
ValveEntityFeature[ValveEntityFeature["OPEN"] = 1] = "OPEN";
ValveEntityFeature[ValveEntityFeature["CLOSE"] = 2] = "CLOSE";
ValveEntityFeature[ValveEntityFeature["SET_POSITION"] = 4] = "SET_POSITION";
ValveEntityFeature[ValveEntityFeature["STOP"] = 8] = "STOP";
})(ValveEntityFeature || (ValveEntityFeature = {}));
export var ValveDeviceClass;
(function (ValveDeviceClass) {
ValveDeviceClass["WATER"] = "water";
ValveDeviceClass["GAS"] = "gas";
})(ValveDeviceClass || (ValveDeviceClass = {}));
export var ValveState;
(function (ValveState) {
ValveState["OPENING"] = "opening";
ValveState["CLOSING"] = "closing";
ValveState["CLOSED"] = "closed";
ValveState["OPEN"] = "open";
})(ValveState || (ValveState = {}));
export var VacuumEntityFeature;
(function (VacuumEntityFeature) {
VacuumEntityFeature[VacuumEntityFeature["TURN_ON"] = 1] = "TURN_ON";
VacuumEntityFeature[VacuumEntityFeature["TURN_OFF"] = 2] = "TURN_OFF";
VacuumEntityFeature[VacuumEntityFeature["PAUSE"] = 4] = "PAUSE";
VacuumEntityFeature[VacuumEntityFeature["STOP"] = 8] = "STOP";
VacuumEntityFeature[VacuumEntityFeature["RETURN_HOME"] = 16] = "RETURN_HOME";
VacuumEntityFeature[VacuumEntityFeature["FAN_SPEED"] = 32] = "FAN_SPEED";
VacuumEntityFeature[VacuumEntityFeature["BATTERY"] = 64] = "BATTERY";
VacuumEntityFeature[VacuumEntityFeature["STATUS"] = 128] = "STATUS";
VacuumEntityFeature[VacuumEntityFeature["SEND_COMMAND"] = 256] = "SEND_COMMAND";
VacuumEntityFeature[VacuumEntityFeature["LOCATE"] = 512] = "LOCATE";
VacuumEntityFeature[VacuumEntityFeature["CLEAN_SPOT"] = 1024] = "CLEAN_SPOT";
VacuumEntityFeature[VacuumEntityFeature["MAP"] = 2048] = "MAP";
VacuumEntityFeature[VacuumEntityFeature["STATE"] = 4096] = "STATE";
VacuumEntityFeature[VacuumEntityFeature["START"] = 8192] = "START";
})(VacuumEntityFeature || (VacuumEntityFeature = {}));
export var VacuumActivity;
(function (VacuumActivity) {
VacuumActivity["CLEANING"] = "cleaning";
VacuumActivity["DOCKED"] = "docked";
VacuumActivity["IDLE"] = "idle";
VacuumActivity["PAUSED"] = "paused";
VacuumActivity["RETURNING"] = "returning";
VacuumActivity["ERROR"] = "error";
})(VacuumActivity || (VacuumActivity = {}));
export var ClimateEntityFeature;
(function (ClimateEntityFeature) {
ClimateEntityFeature[ClimateEntityFeature["TARGET_TEMPERATURE"] = 1] = "TARGET_TEMPERATURE";
ClimateEntityFeature[ClimateEntityFeature["TARGET_TEMPERATURE_RANGE"] = 2] = "TARGET_TEMPERATURE_RANGE";
ClimateEntityFeature[ClimateEntityFeature["TARGET_HUMIDITY"] = 4] = "TARGET_HUMIDITY";
ClimateEntityFeature[ClimateEntityFeature["FAN_MODE"] = 8] = "FAN_MODE";
ClimateEntityFeature[ClimateEntityFeature["PRESET_MODE"] = 16] = "PRESET_MODE";
ClimateEntityFeature[ClimateEntityFeature["SWING_MODE"] = 32] = "SWING_MODE";
ClimateEntityFeature[ClimateEntityFeature["TURN_OFF"] = 128] = "TURN_OFF";
ClimateEntityFeature[ClimateEntityFeature["TURN_ON"] = 256] = "TURN_ON";
ClimateEntityFeature[ClimateEntityFeature["SWING_HORIZONTAL_MODE"] = 512] = "SWING_HORIZONTAL_MODE";
})(ClimateEntityFeature || (ClimateEntityFeature = {}));
export var HVACMode;
(function (HVACMode) {
HVACMode["OFF"] = "off";
HVACMode["HEAT"] = "heat";
HVACMode["COOL"] = "cool";
HVACMode["HEAT_COOL"] = "heat_cool";
HVACMode["AUTO"] = "auto";
HVACMode["DRY"] = "dry";
HVACMode["FAN_ONLY"] = "fan_only";
})(HVACMode || (HVACMode = {}));
export var HVACAction;
(function (HVACAction) {
HVACAction["COOLING"] = "cooling";
HVACAction["DEFROSTING"] = "defrosting";
HVACAction["DRYING"] = "drying";
HVACAction["FAN"] = "fan";
HVACAction["HEATING"] = "heating";
HVACAction["IDLE"] = "idle";
HVACAction["OFF"] = "off";
HVACAction["PREHEATING"] = "preheating";
})(HVACAction || (HVACAction = {}));
export const CLIMATE_FAN_ON = 'on';
export const CLIMATE_FAN_OFF = 'off';
export const CLIMATE_FAN_AUTO = 'auto';
export const CLIMATE_FAN_LOW = 'low';
export const CLIMATE_FAN_MEDIUM = 'medium';
export const CLIMATE_FAN_HIGH = 'high';
export const CLIMATE_FAN_TOP = 'top';
export const CLIMATE_FAN_MIDDLE = 'middle';
export const CLIMATE_FAN_FOCUS = 'focus';
export const CLIMATE_FAN_DIFFUSE = 'diffuse';
export const CLIMATE_SWING_ON = 'on';
export const CLIMATE_SWING_OFF = 'off';
export const CLIMATE_SWING_BOTH = 'both';
export const CLIMATE_SWING_VERTICAL = 'vertical';
export const CLIMATE_SWING_HORIZONTAL = 'horizontal';
export const CLIMATE_SWING_HORIZONTAL_ON = 'on';
export const CLIMATE_SWING_HORIZONTAL_OFF = 'off';
export const DEFAULT_MIN_TEMP = 7;
export const DEFAULT_MAX_TEMP = 35;
export const DEFAULT_MIN_HUMIDITY = 30;
export const DEFAULT_MAX_HUMIDITY = 99;
export var EventDeviceClass;
(function (EventDeviceClass) {
EventDeviceClass["DOORBELL"] = "doorbell";
EventDeviceClass["BUTTON"] = "button";
EventDeviceClass["MOTION"] = "motion";
})(EventDeviceClass || (EventDeviceClass = {}));
export var UnitOfApparentPower;
(function (UnitOfApparentPower) {
UnitOfApparentPower["MILLIVOLT_AMPERE"] = "mVA";
UnitOfApparentPower["VOLT_AMPERE"] = "VA";
UnitOfApparentPower["KILO_VOLT_AMPERE"] = "kVA";
})(UnitOfApparentPower || (UnitOfApparentPower = {}));
export var UnitOfPower;
(function (UnitOfPower) {
UnitOfPower["MILLIWATT"] = "mW";
UnitOfPower["WATT"] = "W";
UnitOfPower["KILO_WATT"] = "kW";
UnitOfPower["MEGA_WATT"] = "MW";
UnitOfPower["GIGA_WATT"] = "GW";
UnitOfPower["TERA_WATT"] = "TW";
UnitOfPower["BTU_PER_HOUR"] = "BTU/h";
})(UnitOfPower || (UnitOfPower = {}));
export var UnitOfReactivePower;
(function (UnitOfReactivePower) {
UnitOfReactivePower["MILLIVOLT_AMPERE_REACTIVE"] = "mvar";
UnitOfReactivePower["VOLT_AMPERE_REACTIVE"] = "var";
UnitOfReactivePower["KILO_VOLT_AMPERE_REACTIVE"] = "kvar";
})(UnitOfReactivePower || (UnitOfReactivePower = {}));
export var UnitOfEnergy;
(function (UnitOfEnergy) {
UnitOfEnergy["JOULE"] = "J";
UnitOfEnergy["KILO_JOULE"] = "kJ";
UnitOfEnergy["MEGA_JOULE"] = "MJ";
UnitOfEnergy["GIGA_JOULE"] = "GJ";
UnitOfEnergy["MILLIWATT_HOUR"] = "mWh";
UnitOfEnergy["WATT_HOUR"] = "Wh";
UnitOfEnergy["KILO_WATT_HOUR"] = "kWh";
UnitOfEnergy["MEGA_WATT_HOUR"] = "MWh";
UnitOfEnergy["GIGA_WATT_HOUR"] = "GWh";
UnitOfEnergy["TERA_WATT_HOUR"] = "TWh";
UnitOfEnergy["CALORIE"] = "cal";
UnitOfEnergy["KILO_CALORIE"] = "kcal";
UnitOfEnergy["MEGA_CALORIE"] = "Mcal";
UnitOfEnergy["GIGA_CALORIE"] = "Gcal";
})(UnitOfEnergy || (UnitOfEnergy = {}));
export var UnitOfReactiveEnergy;
(function (UnitOfReactiveEnergy) {
UnitOfReactiveEnergy["VOLT_AMPERE_REACTIVE_HOUR"] = "varh";
UnitOfReactiveEnergy["KILO_VOLT_AMPERE_REACTIVE_HOUR"] = "kvarh";
})(UnitOfReactiveEnergy || (UnitOfReactiveEnergy = {}));
export var UnitOfEnergyDistance;
(function (UnitOfEnergyDistance) {
UnitOfEnergyDistance["KILO_WATT_HOUR_PER_100_KM"] = "kWh/100km";
UnitOfEnergyDistance["WATT_HOUR_PER_KM"] = "Wh/km";
UnitOfEnergyDistance["MILES_PER_KILO_WATT_HOUR"] = "mi/kWh";
UnitOfEnergyDistance["KM_PER_KILO_WATT_HOUR"] = "km/kWh";
})(UnitOfEnergyDistance || (UnitOfEnergyDistance = {}));
export var UnitOfElectricCurrent;
(function (UnitOfElectricCurrent) {
UnitOfElectricCurrent["MILLIAMPERE"] = "mA";
UnitOfElectricCurrent["AMPERE"] = "A";
})(UnitOfElectricCurrent || (UnitOfElectricCurrent = {}));
export var UnitOfElectricPotential;
(function (UnitOfElectricPotential) {
UnitOfElectricPotential["MICROVOLT"] = "\u03BCV";
UnitOfElectricPotential["MILLIVOLT"] = "mV";
UnitOfElectricPotential["VOLT"] = "V";
UnitOfElectricPotential["KILOVOLT"] = "kV";
UnitOfElectricPotential["MEGAVOLT"] = "MV";
})(UnitOfElectricPotential || (UnitOfElectricPotential = {}));
export const DEGREE = '°';
export var Currency;
(function (Currency) {
Currency["EURO"] = "\u20AC";
Currency["DOLLAR"] = "$";
Currency["CENT"] = "\u00A2";
})(Currency || (Currency = {}));
export var UnitOfTemperature;
(function (UnitOfTemperature) {
UnitOfTemperature["CELSIUS"] = "\u00B0C";
UnitOfTemperature["FAHRENHEIT"] = "\u00B0F";
UnitOfTemperature["KELVIN"] = "K";
})(UnitOfTemperature || (UnitOfTemperature = {}));
export var UnitOfTime;
(function (UnitOfTime) {
UnitOfTime["MICROSECONDS"] = "\u03BCs";
UnitOfTime["MILLISECONDS"] = "ms";
UnitOfTime["SECONDS"] = "s";
UnitOfTime["MINUTES"] = "min";
UnitOfTime["HOURS"] = "h";
UnitOfTime["DAYS"] = "d";
UnitOfTime["WEEKS"] = "w";
UnitOfTime["MONTHS"] = "m";
UnitOfTime["YEARS"] = "y";
})(UnitOfTime || (UnitOfTime = {}));
export var UnitOfLength;
(function (UnitOfLength) {
UnitOfLength["MILLIMETERS"] = "mm";
UnitOfLength["CENTIMETERS"] = "cm";
UnitOfLength["METERS"] = "m";
UnitOfLength["KILOMETERS"] = "km";
UnitOfLength["INCHES"] = "in";
UnitOfLength["FEET"] = "ft";
UnitOfLength["YARDS"] = "yd";
UnitOfLength["MILES"] = "mi";
UnitOfLength["NAUTICAL_MILES"] = "nmi";
})(UnitOfLength || (UnitOfLength = {}));
export var UnitOfFrequency;
(function (UnitOfFrequency) {
UnitOfFrequency["HERTZ"] = "Hz";
UnitOfFrequency["KILOHERTZ"] = "kHz";
UnitOfFrequency["MEGAHERTZ"] = "MHz";
UnitOfFrequency["GIGAHERTZ"] = "GHz";
})(UnitOfFrequency || (UnitOfFrequency = {}));
export var UnitOfPressure;
(function (UnitOfPressure) {
UnitOfPressure["MILLIPASCAL"] = "mPa";
UnitOfPressure["PA"] = "Pa";
UnitOfPressure["HPA"] = "hPa";
UnitOfPressure["KPA"] = "kPa";
UnitOfPressure["BAR"] = "bar";
UnitOfPressure["CBAR"] = "cbar";
UnitOfPressure["MBAR"] = "mbar";
UnitOfPressure["MMHG"] = "mmHg";
UnitOfPressure["INHG"] = "inHg";
UnitOfPressure["INH2O"] = "inH\u2082O";
UnitOfPressure["PSI"] = "psi";
})(UnitOfPressure || (UnitOfPressure = {}));
export var UnitOfSoundPressure;
(function (UnitOfSoundPressure) {
UnitOfSoundPressure["DECIBEL"] = "dB";
UnitOfSoundPressure["WEIGHTED_DECIBEL_A"] = "dBA";
})(UnitOfSoundPressure || (UnitOfSoundPressure = {}));
export var UnitOfVolume;
(function (UnitOfVolume) {
UnitOfVolume["CUBIC_FEET"] = "ft\u00B3";
UnitOfVolume["CENTUM_CUBIC_FEET"] = "CCF";
UnitOfVolume["MILLE_CUBIC_FEET"] = "MCF";
UnitOfVolume["CUBIC_METERS"] = "m\u00B3";
UnitOfVolume["LITERS"] = "L";
UnitOfVolume["MILLILITERS"] = "mL";
UnitOfVolume["GALLONS"] = "gal";
UnitOfVolume["FLUID_OUNCES"] = "fl. oz.";
})(UnitOfVolume || (UnitOfVolume = {}));
export var UnitOfVolumeFlowRate;
(function (UnitOfVolumeFlowRate) {
UnitOfVolumeFlowRate["CUBIC_METERS_PER_HOUR"] = "m\u00B3/h";
UnitOfVolumeFlowRate["CUBIC_METERS_PER_MINUTE"] = "m\u00B3/min";
UnitOfVolumeFlowRate["CUBIC_METERS_PER_SECOND"] = "m\u00B3/s";
UnitOfVolumeFlowRate["CUBIC_FEET_PER_MINUTE"] = "ft\u00B3/min";
UnitOfVolumeFlowRate["LITERS_PER_HOUR"] = "L/h";
UnitOfVolumeFlowRate["LITERS_PER_MINUTE"] = "L/min";
UnitOfVolumeFlowRate["LITERS_PER_SECOND"] = "L/s";
UnitOfVolumeFlowRate["GALLONS_PER_HOUR"] = "gal/h";
UnitOfVolumeFlowRate["GALLONS_PER_MINUTE"] = "gal/min";
UnitOfVolumeFlowRate["GALLONS_PER_DAY"] = "gal/d";
UnitOfVolumeFlowRate["MILLILITERS_PER_SECOND"] = "mL/s";
})(UnitOfVolumeFlowRate || (UnitOfVolumeFlowRate = {}));
export var UnitOfArea;
(function (UnitOfArea) {
UnitOfArea["SQUARE_METERS"] = "m\u00B2";
UnitOfArea["SQUARE_CENTIMETERS"] = "cm\u00B2";
UnitOfArea["SQUARE_KILOMETERS"] = "km\u00B2";
UnitOfArea["SQUARE_MILLIMETERS"] = "mm\u00B2";
UnitOfArea["SQUARE_INCHES"] = "in\u00B2";
UnitOfArea["SQUARE_FEET"] = "ft\u00B2";
UnitOfArea["SQUARE_YARDS"] = "yd\u00B2";
UnitOfArea["SQUARE_MILES"] = "mi\u00B2";
UnitOfArea["ACRES"] = "ac";
UnitOfArea["HECTARES"] = "ha";
})(UnitOfArea || (UnitOfArea = {}));
export var UnitOfMass;
(function (UnitOfMass) {
UnitOfMass["GRAMS"] = "g";
UnitOfMass["KILOGRAMS"] = "kg";
UnitOfMass["MILLIGRAMS"] = "mg";
UnitOfMass["MICROGRAMS"] = "\u03BCg";
UnitOfMass["OUNCES"] = "oz";
UnitOfMass["POUNDS"] = "lb";
UnitOfMass["STONES"] = "st";
})(UnitOfMass || (UnitOfMass = {}));
export var UnitOfConductivity;
(function (UnitOfConductivity) {
UnitOfConductivity["SIEMENS_PER_CM"] = "S/cm";
UnitOfConductivity["MICROSIEMENS_PER_CM"] = "\u03BCS/cm";
UnitOfConductivity["MILLISIEMENS_PER_CM"] = "mS/cm";
})(UnitOfConductivity || (UnitOfConductivity = {}));
export class HomeAssistant extends EventEmitter {
connected = false;
ws = null;
wsUrl;
wsAccessToken;
log;
hassDevices = new Map();
hassEntities = new Map();
hassStates = new Map();
hassAreas = new Map();
hassLabels = new Map();
hassServices = null;
hassConfig = null;
static hassConfig = null;
debug = hasParameter('debug') || hasParameter('verbose');
verbose = hasParameter('verbose');
pingInterval = undefined;
pingTimeout = undefined;
reconnectTimeout = undefined;
pingIntervalTime = 30000;
pingTimeoutTime = 35000;
reconnectTimeoutTime = 60000;
reconnectRetries = 10;
_responseTimeout = 5000;
certificatePath = undefined;
rejectUnauthorized = undefined;
reconnectRetry = 1;
requestId = 1;
fetchTimeout = undefined;
fetchQueue = new Set();
emit(eventName, ...args) {
return super.emit(eventName, ...args);
}
on(eventName, listener) {
return super.on(eventName, listener);
}
get responseTimeout() {
return this._responseTimeout;
}
set responseTimeout(value) {
this._responseTimeout = value;
}
constructor(url, accessToken, reconnectTimeoutTime = 60, reconnectRetries = 10, certificatePath = undefined, rejectUnauthorized = undefined) {
super();
this.wsUrl = url;
this.wsAccessToken = accessToken;
this.reconnectTimeoutTime = reconnectTimeoutTime * 1000;
this.reconnectRetries = reconnectRetries;
this.certificatePath = certificatePath;
this.rejectUnauthorized = rejectUnauthorized;
this.log = new AnsiLogger({
logName: 'HomeAssistant',
logTimestampFormat: 4,
logLevel: this.debug ? "debug" : "info",
});
}
onOpen = () => {
this.log.debug('WebSocket connection established');
this.emit('socket_opened');
};
onPing(data) {
this.log.debug('WebSocket ping received');
if (this.pingTimeout) {
clearTimeout(this.pingTimeout);
this.pingTimeout = undefined;
this.log.debug('Stopped ping timeout');
}
this.emit('ping', data);
}
onPong(data) {
this.log.debug('WebSocket pong received');
if (this.pingTimeout) {
clearTimeout(this.pingTimeout);
this.pingTimeout = undefined;
this.log.debug('Stopped ping timeout');
}
this.emit('pong', data);
}
onError(error) {
const errorMessage = `WebSocket error: ${error}`;
this.log.debug(errorMessage);
this.emit('error', errorMessage);
}
onMessage(data, isBinary) {
let response;
try {
response = JSON.parse(isBinary ? data.toString() : data);
}
catch (error) {
this.log.error(`Error parsing WebSocket message: ${error}`);
return;
}
if (response.type === 'pong') {
this.log.debug(`Home Assistant pong received with id ${response.id}`);
if (this.pingTimeout) {
clearTimeout(this.pingTimeout);
this.pingTimeout = undefined;
this.log.debug('Stopped ping timeout');
}
this.emit('pong', Buffer.from('Home Assistant pong received'));
}
else if (response.type === 'event') {
if (!response.event) {
const errorMessage = `WebSocket event response missing event data for id ${response.id}`;
this.log.error(errorMessage);
this.emit('error', errorMessage);
return;
}
if (this.verbose)
this.log.debug(`Event ${CYAN}${response.event.event_type}${db} received id ${CYAN}${response.id}${db}:${rs}\n${debugStringify(response.event)}`);
if (response.event.event_type === 'state_changed') {
const entity = this.hassEntities.get(response.event.data.entity_id);
if (!entity) {
this.log.debug(`Entity id ${CYAN}${response.event.data.entity_id}${db} not found processing event`);
return;
}
if (response.event.data.old_state && response.event.data.new_state) {
this.hassStates.set(response.event.data.new_state.entity_id, response.event.data.new_state);
this.emit('event', entity.device_id, entity.entity_id, response.event.data.old_state, response.event.data.new_state);
}
}
else if (response.event.event_type === 'call_service') {
this.log.debug(`Event ${CYAN}${response.event.event_type}${db} received id ${CYAN}${response.id}${db}`);
this.emit('call_service');
}
else if (response.event.event_type === 'core_config_updated') {
this.log.debug(`Event ${CYAN}${response.event.event_type}${db} received id ${CYAN}${response.id}${db}`);
clearTimeout(this.fetchTimeout);
this.fetchTimeout = setTimeout(() => void this.onFetchTimeout(), 5000).unref();
this.fetchQueue.add('get_config');
}
else if (response.event.event_type === 'device_registry_updated') {
this.log.debug(`Event ${CYAN}${response.event.event_type}${db} received id ${CYAN}${response.id}${db}`);
clearTimeout(this.fetchTimeout);
this.fetchTimeout = setTimeout(() => void this.onFetchTimeout(), 5000).unref();
this.fetchQueue.add('config/device_registry/list');
}
else if (response.event.event_type === 'entity_registry_updated') {
this.log.debug(`Event ${CYAN}${response.event.event_type}${db} received id ${CYAN}${response.id}${db}`);
clearTimeout(this.fetchTimeout);
this.fetchTimeout = setTimeout(() => void this.onFetchTimeout(), 5000).unref();
this.fetchQueue.add('config/entity_registry/list');
}
else if (response.event.event_type === 'area_registry_updated') {
this.log.debug(`Event ${CYAN}${response.event.event_type}${db} received id ${CYAN}${response.id}${db}`);
clearTimeout(this.fetchTimeout);
this.fetchTimeout = setTimeout(() => void this.onFetchTimeout(), 5000).unref();
this.fetchQueue.add('config/area_registry/list');
}
else if (response.event.event_type === 'label_registry_updated') {
this.log.debug(`Event ${CYAN}${response.event.event_type}${db} received id ${CYAN}${response.id}${db}`);
clearTimeout(this.fetchTimeout);
this.fetchTimeout = setTimeout(() => void this.onFetchTimeout(), 5000).unref();
this.fetchQueue.add('config/label_registry/list');
}
else {
if (this.debug)
this.log.debug(`Unknown event type ${CYAN}${response.event.event_type}${db} received id ${CYAN}${response.id}${db}`);
}
}
}
onClose(code, reason) {
const closeMessage = `WebSocket connection closed. Code: ${code} Reason: ${reason.toString()}`;
this.log.debug(closeMessage);
this.connected = false;
this.stopPing();
this.emit('socket_closed', code, reason);
this.emit('disconnected', `Code: ${code} Reason: ${reason.toString()}`);
this.startReconnect();
}
async onFetchTimeout() {
this.fetchTimeout = undefined;
this.log.debug(`Fetch timeout reached, processing fetch queue of ${this.fetchQueue.size} fetch id(s)...`);
for (const fetchId of this.fetchQueue) {
this.log.debug(`Fetching ${CYAN}${fetchId}${db}...`);
try {
const data = await this.fetch(fetchId);
this.log.debug(`Received data for ${CYAN}${fetchId}${db}`);
if (fetchId === 'get_config') {
const config = data;
this.log.debug(`Received config.`);
this.hassConfig = config;
HomeAssistant.hassConfig = this.hassConfig;
this.emit('config', config);
}
else if (fetchId === 'config/device_registry/list') {
const devices = data;
this.log.debug(`Received ${devices.length} devices.`);
devices.forEach((device) => this.hassDevices.set(device.id, device));
this.emit('devices', devices);
}
else if (fetchId === 'config/entity_registry/list') {
const entities = data;
this.log.debug(`Received ${entities.length} entities.`);
entities.forEach((entity) => this.hassEntities.set(entity.entity_id, entity));
this.emit('entities', entities);
}
else if (fetchId === 'config/area_registry/list') {
const areas = data;
this.log.debug(`Received ${areas.length} areas.`);
areas.forEach((area) => this.hassAreas.set(area.area_id, area));
this.emit('areas', areas);
}
else if (fetchId === 'config/label_registry/list') {
const labels = data;
this.log.debug(`Received ${labels.length} labels.`);
labels.forEach((label) => this.hassLabels.set(label.label_id, label));
this.emit('labels', labels);
}
}
catch (error) {
this.log.error(`Error fetching ${CYAN}${fetchId}${er}: ${error}`);
}
this.fetchQueue.delete(fetchId);
}
}
connect() {
return new Promise((resolve, reject) => {
if (this.connected) {
return reject(new Error('Already connected to Home Assistant'));
}
try {
this.log.info(`Connecting to Home Assistant on ${this.wsUrl}...`);
if (this.wsUrl.startsWith('ws://')) {
this.ws = new WebSocket(this.wsUrl + '/api/websocket');
}
else if (this.wsUrl.startsWith('wss://')) {
let ca;
if (this.certificatePath) {
this.log.debug(`Loading CA certificate from ${this.certificatePath}...`);
ca = readFileSync(this.certificatePath);
this.log.debug(`CA certificate loaded successfully`);
}
this.ws = new WebSocket(this.wsUrl + '/api/websocket', {
ca,
rejectUnauthorized: this.rejectUnauthorized,
});
}
else {
return reject(new Error(`Invalid WebSocket URL: ${this.wsUrl}. It must start with ws:// or wss://`));
}
this.ws.on('open', this.onOpen.bind(this));
this.ws.on('ping', this.onPing.bind(this));
this.ws.on('pong', this.onPong.bind(this));
this.ws.on('close', this.onClose.bind(this));
this.ws.onerror = (event) => {
this.log.error(`WebSocket error: ${event.message}`);
this.emit('error', `WebSocket error: ${event.message}`);
return reject(new Error(`WebSocket error: ${event.message}`));
};
this.ws.onmessage = (event) => {
let response;
try {
response = JSON.parse(event.data.toString());
}
catch (error) {
return reject(new Error(`Error parsing WebSocket message: ${error}`));
}
if (response.type === 'auth_required') {
this.log.debug(`Authentication required: ${debugStringify(response)}`);
this.log.debug('Authentication required. Sending auth message...');
this.ws?.send(JSON.stringify({
type: 'auth',
access_token: this.wsAccessToken,
}));
}
else if (response.type === 'auth_ok') {
this.log.debug(`Authenticated successfully: ${debugStringify(response)}`);
this.log.debug(`Authenticated successfully with Home Assistant v. ${response.ha_version}`);
this.connected = true;
this.reconnectRetry = 1;
if (this.ws)
this.ws.onmessage = null;
this.ws?.on('message', this.onMessage.bind(this));
if (this.ws)
this.ws.onerror = null;
this.ws?.on('error', this.onError.bind(this));
this.startPing();
this.emit('connected', response.ha_version);
return resolve(response.ha_version);
}
};
}
catch (error) {
const errorMessage = `WebSocket error connecting to Home Assistant: ${error}`;
this.log.debug(errorMessage);
return reject(new Error(errorMessage));
}
});
}
startPing() {
if (this.pingInterval) {
this.log.debug('Ping interval already started');
return;
}
this.log.debug('Starting ping interval...');
this.pingInterval = setInterval(() => {
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
this.log.error('WebSocket not open sending ping. Closing connection...');
void this.close().catch(() => { });
return;
}
this.log.debug(`Sending WebSocket ping...`);
this.ws.ping();
this.log.debug(`Sending Home Assistant ping id ${this.requestId}...`);
this.ws.send(JSON.stringify({
id: this.requestId++,
type: 'ping',
}));
this.log.debug('Starting ping timeout...');
this.pingTimeout = setTimeout(() => {
this.log.error('Ping timeout. Closing connection...');
void this.close().catch(() => { });
this.startReconnect();
}, this.pingTimeoutTime).unref();
this.log.debug('Started ping timeout');
}, this.pingIntervalTime).unref();
this.log.debug('Started ping interval');
}
stopPing() {
this.log.debug('Stopping ping interval...');
if (this.pingInterval) {
clearInterval(this.pingInterval);
this.pingInterval = undefined;
}
this.log.debug('Stopped ping interval');
this.log.debug('Stopping ping timeout...');
if (this.pingTimeout) {
clearTimeout(this.pingTimeout);
this.pingTimeout = undefined;
}
this.log.debug('Stopped ping timeout');
}
startReconnect() {
if (this.reconnectTimeout) {
this.log.debug(`Reconnecting already in progress.`);
return;
}
if (this.reconnectTimeoutTime && this.reconnectRetry <= this.reconnectRetries) {
this.log.notice(`Reconnecting in ${this.reconnectTimeoutTime / 1000} seconds...`);
this.reconnectTimeout = setTimeout(() => {
const attempt = this.reconnectRetry;
this.log.notice(`Reconnecting attempt ${attempt} of ${this.reconnectRetries}...`);
void this.connect().catch((error) => {
const errorMessage = error instanceof Error ? error.message : String(error);
this.log.debug(`Reconnection attempt ${attempt} failed: ${errorMessage}`);
});
this.reconnectRetry++;
this.reconnectTimeout = undefined;
}, this.reconnectTimeoutTime).unref();
}
else {
this.log.error('Restart the plugin to reconnect.');
}
}
close(code = 1000, reason = 'Normal closure') {
return new Promise((resolve, reject) => {
this.log.info('Closing Home Assistant connection...');
this.stopPing();
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
this.reconnectTimeout = undefined;
}
const cleanup = () => {
clearTimeout(timer);
this.ws?.removeAllListeners();
this.ws = null;
this.connected = false;
this.emit('disconnected', 'WebSocket connection closed');
this.log.info('Home Assistant connection closed');
};
const timer = setTimeout(() => {
const message = `Close did not complete before the timeout of ${this._responseTimeout} ms`;
this.log.debug(message);
cleanup();
return reject(new Error(message));
}, this._responseTimeout).unref();
const onClose = () => {
this.log.debug('Close received closed event from Home Assistant');
this.emit('socket_closed', code, Buffer.from(reason));
cleanup();
return resolve();
};
const onError = () => {
const message = 'Close received error event while closing connection to Home Assistant';
this.log.debug(message);
cleanup();
return reject(new Error(message));
};
if (this.ws) {
this.ws.removeAllListeners();
this.ws.onclose = onClose;
this.ws.onerror = onError;
}
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.log.debug('Close websocket is open, closing...');
this.ws.close(code, reason);
}
else {
this.log.debug('Close websocket is not open, resolving...');
cleanup();
return resolve();
}
});
}
async fetchData() {
try {
this.log.debug('Fetching initial data from Home Assistant...');
this.hassConfig = (await this.fetch('get_config'));
HomeAssistant.hassConfig = this.hassConfig;
this.log.debug('Received config.');
this.emit('config', this.hassConfig);
let retries = 1;
while (this.hassConfig.state !== 'RUNNING' && retries <= 100) {
this.log.debug(`State is ${CYAN}${this.hassConfig.state}${db}. Waiting (${retries}/100) for Home Assistant to be RUNNING...`);
retries += 1;
await new Promise((resolve) => setTimeout(resolve, 1000));
this.hassConfig = (await this.fetch('get_config'));
HomeAssistant.hassConfig = this.hassConfig;
this.emit('config', this.hassConfig);
}
this.hassServices = (await this.fetch('get_services'));
this.log.debug('Received services.');
this.emit('services', this.hassServices);
const devices = (await this.fetch('config/device_registry/list'));
devices.forEach((device) => this.hassDevices.set(device.id, device));
this.log.debug(`Received ${devices.length} devices.`);
this.emit('devices', devices);
const entities = (await this.fetch('config/entity_registry/list'));
entities.forEach((entity) => this.hassEntities.set(entity.entity_id, entity));
this.log.debug(`Received ${entities.length} entities.`);
this.emit('entities', entities);
const states = (await this.fetch('get_states'));
states.forEach((state) => this.hassStates.set(state.entity_id, state));
this.log.debug(`Received ${states.length} states.`);
this.emit('states', states);
const areas = (await this.fetch('config/area_registry/list'));
areas.forEach((area) => this.hassAreas.set(area.area_id, area));
this.log.debug(`Received ${areas.length} areas.`);
this.emit('areas', areas);
const labels = (await this.fetch('config/label_registry/list'));
labels.forEach((label) => this.hassLabels.set(label.label_id, label));
this.log.debug(`Received ${labels.length} labels.`);
this.emit('labels', labels);
this.log.debug('Initial data fetched successfully.');
}
catch (error) {
this.log.error(`Error fetching initial data: ${error}`);
}
}
fetch(type) {
return new Promise((resolve, reject) => {
if (!this.connected) {
return reject(new Error('Fetch error: not connected to Home Assistant'));
}
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
return reject(new Error('Fetch error: WebSocket not open'));
}
const requestId = this.requestId++;
const timer = setTimeout(() => {
this.ws?.removeEventListener('message', handleMessage);
return reject(new Error(`Fetch type ${type} id ${requestId} did not complete before the timeout`));
}, this._responseTimeout).unref();
const handleMessage = (event) => {
try {
const response = JSON.parse(event.data.toString());
if (response.type === 'result' && response.id === requestId) {
clearTimeout(timer);
this.ws?.removeEventListener('message', handleMessage);
if (response.success) {
return resolve(response.result);
}
else {
return reject(new Error(response.error?.message));
}
}
}
catch (error) {
clearTimeout(timer);
this.ws?.removeEventListener('message', handleMessage);
reject(error);
}
};
this.ws.addEventListener('message', handleMessage);
this.log.debug(`Fetching ${CYAN}${type}${db} with id ${CYAN}${requestId}${db} and timeout ${CYAN}${this._responseTimeout}${db} ms ...`);
this.ws.send(JSON.stringify({ id: requestId, type }));
});
}
subscribe(event) {
return new Promise((resolve, reject) => {
if (!this.connected) {
return reject(new Error('Subscribe error: not connected to Home Assistant'));
}
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
return reject(new Error('Subscribe error: WebSocket not open'));
}
const requestId = this.requestId++;
const timer = setTimeout(() => {
this.ws?.removeEventListener('message', handleMessage);
return reject(new Error(`Subscribe event ${event} id ${requestId} did not complete before the timeout`));
}, this._responseTimeout).unref();
const handleMessage = (event) => {
try {
const response = JSON.parse(event.data.toString());
if (response.type === 'result' && response.id === requestId) {
clearTimeout(timer);
this.ws?.removeEventListener('message', handleMessage);
if (response.success) {
this.log.debug(`Subscribed successfully with id ${CYAN}${requestId}${db}`);
return resolve(response.id);
}
else {
return reject(new Error(response.error?.message));
}
}
}
catch (error) {
clearTimeout(timer);
this.ws?.removeEventListener('message', handleMessage);
reject(error);
}
};
this.ws.addEventListener('message', handleMessage);
this.log.debug(`Subscribing to ${CYAN}${event ?? 'all events'}${db} with id ${CYAN}${requestId}${db} and timeout ${CYAN}${this._responseTimeout}${db} ms ...`);
this.ws.send(JSON.stringify({
id: requestId,
type: 'subscribe_events',
event_type: event,
}));
});
}
unsubscribe(subscriptionId) {
return new Promise((resolve, reject) => {
if (!this.connected) {
return reject(new Error('Unsubscribe error: not connected to Home Assistant'));
}
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
return reject(new Error('Unsubscribe error: WebSocket not open'));
}
const requestId = this.requestId++;
const timer = setTimeout(() => {
this.ws?.removeEventListener('message', handleMessage);
return reject(new Error(`Unsubscri