UNPKG

eufy-security-client

Version:

Client to comunicate with Eufy-Security devices

897 lines (896 loc) 635 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Station = void 0; const tiny_typed_emitter_1 = require("tiny-typed-emitter"); const date_and_time_1 = __importDefault(require("date-and-time")); const types_1 = require("./types"); const parameter_1 = require("./parameter"); const utils_1 = require("./utils"); const session_1 = require("../p2p/session"); const types_2 = require("../p2p/types"); const device_1 = require("./device"); const utils_2 = require("../p2p/utils"); const error_1 = require("../error"); const types_3 = require("../push/types"); const error_2 = require("./error"); const utils_3 = require("../utils"); const repl_1 = require("repl"); const logging_1 = require("../logging"); class Station extends tiny_typed_emitter_1.TypedEmitter { api; rawStation; p2pSession; properties = {}; rawProperties = {}; ready = false; lockPublicKey; currentDelay = 0; reconnectTimeout; terminating = false; p2pConnectionType = types_2.P2PConnectionType.QUICKEST; static CHANNEL = 255; static CHANNEL_INDOOR = 1000; pinVerified = false; constructor(api, station, ipAddress, listeningPort = 0, publicKey = "", enableEmbeddedPKCS1Support = false) { super(); this.api = api; this.rawStation = station; this.lockPublicKey = publicKey; this.p2pSession = new session_1.P2PClientProtocol(this.rawStation, this.api, ipAddress, listeningPort, publicKey, enableEmbeddedPKCS1Support); this.p2pSession.on("connect", (address) => this.onConnect(address)); this.p2pSession.on("close", () => this.onDisconnect()); this.p2pSession.on("timeout", () => this.onTimeout()); this.p2pSession.on("command", (result) => this.onCommandResponse(result)); this.p2pSession.on("alarm mode", (mode) => this.onAlarmMode(mode)); this.p2pSession.on("camera info", (cameraInfo) => this.onCameraInfo(cameraInfo)); this.p2pSession.on("download started", (channel, metadata, videoStream, audioStream) => this.onStartDownload(channel, metadata, videoStream, audioStream)); this.p2pSession.on("download finished", (channel) => this.onFinishDownload(channel)); this.p2pSession.on("livestream started", (channel, metadata, videoStream, audioStream) => this.onStartLivestream(channel, metadata, videoStream, audioStream)); this.p2pSession.on("livestream stopped", (channel) => this.onStopLivestream(channel)); this.p2pSession.on("livestream error", (channel, error) => this.onErrorLivestream(channel, error)); this.p2pSession.on("wifi rssi", (channel, rssi) => this.onWifiRssiChanged(channel, rssi)); this.p2pSession.on("rtsp livestream started", (channel) => this.onStartRTSPLivestream(channel)); this.p2pSession.on("rtsp livestream stopped", (channel) => this.onStopRTSPLivestream(channel)); this.p2pSession.on("rtsp url", (channel, rtspUrl) => this.onRTSPUrl(channel, rtspUrl)); this.p2pSession.on("parameter", (channel, param, value) => this.onParameter(channel, param, value)); this.p2pSession.on("runtime state", (channel, batteryLevel, temperature) => this.onRuntimeState(channel, batteryLevel, temperature)); this.p2pSession.on("charging state", (channel, chargeType, batteryLevel) => this.onChargingState(channel, chargeType, batteryLevel)); this.p2pSession.on("floodlight manual switch", (channel, enabled) => this.onFloodlightManualSwitch(channel, enabled)); this.p2pSession.on("alarm delay", (alarmDelayEvent, alarmDelay) => this.onAlarmDelay(alarmDelayEvent, alarmDelay)); this.p2pSession.on("alarm armed", () => this.onAlarmArmed()); this.p2pSession.on("alarm event", (alarmEvent) => this.onAlarmEvent(alarmEvent)); this.p2pSession.on("talkback started", (channel, talkbackStream) => this.onTalkbackStarted(channel, talkbackStream)); this.p2pSession.on("talkback stopped", (channel) => this.onTalkbackStopped(channel)); this.p2pSession.on("talkback error", (channel, error) => this.onTalkbackError(channel, error)); this.p2pSession.on("secondary command", (result) => this.onSecondaryCommandResponse(result)); this.p2pSession.on("shake alarm", (channel, event) => this.onDeviceShakeAlarm(channel, event)); this.p2pSession.on("911 alarm", (channel, event) => this.onDevice911Alarm(channel, event)); this.p2pSession.on("jammed", (channel) => this.onDeviceJammed(channel)); this.p2pSession.on("low battery", (channel) => this.onDeviceLowBattery(channel)); this.p2pSession.on("wrong try-protect alarm", (channel) => this.onDeviceWrongTryProtectAlarm(channel)); this.p2pSession.on("sd info ex", (sdStatus, sdCapacity, sdCapacityAvailable) => this.onSdInfoEx(sdStatus, sdCapacity, sdCapacityAvailable)); this.p2pSession.on("image download", (file, image) => this.onImageDownload(file, image)); this.p2pSession.on("tfcard status", (channel, status) => this.onTFCardStatus(channel, status)); this.p2pSession.on("database query latest", (returnCode, data) => this.onDatabaseQueryLatest(returnCode, data)); this.p2pSession.on("database query local", (returnCode, data) => this.onDatabaseQueryLocal(returnCode, data)); this.p2pSession.on("database count by date", (returnCode, data) => this.onDatabaseCountByDate(returnCode, data)); this.p2pSession.on("database delete", (returnCode, failedIds) => this.onDatabaseDelete(returnCode, failedIds)); this.p2pSession.on("sensor status", (channel, status) => this.onSensorStatus(channel, status)); this.p2pSession.on("garage door status", (channel, doorId, status) => this.onGarageDoorStatus(channel, doorId, status)); this.p2pSession.on("storage info hb3", (channel, storageInfo) => this.onStorageInfoHB3(channel, storageInfo)); this.p2pSession.on("sequence error", (channel, command, sequence, serialnumber) => this.onSequenceError(channel, command, sequence, serialnumber)); } initializeState() { this.update(this.rawStation); this.ready = true; setImmediate(() => { this.emit("ready", this); }); } initialize() { this.initializeState(); } static async getInstance(api, stationData, ipAddress, listeningPort, enableEmbeddedPKCS1Support) { let publicKey; if (device_1.Device.isLock(stationData.device_type) && !device_1.Device.isLockWifiT8506(stationData.device_type) && !device_1.Device.isLockWifiT8502(stationData.device_type) && !device_1.Device.isLockWifiT8510P(stationData.device_type, stationData.station_sn) && !device_1.Device.isLockWifiT8520P(stationData.device_type, stationData.station_sn)) { publicKey = await api.getPublicKey(stationData.station_sn, types_1.PublicKeyType.LOCK); } return new Station(api, stationData, ipAddress, listeningPort, publicKey, enableEmbeddedPKCS1Support); } //TODO: To remove getStateID(state, level = 2) { switch (level) { case 0: return `${this.getSerial()}`; case 1: return `${this.getSerial()}.${this.getStateChannel()}`; default: if (state) return `${this.getSerial()}.${this.getStateChannel()}.${state}`; throw new Error("No state value passed."); } } getStateChannel() { return "station"; } getRawStation() { return this.rawStation; } update(station) { this.rawStation = station; this.p2pSession.updateRawStation(station); const metadata = this.getPropertiesMetadata(true); for (const property of Object.values(metadata)) { if (this.rawStation[property.key] !== undefined && typeof property.key === "string") { this.updateProperty(property.name, this.convertRawPropertyValue(property, this.rawStation[property.key])); } else if (this.properties[property.name] === undefined && property.default !== undefined && !this.ready) { this.updateProperty(property.name, property.default); } } if (this.rawStation.params) { this.rawStation.params.forEach(param => { this.updateRawProperty(param.param_type, param.param_value, "http"); }); } logging_1.rootHTTPLogger.debug("Update station cloud properties", { stationSN: this.getSerial(), properties: this.properties }); } updateProperty(name, value, force = false) { if ((this.properties[name] !== undefined && this.properties[name] !== value) || this.properties[name] === undefined || force) { const oldValue = this.properties[name]; this.properties[name] = value; this.emit("property changed", this, name, value, this.ready); try { this.handlePropertyChange(this.getPropertyMetadata(name, true), oldValue, this.properties[name]); } catch (err) { const error = (0, error_1.ensureError)(err); if (error instanceof error_2.InvalidPropertyError) { logging_1.rootHTTPLogger.error(`Station update property - Invalid Property error`, { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), propertyName: name, propertyValue: value, force: force }); } else { logging_1.rootHTTPLogger.error(`Station update property - Property error`, { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), propertyName: name, propertyValue: value, force: force }); } } return true; } return false; } updateRawProperties(values) { Object.keys(values).forEach(paramtype => { const param_type = Number.parseInt(paramtype); this.updateRawProperty(param_type, values[param_type].value, values[param_type].source); }); } // eslint-disable-next-line @typescript-eslint/no-unused-vars handlePropertyChange(metadata, oldValue, newValue) { if (metadata.name === types_1.PropertyName.StationCurrentMode) { //TODO: Finish implementation! if (newValue === types_1.AlarmMode.DISARMED) { if (this.hasProperty(types_1.PropertyName.StationAlarmArmed)) { this.updateProperty(types_1.PropertyName.StationAlarmArmed, false); } if (this.hasProperty(types_1.PropertyName.StationAlarmDelay)) { this.updateProperty(types_1.PropertyName.StationAlarmDelay, 0); } if (this.hasProperty(types_1.PropertyName.StationAlarmDelayType)) { this.updateProperty(types_1.PropertyName.StationAlarmDelayType, 0); } if (this.hasProperty(types_1.PropertyName.StationAlarm)) { this.updateProperty(types_1.PropertyName.StationAlarm, false); } if (this.hasProperty(types_1.PropertyName.StationAlarmType)) { this.updateProperty(types_1.PropertyName.StationAlarmType, 0); } } /*else if (this.hasProperty(PropertyName.StationAlarmArmed)) { //TODO: Type !== HB3 or STATION this.updateProperty(PropertyName.StationAlarmArmed, this.isAlarmArmable(newValue as AlarmMode)); }*/ } } updateRawProperty(type, value, source) { const parsedValue = parameter_1.ParameterHelper.readValue(this.getSerial(), type, value, logging_1.rootHTTPLogger); if (parsedValue !== undefined && ((this.rawProperties[type] !== undefined && this.rawProperties[type].value !== parsedValue && (0, utils_1.isPrioritySourceType)(this.rawProperties[type].source, source)) || this.rawProperties[type] === undefined)) { this.rawProperties[type] = { value: parsedValue, source: source }; if (this.ready) { this.emit("raw property changed", this, type, this.rawProperties[type].value); try { if (type === types_1.ParamType.GUARD_MODE) { this.emit("guard mode", this, Number.parseInt(parsedValue)); } else if (type === types_2.CommandType.CMD_GET_ALARM_MODE) { this.emit("current mode", this, Number.parseInt(parsedValue)); } } catch (err) { const error = (0, error_1.ensureError)(err); logging_1.rootHTTPLogger.error("Station update raw property - Number conversion error", { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), type: type, value: value, source: source }); } } const metadata = this.getPropertiesMetadata(true); for (const property of Object.values(metadata)) { if (property.key === type) { try { this.updateProperty(property.name, this.convertRawPropertyValue(property, this.rawProperties[type].value)); } catch (err) { const error = (0, error_1.ensureError)(err); if (error instanceof error_2.PropertyNotSupportedError) { logging_1.rootHTTPLogger.debug("Station update raw property - Property not supported error", { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), type: type, value: value, source: source }); } else { logging_1.rootHTTPLogger.error("Station update raw property - Property error", { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), type: type, value: value, source: source }); } } } } return true; } return false; } convertRawPropertyValue(property, value) { try { switch (property.key) { case types_2.CommandType.CMD_GET_HUB_LAN_IP: return value !== undefined ? ((0, utils_2.isPrivateIp)(value) ? value : "") : ""; case types_2.CommandType.CMD_SET_ARMING: return Number.parseInt(value !== undefined ? value : "-1"); case types_2.CommandType.CMD_GET_ALARM_MODE: { const guard_mode = this.getGuardMode(); return Number.parseInt(value !== undefined ? value : guard_mode !== undefined && guard_mode !== types_1.GuardMode.SCHEDULE && guard_mode !== types_1.GuardMode.GEO ? guard_mode : types_1.GuardMode.UNKNOWN.toString()); } case types_2.CommandType.CMD_HUB_NOTIFY_MODE: { switch (property.name) { case types_1.PropertyName.StationNotificationSwitchModeSchedule: if (!(0, utils_1.isGreaterEqualMinVersion)("2.1.1.6", this.getSoftwareVersion())) { return value !== undefined ? (value === "1" ? true : false) : false; } return value !== undefined ? (0, utils_1.isNotificationSwitchMode)(Number.parseInt(value), types_1.NotificationSwitchMode.SCHEDULE) : false; case types_1.PropertyName.StationNotificationSwitchModeGeofence: if (!(0, utils_1.isGreaterEqualMinVersion)("2.1.1.6", this.getSoftwareVersion())) { throw new error_2.PropertyNotSupportedError("Property not supported for station with this software version", { context: { propertName: property.name, station: this.getSerial(), softwareVersion: this.getSoftwareVersion() } }); } return value !== undefined ? (0, utils_1.isNotificationSwitchMode)(Number.parseInt(value), types_1.NotificationSwitchMode.GEOFENCE) : false; case types_1.PropertyName.StationNotificationSwitchModeApp: if (!(0, utils_1.isGreaterEqualMinVersion)("2.1.1.6", this.getSoftwareVersion())) { throw new error_2.PropertyNotSupportedError("Property not supported for station with this software version", { context: { propertName: property.name, station: this.getSerial(), softwareVersion: this.getSoftwareVersion() } }); } return value !== undefined ? (0, utils_1.isNotificationSwitchMode)(Number.parseInt(value), types_1.NotificationSwitchMode.APP) : false; case types_1.PropertyName.StationNotificationSwitchModeKeypad: if (!(0, utils_1.isGreaterEqualMinVersion)("2.1.1.6", this.getSoftwareVersion())) { throw new error_2.PropertyNotSupportedError("Property not supported for station with this software version", { context: { propertName: property.name, station: this.getSerial(), softwareVersion: this.getSoftwareVersion() } }); } return value !== undefined ? (0, utils_1.isNotificationSwitchMode)(Number.parseInt(value), types_1.NotificationSwitchMode.KEYPAD) : false; } } case types_2.CommandType.CMD_HUB_NOTIFY_ALARM: return value !== undefined ? (value === "1" ? true : false) : false; case types_2.CommandType.CMD_HUB_ALARM_TONE: try { return value !== undefined ? Number.parseInt(value) : 1; } catch (err) { const error = (0, error_1.ensureError)(err); logging_1.rootHTTPLogger.error("Station convert raw property - CMD_HUB_ALARM_TONE Error", { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), property: property, value: value }); return 1; } case types_2.CommandType.CMD_SET_HUB_SPK_VOLUME: try { return value !== undefined ? Number.parseInt(value) : 26; } catch (err) { const error = (0, error_1.ensureError)(err); logging_1.rootHTTPLogger.error("Station convert raw property - CMD_SET_HUB_SPK_VOLUME Error", { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), property: property, value: value }); return 26; } case types_2.CommandType.CMD_SET_PROMPT_VOLUME: try { return value !== undefined ? Number.parseInt(value) : 26; } catch (err) { const error = (0, error_1.ensureError)(err); logging_1.rootHTTPLogger.error("Station convert raw property - CMD_SET_PROMPT_VOLUME Error", { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), property: property, value: value }); return 26; } case types_2.CommandType.CMD_SET_HUB_OSD: try { return value !== undefined ? Number.parseInt(value) : 0; } catch (err) { const error = (0, error_1.ensureError)(err); logging_1.rootHTTPLogger.error("Station convert raw property - CMD_SET_HUB_OSD Error", { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), property: property, value: value }); return 0; } case types_2.CommandType.CMD_SET_HUB_ALARM_AUTO_END: return value !== undefined ? value !== "0" ? false : true : false; case types_2.CommandType.CMD_SET_HUB_ALARM_CLOSE: return value !== undefined ? value === "1" ? false : true : false; } if (property.name === types_1.PropertyName.Model && device_1.Device.isLockWifiT8510P(this.getDeviceType(), this.getSerial())) { return "T8510P"; } else if (property.type === "number") { const numericProperty = property; try { return value !== undefined ? Number.parseInt(value) : (numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0)); } catch (err) { const error = (0, error_1.ensureError)(err); logging_1.rootHTTPLogger.warn("Station convert raw property - PropertyMetadataNumeric Convert Error", { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } else if (property.type === "boolean") { const booleanProperty = property; try { return value !== undefined ? (typeof value === "number" ? !!value : (value === "1" || value.toLowerCase() === "true" ? true : false)) : (booleanProperty.default !== undefined ? booleanProperty.default : false); } catch (err) { const error = (0, error_1.ensureError)(err); logging_1.rootHTTPLogger.warn("Station convert raw property - PropertyMetadataBoolean Convert Error", { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } else if (property.type === "string") { const stringProperty = property; return value !== undefined ? value : (stringProperty.default !== undefined ? stringProperty.default : ""); } else if (property.type === "object") { const objectProperty = property; return value !== undefined ? value : (objectProperty.default !== undefined ? objectProperty.default : undefined); } } catch (err) { const error = (0, error_1.ensureError)(err); logging_1.rootHTTPLogger.error("Station convert raw property - Error", { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), property: property, value: value }); } return value; } getPropertyMetadata(name, hidden = false) { const property = this.getPropertiesMetadata(hidden)[name]; if (property !== undefined) return property; throw new error_2.InvalidPropertyError("Property name is not valid", { context: { name: name } }); } getPropertyValue(name) { if (name === types_1.PropertyName.StationCurrentMode) { const guard_mode = this.properties[types_1.PropertyName.StationGuardMode]; return this.properties[types_1.PropertyName.StationCurrentMode] !== undefined ? this.properties[types_1.PropertyName.StationCurrentMode] : guard_mode !== undefined && guard_mode !== types_1.GuardMode.SCHEDULE && guard_mode !== types_1.GuardMode.GEO ? guard_mode : types_1.GuardMode.UNKNOWN; } return this.properties[name]; } hasPropertyValue(name) { return this.getPropertyValue(name) !== undefined; } getRawProperty(type) { return this.rawProperties[type]?.value; } getRawProperties() { return this.rawProperties; } getProperties() { const result = {}; for (const property of Object.keys(this.properties)) { if (!property.startsWith("hidden-")) result[property] = this.properties[property]; } return result; } getPropertiesMetadata(hidden = false) { let metadata = { ...types_1.StationProperties[this.getDeviceType()] }; if (Object.keys(metadata).length === 0) { metadata = { ...types_1.BaseStationProperties }; } if (this.hasDeviceWithType(types_1.DeviceType.KEYPAD)) { metadata[types_1.PropertyName.StationGuardMode] = types_1.StationGuardModeKeyPadProperty; metadata[types_1.PropertyName.StationCurrentMode] = types_1.StationCurrentModeKeyPadProperty; metadata[types_1.PropertyName.StationSwitchModeWithAccessCode] = types_1.StationSwitchModeWithAccessCodeProperty; metadata[types_1.PropertyName.StationAutoEndAlarm] = types_1.StationAutoEndAlarmProperty; metadata[types_1.PropertyName.StationTurnOffAlarmWithButton] = types_1.StationTurnOffAlarmWithButtonProperty; } if (!hidden) { for (const property of Object.keys(metadata)) { if (property.startsWith("hidden-")) delete metadata[property]; } } return metadata; } hasProperty(name, hidden = false) { return this.getPropertiesMetadata(hidden)[name] !== undefined; } getCommands() { const commands = types_1.StationCommands[this.getDeviceType()]; if (commands === undefined) return []; return commands; } hasCommand(name) { return this.getCommands().includes(name); } static getChannel(type) { return Station.isStation(type) === true ? (device_1.Device.isIndoorCamera(type) ? Station.CHANNEL_INDOOR : Station.CHANNEL) : 0; } static isStation(type) { return type === types_1.DeviceType.STATION || type === types_1.DeviceType.HB3 || type === types_1.DeviceType.MINIBASE_CHIME; } isStation() { return Station.isStation(this.rawStation.device_type); } static isStationHomeBase3(type) { return type === types_1.DeviceType.HB3; } static isStationHomeBase3BySn(sn) { return sn.startsWith("T8030"); } isStationHomeBase3() { return Station.isStationHomeBase3(this.rawStation.device_type); } isIntegratedDevice() { //TODO: Recheck this implementation considering HomeBase 3 integration if (device_1.Device.isLock(this.getDeviceType()) || device_1.Device.isSmartDrop(this.getDeviceType()) || device_1.Device.isSmartSafe(this.getDeviceType())) { if (this.rawStation.devices?.length === 1) return this.rawStation.devices[0]?.device_sn === this.rawStation.station_sn; else return true; } return device_1.Device.isWiredDoorbellDual(this.getDeviceType()) || device_1.Device.isFloodLight(this.getDeviceType()) || device_1.Device.isWiredDoorbell(this.getDeviceType()) || device_1.Device.isIndoorCamera(this.getDeviceType()) || device_1.Device.isSoloCameras(this.getDeviceType()) || device_1.Device.isWallLightCam(this.getDeviceType()) || device_1.Device.isStarlight4GLTE(this.getDeviceType()) || device_1.Device.isSoloCameraPro(this.getDeviceType()); } isP2PConnectableDevice() { if (device_1.Device.isSmartTrack(this.getDeviceType()) || (!device_1.Device.isSupported(this.getDeviceType()) && !this.isStation())) { if (!device_1.Device.isSupported(this.getDeviceType()) && !this.isStation()) { logging_1.rootHTTPLogger.debug("Station not supported, no connection over p2p will be initiated", { stationSN: this.getSerial(), type: this.getDeviceType() }); } return false; } return true; } getDeviceType() { return this.rawStation.device_type; } getHardwareVersion() { return this.rawStation.main_hw_version; } getMACAddress() { return this.rawStation.wifi_mac; } getModel() { return this.rawStation.station_model; } getName() { return this.rawStation.station_name; } getSerial() { return this.rawStation.station_sn; } getSoftwareVersion() { return this.rawStation.main_sw_version; } getIPAddress() { return this.rawStation.ip_addr; } getLANIPAddress() { return this.getPropertyValue(types_1.PropertyName.StationLANIpAddress); } getGuardMode() { return this.getPropertyValue(types_1.PropertyName.StationGuardMode); } getCurrentMode() { const guard_mode = this.getGuardMode(); return this.getPropertyValue(types_1.PropertyName.StationCurrentMode) !== undefined ? this.getPropertyValue(types_1.PropertyName.StationCurrentMode) : guard_mode !== undefined && guard_mode !== types_1.GuardMode.SCHEDULE && guard_mode !== types_1.GuardMode.GEO ? guard_mode : types_1.GuardMode.UNKNOWN; } processPushNotification(message) { if (message.type !== undefined && message.event_type !== undefined) { if (message.event_type === types_3.CusPushEvent.MODE_SWITCH && message.station_sn === this.getSerial()) { logging_1.rootHTTPLogger.info("Received push notification for changing guard mode", { guard_mode: message.station_guard_mode, current_mode: message.station_current_mode, stationSN: message.station_sn }); try { if (message.station_guard_mode !== undefined) this.updateRawProperty(types_1.ParamType.GUARD_MODE, message.station_guard_mode.toString(), "push"); if (message.station_current_mode !== undefined) this.updateRawProperty(types_2.CommandType.CMD_GET_ALARM_MODE, message.station_current_mode.toString(), "push"); } catch (err) { const error = (0, error_1.ensureError)(err); logging_1.rootHTTPLogger.debug(`Station process push notification - MODE_SWITCH event error`, { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), message: JSON.stringify(message) }); } } else if (message.event_type === types_3.CusPushEvent.ALARM && message.station_sn === this.getSerial() && !this.isStation()) { logging_1.rootHTTPLogger.info("Received push notification for alarm event", { stationSN: message.station_sn, alarmType: message.alarm_type }); if (message.alarm_type !== undefined) { this.onAlarmEvent(message.alarm_type); } } } else if (message.msg_type === types_3.CusPushEvent.TFCARD && message.station_sn === this.getSerial() && message.tfcard_status !== undefined) { this.updateRawProperty(types_2.CommandType.CMD_GET_TFCARD_STATUS, message.tfcard_status.toString(), "push"); } } isConnected() { return this.p2pSession.isConnected(); } close() { this.terminating = true; if (this.reconnectTimeout) { clearTimeout(this.reconnectTimeout); this.reconnectTimeout = undefined; } if (this.p2pSession.isConnected()) { logging_1.rootHTTPLogger.info(`Disconnect from station ${this.getSerial()}`); this.p2pSession.close(); } } isEnergySavingDevice() { return this.p2pSession.isEnergySavingDevice(); } async connect() { if (!this.p2pSession.isConnected() && !this.p2pSession.isConnecting()) { logging_1.rootHTTPLogger.debug(`Connecting to station ${this.getSerial()}...`, { stationSN: this.getSerial(), p2pConnectionType: types_2.P2PConnectionType[this.p2pConnectionType] }); this.p2pSession.setConnectionType(this.p2pConnectionType); await this.p2pSession.connect(); } } onFinishDownload(channel) { this.emit("download finish", this, channel); } onStartDownload(channel, metadata, videoStream, audioStream) { this.emit("download start", this, channel, metadata, videoStream, audioStream); } onStopLivestream(channel) { this.emit("livestream stop", this, channel); } onErrorLivestream(channel, error) { this.emit("livestream error", this, channel, error); } onStartLivestream(channel, metadata, videoStream, audioStream) { this.emit("livestream start", this, channel, metadata, videoStream, audioStream); } onStopRTSPLivestream(channel) { this.emit("rtsp livestream stop", this, channel); } onStartRTSPLivestream(channel) { this.emit("rtsp livestream start", this, channel); } onWifiRssiChanged(channel, rssi) { this.emit("wifi rssi", this, channel, rssi); } onRTSPUrl(channel, rtspUrl) { this.emit("rtsp url", this, channel, rtspUrl); } onParameter(channel, param, value) { const params = {}; const parsedValue = parameter_1.ParameterHelper.readValue(this.getSerial(), param, value, logging_1.rootHTTPLogger); if (parsedValue !== undefined) { params[param] = { value: parsedValue, source: "p2p" }; this.emit("raw device property changed", this._getDeviceSerial(channel), params); } } onAlarmDelay(alarmDelayEvent, alarmDelay) { this.emit("alarm delay event", this, alarmDelayEvent, alarmDelay); if (this.hasProperty(types_1.PropertyName.StationAlarmDelay)) { this.updateProperty(types_1.PropertyName.StationAlarmDelay, alarmDelay); } if (this.hasProperty(types_1.PropertyName.StationAlarmDelayType)) { this.updateProperty(types_1.PropertyName.StationAlarmDelayType, alarmDelayEvent); } } onAlarmArmed() { this.emit("alarm armed event", this); if (this.hasProperty(types_1.PropertyName.StationAlarmArmDelay)) { this.updateProperty(types_1.PropertyName.StationAlarmArmDelay, 0); } /*if (this.hasProperty(PropertyName.StationAlarmArmed) && this.hasProperty(PropertyName.StationCurrentMode)) { this.updateProperty(PropertyName.StationAlarmArmed, this.isAlarmArmable(this.getPropertyValue(PropertyName.StationCurrentMode) as AlarmMode)); }*/ if (this.hasProperty(types_1.PropertyName.StationAlarmArmed)) { this.updateProperty(types_1.PropertyName.StationAlarmArmed, true); } if (this.hasProperty(types_1.PropertyName.StationAlarmDelay)) { this.updateProperty(types_1.PropertyName.StationAlarmDelay, 0); } if (this.hasProperty(types_1.PropertyName.StationAlarmDelayType)) { this.updateProperty(types_1.PropertyName.StationAlarmDelayType, 0); } if (this.hasProperty(types_1.PropertyName.StationAlarm)) { this.updateProperty(types_1.PropertyName.StationAlarm, false); } if (this.hasProperty(types_1.PropertyName.StationAlarmType)) { this.updateProperty(types_1.PropertyName.StationAlarmType, 0); } } onAlarmEvent(alarmEvent) { this.emit("alarm event", this, alarmEvent); if (this.hasProperty(types_1.PropertyName.StationAlarmDelay)) { this.updateProperty(types_1.PropertyName.StationAlarmDelay, 0); } if (this.hasProperty(types_1.PropertyName.StationAlarmDelayType)) { this.updateProperty(types_1.PropertyName.StationAlarmDelayType, 0); } switch (alarmEvent) { case types_2.AlarmEvent.DEV_STOP: case types_2.AlarmEvent.HUB_STOP: case types_2.AlarmEvent.HUB_STOP_BY_APP: case types_2.AlarmEvent.HUB_STOP_BY_HAND: case types_2.AlarmEvent.HUB_STOP_BY_KEYPAD: if (this.hasProperty(types_1.PropertyName.StationAlarm)) { this.updateProperty(types_1.PropertyName.StationAlarm, false); } if (this.hasProperty(types_1.PropertyName.StationAlarmType)) { this.updateProperty(types_1.PropertyName.StationAlarmType, 0); } break; default: if (this.hasProperty(types_1.PropertyName.StationAlarm)) { this.updateProperty(types_1.PropertyName.StationAlarm, true); } if (this.hasProperty(types_1.PropertyName.StationAlarmType)) { this.updateProperty(types_1.PropertyName.StationAlarmType, alarmEvent); } break; } } setGuardMode(mode) { const propertyData = { name: types_1.PropertyName.StationGuardMode, value: mode }; if (!this.hasProperty(propertyData.name)) { throw new error_1.NotSupportedError("This functionality is not implemented or supported", { context: { propertyName: propertyData.name, propertyValue: propertyData.value, station: this.getSerial() } }); } const property = this.getPropertyMetadata(propertyData.name); (0, utils_3.validValue)(property, mode); logging_1.rootHTTPLogger.debug(`Station set guard mode - sending command`, { stationSN: this.getSerial(), mode: mode }); if ((((0, utils_1.isGreaterEqualMinVersion)("2.0.7.9", this.getSoftwareVersion()) && !device_1.Device.isIntegratedDeviceBySn(this.getSerial())) || device_1.Device.isSoloCameraBySn(this.getSerial())) || this.rawStation.device_type === types_1.DeviceType.HB3) { logging_1.rootHTTPLogger.debug(`Station set guard mode - Using CMD_SET_PAYLOAD`, { stationSN: this.getSerial(), mode: mode, main_sw_version: this.getSoftwareVersion() }); this.p2pSession.sendCommandWithStringPayload({ commandType: types_2.CommandType.CMD_SET_PAYLOAD, value: JSON.stringify({ "account_id": this.rawStation.member.admin_user_id, "cmd": types_2.CommandType.CMD_SET_ARMING, "mValue3": 0, "payload": { "mode_type": mode, "user_name": this.rawStation.member.nick_name } }), channel: Station.CHANNEL }, { property: propertyData }); } else { logging_1.rootHTTPLogger.debug(`Station set guard mode - Using CMD_SET_ARMING`, { stationSN: this.getSerial(), mode: mode }); this.p2pSession.sendCommandWithInt({ commandType: types_2.CommandType.CMD_SET_ARMING, value: mode, strValue: this.rawStation.member.admin_user_id, channel: Station.CHANNEL }, { property: propertyData }); } } getCameraInfo() { logging_1.rootHTTPLogger.debug(`Station send get camera info command`, { stationSN: this.getSerial() }); this.p2pSession.sendCommandWithInt({ commandType: types_2.CommandType.CMD_CAMERA_INFO, value: 255, channel: Station.CHANNEL }); } getStorageInfoEx() { logging_1.rootHTTPLogger.debug(`Station send get storage info command`, { stationSN: this.getSerial() }); if (this.isStation() && this.rawStation.device_type !== types_1.DeviceType.HB3 && (0, utils_1.isGreaterEqualMinVersion)("3.2.7.6", this.getSoftwareVersion())) { this.p2pSession.sendCommandWithoutData(types_2.CommandType.CMD_SDINFO_EX, Station.CHANNEL); } else if (this.rawStation.device_type === types_1.DeviceType.HB3) { this.p2pSession.sendCommandWithStringPayload({ commandType: types_2.CommandType.CMD_SET_PAYLOAD, value: JSON.stringify({ "account_id": this.rawStation.member.admin_user_id, "cmd": types_2.CommandType.CMD_STORAGE_INFO_HB3, "mChannel": 0, "mValue3": 0, "payload": { "version": 0.0, "cmd": 11001.0, } }), }); } else { this.p2pSession.sendCommandWithIntString({ commandType: types_2.CommandType.CMD_SDINFO_EX, value: 0, valueSub: 0, channel: Station.CHANNEL, strValue: this.rawStation.member.admin_user_id }); } } onAlarmMode(mode) { logging_1.rootHTTPLogger.debug(`Station alarm mode changed`, { stationSN: this.getSerial(), mode: mode }); this.updateRawProperty(types_2.CommandType.CMD_GET_ALARM_MODE, mode.toString(), "p2p"); const armDelay = this.getArmDelay(mode); if (armDelay > 0) { this.emit("alarm arm delay event", this, armDelay); if (this.hasProperty(types_1.PropertyName.StationAlarmArmDelay)) { this.updateProperty(types_1.PropertyName.StationAlarmArmDelay, armDelay); } } if (mode === types_1.AlarmMode.DISARMED) { if (this.hasProperty(types_1.PropertyName.StationAlarmArmDelay)) { this.updateProperty(types_1.PropertyName.StationAlarmArmDelay, 0); } if (this.hasProperty(types_1.PropertyName.StationAlarmArmed)) { this.updateProperty(types_1.PropertyName.StationAlarmArmed, false); } if (this.hasProperty(types_1.PropertyName.StationAlarmDelay)) { this.updateProperty(types_1.PropertyName.StationAlarmDelay, 0); } if (this.hasProperty(types_1.PropertyName.StationAlarmDelayType)) { this.updateProperty(types_1.PropertyName.StationAlarmDelayType, 0); } if (this.hasProperty(types_1.PropertyName.StationAlarm)) { this.updateProperty(types_1.PropertyName.StationAlarm, false); } if (this.hasProperty(types_1.PropertyName.StationAlarmType)) { this.updateProperty(types_1.PropertyName.StationAlarmType, 0); } } // Trigger refresh Guard Mode this.getCameraInfo(); } getArmDelay(mode) { let propertyName; switch (mode) { case types_1.AlarmMode.HOME: propertyName = types_1.PropertyName.StationHomeSecuritySettings; break; case types_1.AlarmMode.AWAY: propertyName = types_1.PropertyName.StationAwaySecuritySettings; break; case types_1.AlarmMode.CUSTOM1: propertyName = types_1.PropertyName.StationCustom1SecuritySettings; break; case types_1.AlarmMode.CUSTOM2: propertyName = types_1.PropertyName.StationCustom2SecuritySettings; break; case types_1.AlarmMode.CUSTOM3: propertyName = types_1.PropertyName.StationCustom3SecuritySettings; break; } if (propertyName !== undefined && this.hasPropertyValue(propertyName) && this.getPropertyValue(propertyName) !== "") { const settings = this.getPropertyValue(propertyName); try { if (settings.count_down_arm?.channel_list?.length > 0 && settings.count_down_arm?.delay_time > 0) { return settings.count_down_arm.delay_time; } } catch (err) { const error = (0, error_1.ensureError)(err); logging_1.rootHTTPLogger.debug(`Station get arm delay - Error`, { error: (0, utils_3.getError)(error), stationSN: this.getSerial(), mode: mode, propertyName: propertyName, settings: settings }); } } return 0; } /*private getGuardModeActionSetting(mode: AlarmMode): number { //TODO: This settings are only available on the device properties... let value = 0; try { switch (mode) { case AlarmMode.HOME: value = Number.parseInt(this.getRawProperty(CommandType.CMD_GET_HOME_ACTION)); break; case AlarmMode.AWAY: value = Number.parseInt(this.getRawProperty(CommandType.CMD_GET_AWAY_ACTION)); break; case AlarmMode.CUSTOM1: value = Number.parseInt(this.getRawProperty(CommandType.CMD_GET_CUSTOM1_ACTION)); break; case AlarmMode.CUSTOM2: value = Number.parseInt(this.getRawProperty(CommandType.CMD_GET_CUSTOM2_ACTION)); break; case AlarmMode.CUSTOM3: value = Number.parseInt(this.getRawProperty(CommandType.CMD_GET_CUSTOM3_ACTION)); break; } } catch (err) { const error = ensureError(err); rootHTTPLogger.debug(`Station get guard mode action setting - Error`, { error: getError(error), stationSN: this.getSerial(), mode: mode }); } return value; } private isAlarmArmable(mode: AlarmMode): boolean { const action = this.getGuardModeActionSetting(mode); if ((action & GuardModeSecuritySettingsAction.CAMERA_ALARM) == GuardModeSecuritySettingsAction.CAMERA_ALARM || (action & GuardModeSecuritySettingsAction.HOMEBASE_ALARM) == GuardModeSecuritySettingsAction.HOMEBASE_ALARM || (action & GuardModeSecuritySettingsAction.LIGHT_ALARM) == GuardModeSecuritySettingsAction.LIGHT_ALARM) { return true; } return false; }*/ _getDeviceSerial(channel) { if (this.rawStation.devices) for (const device of this.rawStation.devices) { if (device.device_channel === channel) return device.device_sn; } return ""; } _handleCameraInfoParameters(devices, channel, type, value) { if (channel === Station.CHANNEL || channel === Station.CHANNEL_INDOOR || (this.isIntegratedDevice() && this.getDeviceType() !== types_1.DeviceType.HB3)) { this.updateRawProperty(type, value, "p2p"); if (type === types_2.CommandType.CMD_GET_ALARM_MODE) { if (this.getDeviceType() !== types_1.DeviceType.STATION && this.getDeviceType() !== types_1.DeviceType.HB3) // Trigger refresh Guard Mode this.api.refreshStationData(); } if (this.isIntegratedDevice()) { const device_sn = this.getSerial(); if (!devices[device_sn]) { devices[device_sn] = {}; } const parsedValue = parameter_1.ParameterHelper.readValue(device_sn, type, value, logging_1.rootHTTPLogger); if (parsedValue !== undefined) { devices[device_sn][type] = { value: parsedValue, source: "p2p" }; } } } else { const device_sn = this._getDeviceSerial(channel); if (device_sn !== "") { if (!devices[device_sn]) { devices[device_sn] = {}; } const parsedValue = parameter_1.ParameterHelper.readValue(device_sn, type, value, logging_1.rootHTTPLogger); if (parsedValue !== undefined) { devices[device_sn][type] = { value: parsedValue, source: "p2p" }; } } } } onCameraInfo(cameraInfo) { logging_1.rootHTTPLogger.debug("Station got camera info", { station: this.getSerial(), cameraInfo: cameraInfo }); const devices = {}; cameraInfo.params.forEach(param => { this._handleCameraInfoParameters(devices, param.dev_type, param.param_type, param.param_value); }); if (Array.isArray(cameraInfo.db_bypass_str)) { cameraInfo.db_bypass_str?.forEach(param => { this._handleCameraInfoParameters(devices, param.channel, param.param_type, Buffer.from(param.param_value, "base64").toString()); }); } Object.keys(devices).forEach(device => { this.emit("raw device property changed", device, devices[device]); }); } onCommandResponse(result) { logging_1.rootHTTPLogger.debug("Station got p2p command response", { station: this.getSerial(), commandType: result.command_type, channel: result.channel, returnCodeName: types_2.ErrorCode[result.return_code], returnCode: result.return_code, customData: result.customData }); this.emit("command result", this, result); } onSecondaryCommandResponse(result) { logging_1.rootHTTPLogger.debug("Station got p2p secondary command response", { station: this.getSerial(), commandType: result.command_type, channel: result.channel, returnCode: result.return_code, customData: result.customData }); this.emit("secondary command result", this, result); if (result.command_type === types_2.CommandType.CMD_SMARTSAFE_SETTINGS && result.customData?.command?.name === "deviceVer