eufy-security-client
Version:
Client to comunicate with Eufy-Security devices
897 lines (896 loc) • 635 kB
JavaScript
"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