eufy-security-client-fork
Version:
Client to comunicate with Eufy-Security devices
994 lines • 303 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Station = void 0;
const tiny_typed_emitter_1 = require("tiny-typed-emitter");
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");
class Station extends tiny_typed_emitter_1.TypedEmitter {
constructor(api, station) {
super();
this.properties = {};
this.rawProperties = {};
this.ready = false;
this.currentDelay = 0;
this.terminating = false;
this.p2pConnectionType = types_2.P2PConnectionType.QUICKEST;
this.api = api;
this.rawStation = station;
this.log = api.getLog();
this.p2pSession = new session_1.P2PClientProtocol(this.rawStation, this.api);
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.update(this.rawStation);
this.ready = true;
setImmediate(() => {
this.emit("ready", this);
});
}
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, cloudOnlyProperties = false) {
this.rawStation = station;
this.p2pSession.updateRawStation(station);
const metadata = this.getPropertiesMetadata();
for (const property of Object.values(metadata)) {
if (this.rawStation[property.key] !== undefined && typeof property.key === "string") {
this.updateProperty(property.name, this.rawStation[property.key]);
}
else if (this.properties[property.name] === undefined && property.default !== undefined && !this.ready) {
this.updateProperty(property.name, property.default);
}
}
if (!cloudOnlyProperties) {
this.rawStation.params.forEach(param => {
this.updateRawProperty(param.param_type, param.param_value);
});
}
this.log.debug("Normalized Properties", { stationSN: this.getSerial(), properties: this.properties });
}
updateProperty(name, value) {
if ((this.properties[name] !== undefined && this.properties[name] !== value)
|| this.properties[name] === undefined) {
this.properties[name] = value;
if (this.ready)
this.emit("property changed", this, name, value);
return true;
}
return false;
}
updateRawProperties(values) {
Object.keys(values).forEach(paramtype => {
const param_type = Number.parseInt(paramtype);
this.updateRawProperty(param_type, values[param_type]);
});
}
updateRawProperty(type, value) {
const parsedValue = parameter_1.ParameterHelper.readValue(type, value, this.log);
if ((this.rawProperties[type] !== undefined && this.rawProperties[type] !== parsedValue)
|| this.rawProperties[type] === undefined) {
this.rawProperties[type] = parsedValue;
if (this.ready) {
this.emit("raw property changed", this, type, this.rawProperties[type]);
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 (error) {
this.log.error("Number conversion error", error);
}
}
const metadata = this.getPropertiesMetadata();
for (const property of Object.values(metadata)) {
if (property.key === type) {
try {
this.updateProperty(property.name, this.convertRawPropertyValue(property, this.rawProperties[type]));
}
catch (error) {
if (error instanceof error_2.PropertyNotSupportedError) {
this.log.debug("Property not supported error", error);
}
else {
this.log.error("Property error", error);
}
}
}
}
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 ${property.name} not supported for station ${this.getSerial()} with software version ${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 ${property.name} not supported for station ${this.getSerial()} with software version ${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 ${property.name} not supported for station ${this.getSerial()} with software version ${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 (error) {
this.log.error("Convert CMD_HUB_ALARM_TONE Error:", { property: property, value: value, error: error });
return 1;
}
case types_2.CommandType.CMD_SET_HUB_SPK_VOLUME:
try {
return value !== undefined ? Number.parseInt(value) : 26;
}
catch (error) {
this.log.error("Convert CMD_SET_HUB_SPK_VOLUME Error:", { property: property, value: value, error: error });
return 26;
}
case types_2.CommandType.CMD_SET_PROMPT_VOLUME:
try {
return value !== undefined ? Number.parseInt(value) : 26;
}
catch (error) {
this.log.error("Convert CMD_SET_PROMPT_VOLUME Error:", { property: property, value: value, error: error });
return 26;
}
case types_2.CommandType.CMD_SET_HUB_OSD:
try {
return value !== undefined ? Number.parseInt(value) : 0;
}
catch (error) {
this.log.error("Convert CMD_SET_HUB_OSD Error:", { property: property, value: value, error: error });
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.type === "number") {
const numericProperty = property;
try {
return value !== undefined ? Number.parseInt(value) : (numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0));
}
catch (error) {
this.log.warn("PropertyMetadataNumeric Convert Error:", { property: property, value: value, error: error });
return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0);
}
}
else if (property.type === "boolean") {
const booleanProperty = property;
try {
return value !== undefined ? (value === "1" || value.toLowerCase() === "true" ? true : false) : (booleanProperty.default !== undefined ? booleanProperty.default : false);
}
catch (error) {
this.log.warn("PropertyMetadataBoolean Convert Error:", { property: property, value: value, error: error });
return booleanProperty.default !== undefined ? booleanProperty.default : false;
}
}
else if (property.type === "string") {
const stringProperty = property;
return value !== undefined ? value : (stringProperty.default !== undefined ? stringProperty.default : "");
}
}
catch (error) {
this.log.error("Convert Error:", { property: property, value: value, error: error });
}
return value;
}
getPropertyMetadata(name) {
const property = this.getPropertiesMetadata()[name];
if (property !== undefined)
return property;
throw new error_2.InvalidPropertyError(`Property ${name} invalid`);
}
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];
}
getRawProperties() {
return this.rawProperties;
}
getProperties() {
return this.properties;
}
getPropertiesMetadata() {
let metadata = types_1.StationProperties[this.getDeviceType()];
if (metadata === undefined) {
metadata = types_1.StationProperties[types_1.DeviceType.STATION];
}
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;
}
return metadata;
}
hasProperty(name) {
return this.getPropertiesMetadata()[name] !== undefined;
}
getCommands() {
const commands = types_1.StationCommands[this.getDeviceType()];
if (commands === undefined)
return [];
return commands;
}
hasCommand(name) {
return this.getCommands().includes(name);
}
isStation() {
return this.rawStation.device_type == types_1.DeviceType.STATION;
}
isDeviceStation() {
return this.rawStation.device_type != types_1.DeviceType.STATION;
}
isIntegratedDevice() {
var _a, _b;
if (device_1.Device.isLock(this.getDeviceType()) || device_1.Device.isSmartDrop(this.getDeviceType()) || device_1.Device.isSmartSafe(this.getDeviceType())) {
if (((_a = this.rawStation.devices) === null || _a === void 0 ? void 0 : _a.length) === 1)
return ((_b = this.rawStation.devices[0]) === null || _b === void 0 ? void 0 : _b.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());
}
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()) {
this.log.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());
if (message.station_current_mode !== undefined)
this.updateRawProperty(types_2.CommandType.CMD_GET_ALARM_MODE, message.station_current_mode.toString());
}
catch (error) {
this.log.debug(`Station ${message.station_sn} MODE_SWITCH event (${message.event_type}) - Error:`, error);
}
}
else if (message.event_type === types_3.CusPushEvent.ALARM && message.station_sn === this.getSerial() && !this.isStation()) {
this.log.info("Received push notification for alarm event", { stationSN: message.station_sn, alarmType: message.alarm_type });
if (message.alarm_type !== undefined)
this.emit("alarm event", this, message.alarm_type);
}
}
}
isConnected() {
return this.p2pSession.isConnected();
}
close() {
this.terminating = true;
this.log.info(`Disconnect from station ${this.getSerial()}`);
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
this.reconnectTimeout = undefined;
}
if (this.p2pSession.isConnected()) {
this.p2pSession.close();
}
}
isEnergySavingDevice() {
return this.p2pSession.isEnergySavingDevice();
}
async connect() {
this.log.debug(`Connecting to station ${this.getSerial()}...`, { p2pConnectionType: types_2.P2PConnectionType[this.p2pConnectionType] });
this.p2pSession.setConnectionType(this.p2pConnectionType);
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 = {};
params[param] = parameter_1.ParameterHelper.readValue(param, value, this.log);
this.emit("raw device property changed", this._getDeviceSerial(channel), params);
}
onAlarmDelay(alarmDelayEvent, alarmDelay) {
this.emit("alarm delay event", this, alarmDelayEvent, alarmDelay);
}
onAlarmArmed() {
this.emit("alarm armed event", this);
}
onAlarmEvent(alarmEvent) {
this.emit("alarm event", this, alarmEvent);
}
async 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 by ${this.getSerial()}`);
}
const property = this.getPropertyMetadata(propertyData.name);
(0, utils_3.validValue)(property, mode);
this.log.debug(`Sending guard mode command to station ${this.getSerial()} with value: ${types_1.GuardMode[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.log.debug(`Using CMD_SET_PAYLOAD for station ${this.getSerial()}`, { main_sw_version: this.getSoftwareVersion() });
await 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 {
this.log.debug(`Using CMD_SET_ARMING for station ${this.getSerial()}`);
await this.p2pSession.sendCommandWithInt({
commandType: types_2.CommandType.CMD_SET_ARMING,
value: mode,
strValue: this.rawStation.member.admin_user_id,
channel: Station.CHANNEL
}, {
property: propertyData
});
}
}
async getCameraInfo() {
this.log.debug(`Sending get camera infos command to station ${this.getSerial()}`);
await this.p2pSession.sendCommandWithInt({
commandType: types_2.CommandType.CMD_CAMERA_INFO,
value: 255,
channel: Station.CHANNEL
});
}
async getStorageInfo() {
this.log.debug(`Sending get storage info command to station ${this.getSerial()}`);
//TODO: Verify channel! Should be 255...
await this.p2pSession.sendCommandWithIntString({
commandType: types_2.CommandType.CMD_SDINFO_EX,
value: 0,
valueSub: 0,
strValue: this.rawStation.member.admin_user_id
});
}
async onAlarmMode(mode) {
this.log.info(`Alarm mode for station ${this.getSerial()} changed to: ${types_1.AlarmMode[mode]}`);
this.updateRawProperty(types_2.CommandType.CMD_GET_ALARM_MODE, mode.toString());
const armDelay = this.getArmDelay(mode);
if (armDelay > 0) {
this.emit("alarm arm delay event", this, armDelay);
}
// Trigger refresh Guard Mode
await 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);
if (settings.count_down_arm.channel_list.length > 0 && settings.count_down_arm.delay_time > 0) {
return settings.count_down_arm.delay_time;
}
}
return 0;
}
_getDeviceSerial(channel) {
if (this.rawStation.devices)
for (const device of this.rawStation.devices) {
if (device.device_channel === channel)
return device.device_sn;
}
return "";
}
onCameraInfo(cameraInfo) {
this.log.debug("Got camera infos", { station: this.getSerial(), cameraInfo: cameraInfo });
const devices = {};
cameraInfo.params.forEach(param => {
if (param.dev_type === Station.CHANNEL || param.dev_type === Station.CHANNEL_INDOOR || this.isIntegratedDevice()) {
this.updateRawProperty(param.param_type, param.param_value);
if (param.param_type === types_2.CommandType.CMD_GET_ALARM_MODE) {
if (this.getDeviceType() !== types_1.DeviceType.STATION)
// Trigger refresh Guard Mode
this.api.refreshStationData();
}
if (this.isIntegratedDevice()) {
const device_sn = this.getSerial();
if (!devices[device_sn]) {
devices[device_sn] = {};
}
devices[device_sn][param.param_type] = parameter_1.ParameterHelper.readValue(param.param_type, param.param_value, this.log);
}
}
else {
const device_sn = this._getDeviceSerial(param.dev_type);
if (device_sn !== "") {
if (!devices[device_sn]) {
devices[device_sn] = {};
}
devices[device_sn][param.param_type] = parameter_1.ParameterHelper.readValue(param.param_type, param.param_value, this.log);
}
}
});
Object.keys(devices).forEach(device => {
this.emit("raw device property changed", device, devices[device]);
});
}
onCommandResponse(result) {
this.log.debug("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) {
this.log.debug("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);
}
onConnect(address) {
this.terminating = false;
this.resetCurrentDelay();
this.log.info(`Connected to station ${this.getSerial()} on host ${address.host} and port ${address.port}`);
this.emit("connect", this);
}
onDisconnect() {
this.log.info(`Disconnected from station ${this.getSerial()}`);
this.emit("close", this);
if (!this.isEnergySavingDevice() && !this.terminating)
this.scheduleReconnect();
}
onTimeout() {
this.log.info(`Timeout connecting to station ${this.getSerial()}`);
this.emit("connection error", this, new error_1.StationConnectTimeoutError());
this.scheduleReconnect();
}
getCurrentDelay() {
const delay = this.currentDelay == 0 ? 5000 : this.currentDelay;
if (this.currentDelay < 60000)
this.currentDelay += 10000;
if (this.currentDelay >= 60000 && this.currentDelay < 600000)
this.currentDelay += 60000;
return delay;
}
resetCurrentDelay() {
this.currentDelay = 0;
}
scheduleReconnect() {
if (!this.reconnectTimeout) {
const delay = this.getCurrentDelay();
this.log.debug(`Schedule reconnect to station ${this.getSerial()}...`, { delay: delay });
this.reconnectTimeout = setTimeout(async () => {
this.reconnectTimeout = undefined;
this.connect();
}, delay);
}
}
async rebootHUB() {
const commandData = {
name: types_1.CommandName.StationReboot
};
if (!this.hasCommand(types_1.CommandName.StationReboot)) {
throw new error_1.NotSupportedError(`This functionality is not implemented or supported by ${this.getSerial()}`);
}
this.log.debug(`Sending reboot command to station ${this.getSerial()}`);
await this.p2pSession.sendCommandWithInt({
commandType: types_2.CommandType.CMD_HUB_REBOOT,
value: 0,
strValue: this.rawStation.member.admin_user_id,
channel: Station.CHANNEL
}, {
command: commandData
});
}
async setStatusLed(device, value) {
const propertyData = {
name: types_1.PropertyName.DeviceStatusLed,
value: value
};
if (device.getStationSerial() !== this.getSerial()) {
throw new error_1.WrongStationError(`Device ${device.getSerial()} is not managed by this station ${this.getSerial()}`);
}
if (!device.hasProperty(propertyData.name)) {
throw new error_1.NotSupportedError(`This functionality is not implemented or supported by ${device.getSerial()}`);
}
this.log.debug(`Sending status led command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`);
if (device.isCamera2Product() || device.getDeviceType() === types_1.DeviceType.CAMERA || device.getDeviceType() === types_1.DeviceType.CAMERA_E) {
await this.p2pSession.sendCommandWithIntString({
commandType: types_2.CommandType.CMD_DEV_LED_SWITCH,
value: value === true ? 1 : 0,
valueSub: device.getChannel(),
strValue: this.rawStation.member.admin_user_id,
channel: device.getChannel()
}, {
property: propertyData
});
await this.p2pSession.sendCommandWithIntString({
commandType: types_2.CommandType.CMD_LIVEVIEW_LED_SWITCH,
value: value === true ? 1 : 0,
valueSub: device.getChannel(),
strValue: this.rawStation.member.admin_user_id,
channel: device.getChannel()
}, {
property: propertyData
});
}
else if (device.getDeviceType() === types_1.DeviceType.FLOODLIGHT_CAMERA_8423 || device.getDeviceType() === types_1.DeviceType.FLOODLIGHT) {
await this.p2pSession.sendCommandWithIntString({
commandType: types_2.CommandType.CMD_DEV_LED_SWITCH,
value: value === true ? 1 : 0,
valueSub: device.getChannel(),
strValue: this.rawStation.member.admin_user_id,
channel: device.getChannel()
}, {
property: propertyData
});
}
else if (device.isIndoorCamera() || device.isFloodLight()) {
await this.p2pSession.sendCommandWithStringPayload({
commandType: types_2.CommandType.CMD_DOORBELL_SET_PAYLOAD,
value: JSON.stringify({
"commandType": types_2.CommandType.CMD_INDOOR_LED_SWITCH,
"data": {
"enable": 0,
"index": 0,
"status": 0,
"type": 0,
"value": value === true ? 1 : 0,
"voiceID": 0,
"zonecount": 0,
"mediaAccountInfo": {
"deviceChannel": device.getChannel(),
"device_sn": device.getSerial(),
"device_type": -1,
"mDeviceName": device.getName(),
"mDidStr": this.rawStation.p2p_did,
"mHubSn": this.getSerial(),
"mInitStr": this.rawStation.app_conn,
"mReceiveVersion": "",
"mTimeInfo": "",
"mVersionName": ""
},
"transaction": `${new Date().getTime()}`
},
}),
channel: device.getChannel()
}, {
property: propertyData
});
}
else if (device.isSoloCameras()) {
await this.p2pSession.sendCommandWithStringPayload({
commandType: types_2.CommandType.CMD_DOORBELL_SET_PAYLOAD,
value: JSON.stringify({
"commandType": types_2.CommandType.CMD_INDOOR_LED_SWITCH,
"data": {
"enable": 0,
"index": 0,
"status": 0,
"type": 0,
"url": "",
"value": value === true ? 1 : 0,
"voiceID": 0,
"zonecount": 0,
"mediaAccountInfo": {
"deviceChannel": device.getChannel(),
"device_sn": device.getSerial(),
"device_type": -1,
"mDeviceName": device.getName(),
"mDidStr": this.rawStation.p2p_did,
"mHubSn": this.getSerial(),
"mInitStr": this.rawStation.app_conn,
"mReceiveVersion": "",
"mTimeInfo": "",
"mVersionName": ""
},
"transaction": `${new Date().getTime()}`,
}
}),
channel: device.getChannel()
}, {
property: propertyData
});
}
else if (device.isBatteryDoorbell() || device.isWiredDoorbellDual()) {
await 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_BAT_DOORBELL_SET_LED_ENABLE,
"mValue3": 0,
"payload": {
"light_enable": value === true ? 1 : 0
}
}),
channel: device.getChannel()
}, {
property: propertyData
});
}
else if (device.isWiredDoorbell()) {
await this.p2pSession.sendCommandWithStringPayload({
commandType: types_2.CommandType.CMD_DOORBELL_SET_PAYLOAD,
value: JSON.stringify({
"commandType": types_1.ParamType.COMMAND_LED_NIGHT_OPEN,
"data": {
"status": value === true ? 1 : 0
}
}),
channel: device.getChannel()
}, {
property: propertyData
});
}
else {
throw new error_1.NotSupportedError(`This functionality is not implemented or supported by ${device.getSerial()}`);
}
}
async setAutoNightVision(device, value) {
const propertyData = {
name: types_1.PropertyName.DeviceAutoNightvision,
value: value
};
if (device.getStationSerial() !== this.getSerial()) {
throw new error_1.WrongStationError(`Device ${device.getSerial()} is not managed by this station ${this.getSerial()}`);
}
if (!device.hasProperty(propertyData.name)) {
throw new error_1.NotSupportedError(`This functionality is not implemented or supported by ${device.getSerial()}`);
}
this.log.debug(`Sending autonightvision command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`);
await this.p2pSession.sendCommandWithIntString({
commandType: types_2.CommandType.CMD_IRCUT_SWITCH,
value: value === true ? 1 : 0,
valueSub: device.getChannel(),
channel: device.getChannel()
}, {
property: propertyData
});
}
async setNightVision(device, value) {
const propertyData = {
name: types_1.PropertyName.DeviceNightvision,
value: value
};
if (device.getStationSerial() !== this.getSerial()) {
throw new error_1.WrongStationError(`Device ${device.getSerial()} is not managed by this station ${this.getSerial()}`);
}
if (!device.hasProperty(propertyData.name)) {
throw new error_1.NotSupportedError(`This functionality is not implemented or supported by ${device.getSerial()}`);
}
this.log.debug(`Sending nightvision command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`);
await 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_NIGHT_VISION_TYPE,
"mValue3": 0,
"payload": {
"channel": device.getChannel(),
"night_sion": value,
}
}),
channel: device.getChannel()
}, {
property: propertyData
});
}
async setMotionDetection(device, value) {
const propertyData = {
name: types_1.PropertyName.DeviceMotionDetection,
value: value
};
if (device.getStationSerial() !== this.getSerial()) {
throw new error_1.WrongStationError(`Device ${device.getSerial()} is not managed by this station ${this.getSerial()}`);
}
if (!device.hasProperty(propertyData.name)) {
throw new error_1.NotSupportedError(`This functionality is not implemented or supported by ${device.getSerial()}`);
}
this.log.debug(`Sending motion detection command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`);
if (device.isIndoorCamera() || (device.isFloodLight() && device.getDeviceType() !== types_1.DeviceType.FLOODLIGHT)) {
await this.p2pSession.sendCommandWithStringPayload({
commandType: types_2.CommandType.CMD_DOORBELL_SET_PAYLOAD,
value: JSON.stringify({
"commandType": types_2.CommandType.CMD_INDOOR_DET_SET_MOTION_DETECT_ENABLE,
"data": {
"enable": 0,
"index": 0,
"status": value === true ? 1 : 0,
"type": 0,
"value": 0,
"voiceID": 0,
"zonecount": 0
}
}),
channel: device.getChannel()
}, {
property: propertyData
});
}
else if (device.isSoloCameras()) {
await this.p2pSession.sendCommandWithStringPayload({
commandType: types_2.CommandType.CMD_DOORBELL_SET_PAYLOAD,
value: JSON.stringify({
"commandType": types_2.CommandType.CMD_INDOOR_DET_SET_MOTION_DETECT_ENABLE,
"data": {
"enable": 0,
"index": 0,
"status": value === true ? 1 : 0,
"type": 0,
"url": "",
"value": 0,
"voiceID": 0,
"zonecount": 0
}
}),
channel: device.getChannel()
}, {
property: propertyData
});
}
else if (device.isWiredDoorbell()) {
await this.p2pSession.sendCommandWithStringPayload({
commandType: types_2.CommandType.CMD_DOORBELL_SET_PAYLOAD,
value: JSON.stringify({
"commandType": types_1.ParamType.COMMAND_MOTION_DETECTION_PACKAGE,
"data": {
"enable": value === true ? 1 : 0,
}
}),
channel: device.getChannel()
}, {
property: propertyData
});
}
else {
await this.p2pSession.sendCommandWithIntString({
commandType: types_2.CommandType.CMD_PIR_SWITCH,
value: value === true ? 1 : 0,
valueSub: device.getChannel(),
strValue: this.rawStation.member.admin_user_id,
channel: device.getChannel()
}, {
property: propertyData
});
}
}
async setSoundDetection(device, value) {
const propertyData = {
name: types_1.PropertyName.DeviceSoundDetection,
value: value
};
if (device.getStationSerial() !== this.getSerial()) {
throw new error_1.WrongStationError(`Device ${device.getSerial()} is not managed by this station ${this.getSerial()}`);
}
if (!device.hasProperty(propertyData.name)) {
throw new error_1.NotSupportedError(`This functionality is not implemented or supported by ${device.getSerial()}`);
}
this.log.debug(`Sending sound detection command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`);
await this.p2pSession.sendCommandWithStringPayload({
commandType: types_2.CommandType.CMD_DOORBELL_SET_PAYLOAD,
value: JSON.stringify({
"commandType": types_2.CommandType.CMD_INDOOR_DET_SET_SOUND_DETECT_ENABLE,
"data": {
"enable": 0,
"index": 0,
"status": value === true ? 1 : 0,
"type": 0,
"value": 0,
"voiceID": 0,
"zonecount": 0
}
}),
channel: device.getChannel()
}, {
property: propertyData
});
}
async setSoundDetectionType(device, value) {
const propertyData = {
name: types_1.PropertyName.DeviceSoundDetectionType,
value: value
};
if (device.getStationSerial() !== this.getSerial()) {
throw new error_1.WrongStationError(`Device ${device.getSerial()} is not managed by this station ${this.getSerial()}`);
}
if (!device.hasProperty(propertyData.name)) {
throw new error_1.NotSupportedError(`This functionality is not implemented or supported by ${device.getSerial()}`);
}
const property = device.getPropertyMetadata(propertyData.name);
(0, utils_3.validValue)(property, value);
this.log.debug(`Sending sound detection type command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`);
await this.p2pSession.sendCommandWithStringPayload({
commandType: types_2.CommandType.CMD_DOORBELL_SET_PAYLOAD,
value: JSON.stringify({
"commandType": types_2.CommandType.CMD_INDOOR_DET_SET_SOUND_DETECT_TYPE,
"data": {
"enable": 0,
"index": 0,
"status": 0,
"type": value,
"value": 0,
"voiceID": 0,
"zonecount": 0
}
}),
channel: device.getChannel()
}, {
property: propertyData
});
}
async setSoundDetectionSensitivity(device, value) {
const propertyData = {
name: types_1.PropertyName.DeviceSoundDetectionSensitivity,
value: value
};
if (device.getStationSerial() !== this.getSerial()) {
throw new error_1.WrongStationError(`Device ${device.getSerial()} is not managed by this station ${this.getSerial()}`);
}
if (!device.hasProperty(propertyData.name)) {
throw new error_1.NotSupportedError(`This func