This commit is contained in:
2025-11-11 00:04:55 -06:00
parent a76ad41fde
commit 40538eddfd
6405 changed files with 1289756 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.git
node_modules
build
*.tgz
.DS_Store

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-2024 bropat <patrick.broetto@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

927
README.md
View File

@ -0,0 +1,927 @@
# eufy-security-client
![Logo](docs/_media/eufy-security-client.png)
[![node](https://img.shields.io/node/v/eufy-security-client.svg)](https://www.npmjs.com/package/eufy-security-client)
[![NPM version](http://img.shields.io/npm/v/eufy-security-client.svg)](https://www.npmjs.com/package/eufy-security-client)
[![Downloads](https://img.shields.io/npm/dm/eufy-security-client.svg)](https://www.npmjs.com/package/eufy-security-client)
[![Total Downloads](https://img.shields.io/npm/dt/eufy-security-client.svg)](https://www.npmjs.com/package/eufy-security-client)
[![Dependency Status](https://img.shields.io/librariesio/release/npm/eufy-security-client)](https://libraries.io/npm/eufy-security-client)
[![Known Vulnerabilities](https://snyk.io/test/github/bropat/eufy-security-client/badge.svg)](https://snyk.io/test/github/bropat/eufy-security-client)
[![NPM](https://nodei.co/npm/eufy-security-client.png?downloads=true)](https://nodei.co/npm/eufy-security-client/)
Join us on Discord:
<a target="_blank" href="https://discord.gg/5wjQ2asb64"><img src="https://dcbadge.limes.pink/api/server/5wjQ2asb64" alt="" /></a>
The development of this shared library was inspired by the work of the following people:
* FuzzyMistborn (<https://github.com/FuzzyMistborn/python-eufy-security>)
* keshavdv (<https://github.com/keshavdv/python-eufy-security>)
* JanLoebel (<https://github.com/JanLoebel/eufy-node-client>)
Credits go to them as well.
If you appreciate my work and progress and want to support me, you can do it here:
[![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/E1E332Q6Z)
[![Donate](https://img.shields.io/badge/Donate-PayPal-blue.svg)](https://www.paypal.me/pbroetto)
**This project is not affiliated with Anker and Eufy (Eufy Security). It is a personal project that is maintained in spare time.**
## Description
This shared library allows to control [Eufy security devices](https://us.eufylife.com/collections/security) by connecting to the Eufy cloud servers and local/remote stations over p2p.
You need to provide your Cloud login credentials.
One client instance will show all devices from one Eufy Cloud account and allows to control them.
## Features
* Connects to Eufy cloud (supports 2fa)
* Connects to station/devices using p2p communication (supported: local and remote connectivity)
* Supports receiving push notification (unified push messages interface)
* Basic P2P implementation that supports also commands not already implemented
* Get info and parameters from stations/devices over https and/or p2p
* P2P functionality already implemented:
* Station:
* Change guard mode
* Reboot station
* Devices:
* Start livestream (local/remote p2p or rtmp over cloud)
* Stop livestream (local/remote p2p or rtmp over cloud)
* Enable/disable device
* Enable/disable auto night vision (only camera products)
* Enable/disable led (only camera 2 products, indoor cameras, floodlight camera, solo cameras and doorbells)
* Enable/disable anti-theft detection (only camera 2 products)
* Enable/disable motion detection
* Enable/disable pet detection (only indoor cameras)
* Enable/disable sound detection (only indoor cameras)
* Enable/disable RTSP stream (only camera2 products, indoor cameras and solo cameras)
* Change video watermark setting (only camera products)
* Start/cancel download video
* Quick response (only doorbells)
* Lock/unlock (only smart lock products)
* And many more, check it out...
## Documentation
Look [here](https://bropat.github.io/eufy-security-client/).
*As an example, you can look at the following projects: [ioBroker.eufy-security](https://github.com/bropat/ioBroker.eufy-security), [eufy-security-ws](https://github.com/bropat/eufy-security-ws), [eufy_security](https://github.com/fuatakgun/eufy_security)*
## Quick Start
Install via npm:
```bash
npm install eufy-security-client
```
Then import and use in TypeScript:
```typescript
import { EufySecurity } from "eufy-security-client";
// ...existing code...
const eufyClient = new EufySecurity();
// ...existing code...
```
## Known working devices
For a list of supported devices, please see [here](https://bropat.github.io/eufy-security-client/#/supported_devices).
If more devices work (or also not) please report them by opening a GitHub issue.
## How to report issues and feature requests
Please use GitHub issues for this.
## Deployment
Instructions aimed at maintainers for deploying a new version: [Deployment](docs/deployment.md)
## Changelog
### 3.2.0 (2025-04-02)
* (martijnpoppen) FIX: Indoor Cam P&T sw update 2.3.1.2 on/off #604
* (SmolSoftBoi) Add error handling for MQTT proto file loading and improve logging #584
* (ChayoteJarocho) Add missing entry for Wall Cam 81A0 battery #570
* (jarodwilson) NEW: add SoloCam E30 (T8171) & FloodLight E30 (T8426) #583
* (martijnpoppen) FIX: enableEmbeddedPKCS1Support #595
* (NicolaiVdS & martijnpoppen) NEW: Battery doorbell C30 & C31 #600
* (martijnpoppen) NEW: add support for Indoor Cam C210 (T8419) & C220 (T8W11C) #596
* (martijnpoppen) NEW: add support for Eufycam S3 Pro - T8162 #594
* (martijnpoppen) NEW: Add Device Alarm to multiple camera #602
### 3.1.1 (2024-09-28)
* (bropat) Added RTSP support for Indoor Cam S350 (T8416)
* (bropat) Fixed draining issues for some battery powered devices (instead of #544)
* (bropat) Fixed standalone support for Indoor Cam S350 (T8416; #550)
* (bropat) Fixed issue with encryption type level 2
* (bropat) Fixed issue #502 (untested)
* (bropat) Fixed issue #539
* (bropat) Fixed issue #547
* (PhilippEngler) FIX: hasCommand for DevicePresetPosition, DeviceSavePresetPosition and DeviceDeletePresetPosition (#551)
* (PhilippEngler) added preset commands T8170 (#552)
### 3.1.0 (2024-08-27)
* (bropat) **Breaking Change** Requires node version >= 20.0.0
* (martijnpoppen) NEW: add deviceConfig with simultaneousDetections option (#494)
* (PhilippEngler) added StationTimeZoneProperty (#472)
* (martijnpoppen) FIX: HB3 Doorbell Known Face detection not coming trough and Doorbell Ringing (#495)
* (bropat/lenoxys) Added ability to disable automatic cloud polling (#533)
* (bropat/PhilippEngler) Added ability to choose listening port of p2p station communication (#473)
* (bropat) Added vehicleDetected property to Floodlight Cam E340 (T8425)
* (bropat) Implemented runaway limit during parsing of p2p message data (infinite loop detection)
* (bropat) Added new EufySecurity options enableEmbeddedPKCS1Support (possible workaround for issue #487)
* (bropat) Added more logging about the initiation of P2P connections
* (bropat) Added more authentication log for info level
* (bropat) Improved livestream handling
* (PhilippEngler) update T8416 support (#535)
* (PhilippEngler) update T8170 support (#536)
* (bassrock) fix(bool): convert numeric to boolean (#523)
* (bropat) Fixed issue #482
* (bropat) Fixed an unhandled case that led to a infinite loop when parsing p2p messages
* (bropat) Fixed possible incorrect initiation of a P2P reconnection
* (bropat) Fixed some more property parsing
* (bropat) Possible fix for some locks missing some metadata
* (bropat) Updated versions of the package dependencies
### 3.0.0 (2024-03-03)
* (bropat) **Breaking Change** New modular logging implementation
* (bropat) Added support for Video Smart Lock S330 (T8530; #220)
* (bropat) Added support for Smart Lock C210 (T8502; #291)
* (bropat) Added support for Smart Lock C220 (T8506; #377 #356)
* (bropat) Added support for Smart Lock S230 (T8510P; #458)
* (bropat) Added support for Smart Lock S231 (T8520P; untested)
* (bropat) Added support for Retrofit Smart Lock E110 (T8503; #208)
* (bropat) Added support for Retrofit Smart Lock E130 (T8504; untested)
* (bropat) Added support for Smart Drop S300 (T8790; #261 #364)
* (bropat/martijnpoppen) Added support for Video Doorbell E340 (T8214; #406)
* (martijnpoppen) Added support for MiniBase Chime (T8023)
* (bropat/martijnpoppen) Added support for eufyCam E330 (Professional; T8600; #408)
* (bropat/martijnpoppen) Added support for Solar Wall Light Cam S120 (T84A0; #409)
* (bropat/martijnpoppen) Added support for SoloCam S340 (T8170; #410)
* (bropat) Added support for Indoor Cam S350 (T8416; #398)
* (bropat) Added support for Floodlight Cam E340 (T8425; #388)
* (bropat) Added support for SoloCam C210 (T8B00; #369)
* (bropat) Outdated, no longer functioning cloud livestream has been removed
* (bropat) Improved cloud device lookup
* (bropat) Implemented new image gathering from p2p initiated by push notifications
* (bropat) Implemented new p2p parameter format
* (bropat) Implemented calibrate command for Floodlight T8423 (#280)
* (martijnpoppen) OPT: persistentData via config instead of JSON file (#416)
* (PhilippEngler) changed description of state of DualCamWatchViewMode (#402)
* (PhilippEngler) Added support for storage info on HomeBase 3 (#405)
* (bropat) Added default values for some properties
* (bropat) Lowered p2p keepalive interval for battery saving devices
* (bropat) Added name of the person who locked/unlocked the lock
* (bropat) Added origin who locked/unlocked the lock
* (bropat) Changed to simultaneous triggering of different detection types by receiving of a single type of push notification
* (PhilippEngler) Updated device types (#478)
* (PhilippEngler) Add DeviceNotificationIntervalTimeProperty to indoor cams (#471)
* (PhilippEngler) Added storage info fpr S100 (#412)
* (martijnpoppen) FIX: vehicle detection S340 (#475)
* (PhilippEngler) Make StationStorageInfoProperties readonly (#474)
* (PhilippEngler) Solve TypeError in handleMsg (#469)
* (PhilippEngler) Fixed description of state of DualCamWatchViewMode (#402)
* (martijnpoppen) FIX: Eufy e330 remove battery (#445)
* (bropat) Fixed issue #380
* (bropat) Fixed issue #323
* (bropat) Fixed issue #452
* (bropat) Fixed decode of parameters
* (bropat) Fixed: not all types of motion detection can be deactivated at the same time (fallback to last value)
* (bropat) Fixed issue that caused long running p2p livestreams to be interrupted (#431)
* (bropat/PhilippEngler) Fixed possible double api connect event (#439)
* (bropat) Fixed possible issue with loading persistent data for cloud api
* (bropat) Fixed api internal session invalidation
* (bropat) Fixed update processing and persistent data consistency
* (bropat) Fixed persistent data saving
* (bropat) Fixed push notification in connection with HomeBase 3
### 2.9.1 (2023-11-04)
* (bropat) Fixed data decryption for p2p command responses
### 2.9.0 (2023-11-04)
* (bropat) **Breaking Change** Requires node version >= 18.0.0
* (bropat) Added support for SmartTrack Link (T87B0; #385) and SmartTrack Card (T87B2; untested)
* (bropat/martijnpoppen) NEW: add support for S220 (T8134; #353)
* (bropat) Implemented data decryption for p2p command responses
* (bropat) Migrated API getCiphers method to v2 endpoint
* (bropat) Migrated API getInvites method to v2 endpoint
* (bropat) Migrated to Buffer.subarray from deprecated Buffer.slice method
* (bropat) Migrated to new sdcard info gathering over p2p (#373)
* (bropat) Fixed parsing of push notification for sensor open status (#372)
* (bropat) Fixed API getHouseInviteList method (removed encryption)
* (bropat) Fixed device type for lock T8506
* (PhilippEngler) Fixed StatusLed property for doorbell dual (#374)
* (bropat) Updated docs with new device names
* (bropat) Updated versions of the package dependencies
### 2.8.1 (2023-08-31)
* (bropat) Automatic detection of supported P2P encryption (none, type1, type2)
* (bropat) Fixed regression introduced with activating p2p encryption for all devices (some older devices do not support it!)
* (bropat) Updated versions of the package dependencies
### 2.8.0 (2023-08-20)
* (bropat) Implemented p2p data encryption for all supported commands
* (bropat) Improved updating of properties taking into account the priority/quality of the value source (http, p2p, push, mqtt)
* (bropat) API request throttling optimised
* (bropat) Fixed updating of the image property
### 2.7.1 (2023-08-08)
* (bropat) Fixed regression introduced by commit 7471fbf (Fixed possible MaxListenersExceededWarning)
* (bropat) Fixed issue not loading p2p properties over p2p connection for stations (HB2 and HB3)
### 2.7.0 (2023-08-01)
* (bropat) Added support for Wired Wall Light Cam S100 (T84A1; #318)
* (bropat) Added support for Garage-Control Cam (T8452; #219)
* (bropat) Implemented entry sensor status update over p2p connection
* (bropat) Improved cloud device lookup
* (bropat) Improved error handling
* (bropat/witold-gren) Added missing station command support for 4G LTE Starlight (T8151; #333)
* (bropat/witold-gren) Added missing push notification support for 4G LTE Starlight (T8151; #333)
* (bropat/witold-gren) Fixed issue handling push notification alarm events (#333)
* (bropat) Fixed image property not updating correctly
* (bropat) Fixed issue of executing the download image command only if supported
* (PhilippEngler) fix DeviceChargingStatus for eufyCam3 (#330)
* (PhilippEngler) handle incomplete JSON for parameter (#347)
* (bropat) Initiate p2p connection for supported devices only
* (bropat) Updated versions of the package dependencies
### 2.6.2 (2023-05-16)
* (bropat) Fixed issue waiting for device/station loading event in some cases
* (martijnpoppen) FIX: doorbell push not parsed when connected to HB3 #325
### 2.6.1 (2023-05-13)
* (bropat) Fixed an issue that caused the event "livestream started" to be emit twice
* (bropat) Added some missing properties (package detection) for doorbell solo (T8203)
* (bropat) Migrated from dependency protobuf-typescript to protobufjs
### 2.6.0 (2023-05-12)
* (bropat) Implemented access to local event history (database on station)
* (bropat) Implemented download of first picture from local database for supported devices
* (martijnpoppen) FIX: HB3 notifications - (exclude sensors) #324
### 2.5.1 (2023-05-07)
* (bropat) Fixed issue in downloading `cover_path` picture for supported devices
### 2.5.0 (2023-05-07)
* (bropat) **Breaking Change** `picture_url` property is now hidden and was replaced by `picture` property for supported devices
* (bropat) Implemented new push notification picture gathering and decryption
* (bropat) Fixed sdcard info gathering for devices without sdcard inserted
### 2.4.4 (2023-04-21)
* (bropat) Implemented feature request #313
* (bropat) Fixed issue #316
* (bropat) Updated versions of the package dependencies
### 2.4.3 (2023-04-11)
* (martijnpoppen) FIX: HB3 connected sensors not reporting (#314)
* (PhilippEngler) Fix problem when the P2PDID number is starting with zeros
* (bropat) Updated versions of the package dependencies
### 2.4.2 (2023-02-23)
* (bropat) Improved local discovery of stations over p2p
* (bropat) Fixed issue in API communication when no stations and devices are found
### 2.4.1 (2023-02-19)
* (bropat) Added support for configuring a suggested IP address for a station
* (bropat) Fixed json parse issue with null-terminated strings
* (bropat) Fixed p2p keepalive issue
* (bropat/martijnpoppen) Fixed Invalid Property personDetected error for some floodlight cams
* (PhilippEngler) Finished implementation of getStorageInfo
* (bropat) Removed dependency mediainfo.js
### 2.4.0 (2022-12-24)
* (bropat) Implemented new encrypted cloud API communication (v2)
* (bropat) Added support for 4G LTE Starlight camera (T8150; #209; #231)
* (bropat) Implemented client-side termination of the stream (live/download; #258)
* (bropat) Fixed issue #271
* (bropat) Fixed issue #283
* (bropat) Fixed issue #287
* (martijnpoppen) FIX: webAPi stream request (#275)
* (martijnpoppen) FIX: support V2 for getPassportProfile (V1 deprecated; #282)
* (martijnpoppen) FIX: always encrypt login with server key. (#285)
* (PhilippEngler) update _getEvents for v2 (#286)
* (bropat) Fixed wrong variable names in pull request (#286)
* (bropat) Updated versions of the package dependencies
### 2.3.0 (2022-11-26)
* (bropat) Added support for Wired Doorbell (T8200X)
* (bropat) Added new property `snoozeStartTime`, `snoozeHomebase`, `snoozeChime` and `snoozeMotion` to supported devices
* (bropat) Added debug information for analysed audio and video codecs at start of livestream
* (bropat/martijnpoppen) Added new command `stationChime` for supported stations
* (bropat) Implemented fallback for configured empty string for setting `trustedDeviceName`
* (bropat) Implemented missing Homebase 3 notification events
* (bropat) Fixed unknown video codec issue
* (bropat) Fixed issue #240
* (smitty078) Fixed issue #251
* (thieren) Fixed issue #256 (#255)
* (tyware) Fixed issue #257
* (bropat) Fixed issue #258
* (PhilippEngler) Change DeviceChargingStatusProperty value for eufyCam 3c (#254)
* (PhilippEngler) Fixed doubled property labels (#253)
* (martijnpoppen) FIX: keypad wifiSignalLevel property error (#245)
* (martijnpoppen) FIX: issue when params are not available for rawDevice/rawStation (#246)
### 2.2.3 (2022-11-12)
* (bropat) Added Station alarm properties
* (bropat) Added `connection error` event to HTTPApi and EufySecurity
* (bropat) Changed default value of `trustedDeviceName`
* (martijnpoppen) NEW: HB3 Vehicle Detection (#241)
### 2.2.2 (2022-11-06)
* (bropat) Fixed issue identifying alarm delay
### 2.2.1 (2022-11-05)
* (bropat) Added support for Floodlight Cam (T8420X)
* (Palmke) Implemented Homebase 3 familiar faces (#237)
* (bropat) Fixed regression in Station.startDownload
* (Palmke) Fixed issue #236
* (bropat) Fixed issue #233
* (bropat) Small bugfixes
### 2.2.0 (2022-11-01)
* (bropat) **Breaking Change** Renamed all lock settings parameters according to standard
* (bropat) **Breaking Change** Station class initialization is now async
* (bropat) Renewed p2p device address discovery (now also includes local discovery via broadcast; cloud discovery optimised)
* (bropat) Added support for Doorbell Dual notification types (package delivered, package taken, package stranded, someone loitering, radar motion detected)
* (bropat) Added support for eufyCam 3C (#233)
* (bropat) Added support for eufyCam 3 (#228)
* (bropat) Added support for Homebase 3 (#228)
* (bropat) Added support to programmatically add access to lock (#204)
* (thieren) Added station event for connection timeout (#202)
* (bropat) Added Smart Safe support (tested only T7400; #182)
* (bropat) Added snooze command for supported devices (#173, #176)
* (bropat) Added support for video type store to NAS for indoor cameras (#147)
* (bropat) Switched API login to new login_sec endpoint
* (bropat) Incremented p2p disconnect timeout for energy saving device to 30 seconds
* (bropat) Implemented new resend of not acknowledged p2p commands
* (bropat) Fixed issue with energy saving measures interrupting running streams
* (bropat) Better error handling for not supported p2p commands
* (bropat) Fixed signalling of event `station command result`
* (bropat) Fixed local device discovery exception (udp broadcast)
* (bropat) Fixed checking of valid property values (function validValues)
* (bropat) Fixed regression in parsing lock push notifications
* (bropat) Fixed updating of device properties on p2p command result event for some devices
* (bropat) Fixed parsing of raw values of property `motionDetectionSensitivity`
* (bropat) Fixed MQTT certification verification for some eufy servers (disabled certification verrification, since some server have expired certs)
* (bropat) Fixed emitting of event "locked" for lock devices
* (bropat) Fixed issue #227
* (bropat) Fixed issue #215
* (bropat) Fixed issue #212
* (bropat) Fixed issue #207
* (bropat) Fixed issue #201
* (bropat) Fixed issue #196
* (martijnpoppen) FIX: set DevicePictureUrl for sound and crying (#234)
* (bropat) Small bugfixes and optimizations
* (bropat) Updated docs - Added partial supported device HomeBase 3 (T8030, S380)
* (bropat) Updated docs - Added supported devices eufyCam 3 (T8160, S330), eufyCam 3C (T8161, S300)
* (bropat) Updated docs - Added supported devices Smart Safe S10 (T7400), Smart Safe S12 (T7401)
* (bropat) Updated docs - Added supported devices SoloCam L20 (T8122), SoloCam L40 (T8123), SoloCam S40 (T8124), SoloCam E20 (T8130)
* (bropat) Changed default persistent directory path for saving persistent data
### 2.1.2 (2022-07-30)
* (Palmke) Dual Doorbell family detection (#177)
* (Palmke) Fixed issue #187
* (bropat) Fixed issue #186
### 2.1.1 (2022-07-16)
* (Palmke) Add alarm arm delay event (#180)
* (thieren) Fix: stream command for T8420 (#171)
* (Palmke) Don't send the alarm armed p2p events as alarm events (#169)
* (bropat) Fixed issue #167
* (bropat) Fixed issue #161
* (bropat) Updated versions of the package dependencies
### 2.1.0 (2022-06-12)
* (bropat) Added toggle for Spotlight for Outdoor Cam Pro (T8441; #123)
* (bropat & thieren) Added talkback commands for supported devices (#38, #153; thanks @thieren)
* (fabianluque) Added missing RTSP properties for Floodlight T8423 (#146)
* (Palmke) Add alarm delay event (#88, #155)
* (Palmke) P&T T8410: Set motion zone and image mirror (#156)
* (Palmke) Send an event when the alarm is armed and alarm events from p2p (#105, #157)
* (bropat) Implemented simple request throttling for Eufy Cloud
* (bropat) Fixed push notification token renewal
* (bropat) Fixed issue #161
### 2.0.1 (2022-05-03)
* (bropat) **Breaking Change** Fixed regression in device data loading
* (bropat) Target set back to ES2019
### 2.0.0 (2022-04-30)
* (bropat) **Breaking Change** Requires node version >= 14.17
* (bropat) **Breaking Change** HTTPApi class, EufySecurity class and Device classes instantiation changed
* (bropat) **Breaking Change** Timestamp for device and station properties has been removed
* (bropat) Added support for Battery Doorbell Dual (T8213; #126)
* (bropat) Added support for Video Doorbell Dual (T8203; #141)
* (bropat) Added support for IndoorCam Mini (T8414; #143)
* (bropat) Added continuos recording setting for some supported cameras
* (bropat) Added continuos recording type setting for some supported cameras
* (bropat) Added default angle setting for IndoorCam Mini (T8414)
* (bropat) Added default angle idle time setting for IndoorCam Mini (T8414)
* (bropat) Added notification interval time setting for some supported cameras
* (bropat) Added calibrate command for some supported cameras
* (bropat) Added set default angle command for IndoorCam Mini (T8414
* (bropat) Added set privacy angle command for IndoorCam Mini (T8414)
* (bropat) Removed PREFER_LOCAL P2P connectivity mode. Default mode is now QUICKEST.
* (bropat) Added new charging status "solar charging" (value: 4; issue #127)
* (bropat) Fixed Eufy cloud authentication token renewal
* (bropat) Fixed some Eufy cloud authentication issues
* (bropat) Fixed authentication issues when changing country setting
* (bropat) Fixed possible wrong battery values on some devices
* (bropat) Fixed issue if device doesn't support P2P communication
* (bropat) Fixed issue #136
* (bropat) Fixed issue #122
* (bropat) Updated versions of the package dependencies
### 1.6.6 (2022-02-12)
* (bropat) Fixed issue where no devices/stations are found (#116)
### 1.6.5 (2022-02-08)
* (bropat) Fixed regression in authentication flow introduced when fixing issue #116
* (bropat) Updated versions of the package dependencies
### 1.6.4 (2022-02-07)
* (bropat) Fixed issue #116 (choosing the correct country as in the Eufy App is esentially)
**Note:** Selecting the correct country is essential for the devices to be found (should match the setting in the Eufy app).
### 1.6.3 (2022-02-06)
* (bropat) Initialize MQTT connection only if supported devices are found
### 1.6.2 (2022-02-05)
* (bropat) Fixed MQTT connection issue (error: 5)
### 1.6.1 (2022-02-05)
* (bropat) Fixed small issue on driver upgrade of persistence data (has no impact; error entry in log on first startup)
### 1.6.0 (2022-02-05)
* (bropat) Supports new [Home Management](https://communitysecurity.eufylife.com/t/tips-for-eufy-security-app-v4-0/2420747) feature of Eufy Security 4.0
* (bropat) Added support for Smart Lock Touch & Wifi (T8520; #89)
* (bropat) Implemented Eufy MQTT notification subscription for Smart Lock Touch & Wifi (T8520)
* (bropat) Added auto lock setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added auto lock schedule setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added auto lock schedule start time setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added auto lock schedule end time setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added auto lock timer setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added notification setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added notification locked setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added notification unlocked setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added one touch locking setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added scramble passcode setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added sound setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added wrong try protection setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added wrong try attempts setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added wrong try lockdown time setting for Smart Lock Touch & Wifi (T8520)
* (bropat) Added lock/unlock command for Smart Lock Touch & Wifi (T8520)
* (bropat) Added lock calibration command for Smart Lock Touch & Wifi (T8520)
* (bropat) Improved p2p communication with energy saving devices
* (bropat) Added new HTTPApi methods supporting Eufy Security 4.0
* (bropat) Some small improvements were made to the HTTPApi
* (bropat) Fixed issue #97
* (bropat) Fixed issue #102
* (bropat) Fixed issue #109
* (bropat) Updated versions of the package dependencies
### 1.5.0 (2021-12-19)
* (bropat) Added support for floodlight cam 2 pro (T8423)
* (bropat) Added motion detection range setting for floodlight cam 2 pro (T8423)
* (bropat) Added motion detection range standard sensitivity setting for floodlight cam 2 pro (T8423)
* (bropat) Added motion detection range advanced left sensitivity setting for floodlight cam 2 pro (T8423)
* (bropat) Added motion detection range advanced middle sensitivity setting for floodlight cam 2 pro (T8423)
* (bropat) Added motion detection range advanced right sensitivity setting for floodlight cam 2 pro (T8423)
* (bropat) Added motion detection range test mode setting for floodlight cam 2 pro (T8423)
* (bropat) Added motion tracking sensitivity setting for floodlight cam 2 pro (T8423)
* (bropat) Added motion auto-cruise setting for floodlight cam 2 pro (T8423)
* (bropat) Added motion out-of-view detection setting for floodlight cam 2 pro (T8423)
* (bropat) Added light setting color temperature manual setting for floodlight cam 2 pro (T8423)
* (bropat) Added light setting color temperature mamotion setting for floodlight cam 2 pro (T8423)
* (bropat) Added light setting color temperature schedule setting for floodlight cam 2 pro (T8423)
* (bropat) Added light setting motion activation mode setting for floodlight cam 2 pro (T8423)
* (bropat) Added video nightvision image adjustment setting for floodlight cam 2 pro (T8423)
* (bropat) Added video color nightvision setting for floodlight cam 2 pro (T8423)
* (bropat) Added auto calibration setting for floodlight cam 2 pro (T8423)
* (bropat) Added start/stop rtsp livestream command for floodlight cam 2 pro (T8423)
* (bropat) Added battery and wifi rssi properties to eufycam 1/E
* (bropat) Implemented another p2p-keepalive mechanism found in some floodlights (e.g. T8420)
* (bropat) Fixed support for floodlight (T8420) - tested with FW: 1.0.0.35 HW: 2.2
* (bropat) Fixed status led setting for floodlight (T8420)
* (bropat) Fixed motion detected setting for floodlight (T8420)
* (bropat) Fixed motion detected sensitivity setting for floodlight (T8420)
* (bropat) Fixed audio recording setting for floodlight (T8420)
* (bropat) Fixed enable/disable device for floodlight (T8420)
* (bropat) Fixed start livestream command for floodlight (T8420)
* (bropat) Fixed issue #79
* (bropat) Fixed issue #66
* (bropat) Fixed some other minor issues
* (bropat) Added docs (:construction:)
* (bropat) Updated versions of the package dependencies
### 1.4.0 (2021-11-22)
* (bropat) Implemented captcha authentication mechanism (API v2)
* (bropat) Fixed issue #69
### 1.3.0 (2021-11-20)
* (bropat) Implemented new encrypted authentication mechanism (API v2)
* (bropat) Dropped old plaintext authentication mechanism (API v1)
* (bropat) Fixed issue #67
* (bropat) Exchanged axios with got for HTTP/2 support
**Note:** If you have 2FA enabled, you will need to authenticate again after this update.
### 1.2.4 (2021-11-17)
* (bropat) Fixed issue #63
### 1.2.3 (2021-11-16)
* (bropat) Fixed issue #64
* (bropat) Fixed issue #65
* (bropat) Updated versions of the package dependencies
### 1.2.2 (2021-11-06)
* (bropat) Fixed issue of wrong channel value on event rtsp livestream stopped
* (bropat) Updated versions of the package dependencies
### 1.2.1 (2021-10-23)
* (bropat) Changed event detection for start/stop local RTSP streaming
* (bropat) Fixed regression introduced by fixing issue #51
* (bropat) Fixed new implementation that detects interrupted p2p streams
* (bropat) Fixed missing start/stop local RTSP streaming commands to hasCommand and getCommands
### 1.2.0 (2021-10-17)
* (bropat) Extended p2p implementation to better support solo cameras and other battery powered devices
* (bropat) Revised p2p implementation to send commands sequentially
* (bropat) Added support for Floodlight T8422
* (bropat) Added support for SoloCam E40 (T8131)
* (bropat) Added experimental feature for supported devices: start/stop local RTSP streaming
* (bropat) Added new properties for solo cameras: battery, batteryTemperature, wifiSignalLevel, state, chargingStatus, lastChargingDays, lastChargingRecordedEvents, lastChargingTotalEvents, batteryUsageLastWeek
* (bropat) Implemented interrupted p2p stream detection
* (bropat) Fixed issue #51
* (bropat) Fixed push notifications for solo cameras (motion and person detection)
* (bropat) Fixed "livestream stopped" if live stream is started for multiple devices of the same station (1 p2p session could start only 1 live stream at a time)
* (bropat) Fixed "download finished" if download is started for multiple devices of the same station (1 p2p session could start only 1 download at a time)
* (bropat) Fixed an issue where the P2P connection type PREFER_LOCAL did not attempt to connect if no local IP address was found
* (bropat) Updated versions of the package dependencies
### 1.1.2 (2021-08-19)
* (bropat) Fixed push notification issue on new indoor outdoor camera device (thx to @lenoxys)
* (bropat) Fixed issue where device doesn't support p2p connection
### 1.1.1 (2021-08-13)
* (bropat) Fixed p2p video streaming for some devices (fallback mechanism implemented)
* (bropat) Fixed p2p audio codec detection
### 1.1.0 (2021-08-11)
* (bropat) Added brightness light setting for 2c/2c pro cameras, new solo cameras and new outdoor cameras
* (bropat) Added enable/disable light setting for 2c/2c pro cameras, new solo cameras and new outdoor cameras
* (bropat) Added trigger/reset alarm sound for indoor cameras, solo cameras and floodlight cameras
* (bropat) Added video streaming quality setting for 2c pro cameras
* (bropat) Added video recording quality setting for 2c pro cameras
* (bropat) Added trigger alarm sound for indoor cameras, solo cameras (incl. new) and floodlight cameras
* (bropat) Added reset alarm sound for indoor cameras, solo cameras (incl. new) and floodlight cameras
* (bropat) Added battery charging state for keypad devices
* (bropat) Added new property "batteryIsCharging" for keypad devices
* (bropat) Added property "wifiRssi" for keypad devices
* (bropat) Added new property "nightvision" for devices supporting the "light" nightvision mode
* (bropat) Added new properties "switchModeWithAccessCode", "autoEndAlarm" and "turnOffAlarmWithButton" for station with registered keypad
* (bropat) Added default values for some properties that, if not set first, were not listed in the cloud response
* (bropat) Fixed issue with guard mode setting where the "Off" state was not handled correctly (only supported with keypad) (#27)
* (bropat) Fixed issue in class EufySecurity if start cloud stream command fails
* (bropat) Fixed issue with "locked" event for locks
* (bropat) Fixed issue with nightvision setting for devices with light (b&w, light, off)
* (bropat) Fixed issue in station property value conversion for number or boolean types
* (bropat) Fixed issue where "motionDetection" property was incorrectly updated instead of "motionDetected" when a push notification arrived
* (lenoxys) Handle Lock Push Event for Lock / Unlock #36
### 1.0.0 (2021-08-07)
* (bropat) Added new method "getSensorHistory" to HTTPApi class for getting entry sensor history data
* (bropat) Added new events "station connect" and "station close" to EufySecurity class
* (bropat) Added new "chargingStatus", "wifiSignalLevel", "rtspStreamUrl", "chirpVolume", "chirpTone", "videoHdr", "videoDistortionCorrection" and "videoRingRecord" properties for supported devices
* (bropat) Added enable/disable led setting for camera 1 products
* (bropat) Added motion detection sensitivity setting for camera 1 products and wired doorbell
* (bropat) Added motion detection type setting for camera 1 products
* (bropat) Added motion audio recording setting for camera 1 products and wired doorbell
* (bropat) Added ringtone volume setting for wired doorbell
* (bropat) Added enable/disable indoor chime setting for wired doorbell
* (bropat) Added notification ring setting for wired doorbell
* (bropat) Added notification motion setting for wired doorbell
* (bropat) Added video streaming quality setting for wired doorbell
* (bropat) Added video recording quality setting for wired doorbell
* (bropat) Added video HDR setting for wired doorbell
* (bropat) Added video distortion correction setting for wired doorbell
* (bropat) Added video ring recording setting for wired doorbell
* (bropat) Added notification type setting for camera 1 products, solo cameras and wired doorbell
* (bropat) Added chirp volume setting for entry sensor
* (bropat) Added chirp tone setting for entry sensor
* (bropat) Implemented queuing of p2p commands in class P2PClientProtocol if connection to station isn't already present
* (bropat) Renamed some properties for typo issues
* (bropat) Renamed some properties to correct the use of camelcase
* (bropat) Fixed issue where data was not updated (cloud and p2p polling)
* (bropat) Fixed issue with resetting api_base when changing credentials
* (bropat) Fixed some issues with clearing timeouts in class P2PClientProtocol
* (bropat) Fixed issue in class P2PClientProtocol not detecting video codec for some devices (#)
* (bropat) Fixed event "rtsp url" returning the url value containing nulls "\0"
* (bropat) Updated versions of the package dependencies
### 0.9.4 (2021-07-23)
* (bropat) Fixed regression on p2p connection timeout and reconnect tentatives
* (bropat) Updated versions of the package dependencies
### 0.9.3 (2021-07-20)
* (bropat) Fixed p2p livestream video regression
* (bropat) Merged #22 - Add custom modes in alarm mode (thx to @piitaya)
### 0.9.1 (2021-07-17)
* (bropat) Exported some missing error classes and types
* (bropat) Checking valid direction values for panAndTilt command
### 0.9.0 (2021-07-16)
* (bropat) **Breaking Change** Station/EufySecurity "guard mode" event changed to emit only the guard mode
* (bropat) Added Station/EufySecurity "current mode" event that emits only the current mode change
* (bropat) Added more Eufy Cloud error codes to "ResponseErrorCode"
* (bropat) Added more server push notification types to "ServerPushEvent"
* (bropat) Added pan an tilt functionality to supported indoor cameras
* (bropat) Added functionality to handle invitations on "HTTPApi"
* (bropat) Added error detection if stopping or starting stream that isn't running or already running
* (bropat) Added new setting "acceptInvitations" to "EufySecurity" to accept invitations automatically
* (bropat) Added floodlight camera light switch
* (bropat) Added motion detection sensitivity for indoor cameras, solo cameras, floodlight cameras, camera 2 products and battery doorbells
* (bropat) Added motion detection type for indoor cameras, solo cameras, floodlight cameras, camera 2 products and battery doorbells
* (bropat) Added motion tracking for indoor camera pan & tilt cameras
* (bropat) Added video stream quality setting for indoor cameras, solo cameras, floodlight cameras and battery doorbell
* (bropat) Added video recording quality setting for indoor cameras
* (bropat) Added WDR setting for battery doorbells
* (bropat) Added microphone mute setting for indoor cameras, solo cameras, floodlight cameras, camera 2 products and battery doorbells
* (bropat) Added audio recording setting for indoor cameras, solo cameras, floodlight cameras, camera 2 products and battery doorbells
* (bropat) Added enable/disable speaker setting for indoor cameras, solo cameras, floodlight cameras, camera 2 products
* (bropat) Added speaker volume setting for indoor cameras, solo cameras, floodlight cameras, camera 2 products and battery doorbells
* (bropat) Added power source setting for camera 2 products cameras, eufy cameras and eufy E cameras
* (bropat) Added power working mode setting for solo cameras, camera 2 products, battery doorbells, eufy cameras and eufy E cameras
* (bropat) Added power custom working mode recording clip length setting for solo cameras, floodlight cameras, camera 2 products, battery doorbells, eufy cameras and eufy E cameras
* (bropat) Added power custom working mode recording retrigger interval setting for solo cameras, floodlight cameras, camera 2 products, battery doorbells, eufy cameras and eufy E cameras
* (bropat) Added power custom working mode recording ends if motion stops setting for solo cameras, floodlight cameras, camera 2 products, battery doorbells, eufy cameras and eufy E cameras
* (bropat) Added video streaming quality setting for indoor cameras, solo cameras, floodlight cameras and battery doorbells
* (bropat) Added video recording quality setting for indoor 2k cameras
* (bropat) Added motion detection sensitivity setting for indoor cameras, floodlight cameras and camera 2 products
* (bropat) Added enable/disable motion tracking setting for indoor pan & tilt cameras
* (bropat) Added motion detection type setting for indoor cameras, solo cameras, floodlight cameras, camera 2 products and battery doorbells
* (bropat) Added enable/disable WDR setting for battery doorbells
* (bropat) Added ringtone volume setting for battery doorbells
* (bropat) Added enable/disable chime indoor setting for battery doorbells
* (bropat) Added enable/disable chime homebase setting for battery doorbells
* (bropat) Added chime homebase ringtone volume setting for battery doorbells
* (bropat) Added chime homebase ringtone type setting for battery doorbells
* (bropat) Added notification type setting for solo cameras, floodlight cameras, camera 2 products, battery doorbells, eufy cameras and eufy E cameras
* (bropat) Added enable/disable person notification setting for indoor cameras
* (bropat) Added enable/disable pet notification setting for indoor cameras
* (bropat) Added enable/disable all other motion notification setting for indoor cameras
* (bropat) Added enable/disable all sound notification setting for indoor cameras
* (bropat) Added enable/disable crying notification setting for indoor cameras
* (bropat) Added enable/disable motion notification setting for battery doorbells
* (bropat) Added enable/disable ring notification setting for battery doorbells
* (bropat) Added trigger alarm sound for camera 2 products
* (bropat) Added reset alarm sound for camera 2 products
* (bropat) Added trigger alarm sound for homebase 1+2
* (bropat) Added reset alarm sound for homebase 1+2
* (bropat) Added alarm tone setting for homebase 1+2
* (bropat) Added alarm volume setting for homebase 1+2
* (bropat) Added prompt volume setting for homebase 1+2
* (bropat) Added time format setting for homebase 1+2
* (bropat) Added enable/disable switch mode app notification setting for homebase 1+2
* (bropat) Added enable/disable switch mode geofence notification setting for homebase 1+2
* (bropat) Added enable/disable switch mode schedule notification setting for homebase 1+2
* (bropat) Added enable/disable switch mode keypad notification setting for homebase 1+2
* (bropat) Added enable/disable start alarm delay notification setting for homebase 1+2
* (bropat) Added new floodlight, solo and outdoor cameras (untested!)
* (bropat) Added alarm event for Station
* (bropat) Picture url attribute is now also updated via push notifications
* (bropat) Fixed issue where the "pollingIntervalMinutes" setting of "EufySecurity" was not respected
* (bropat) Fixed p2p livestream for floodlight camera
* (bropat) Fixed p2p enable/disable device for floodlight camera
* (bropat) Fixed p2p enable/disable autonightvision for floodlight camera
* (bropat) Fixed p2p download video
* (bropat) Fixed P2PClientProtocol "close" event that was emitted even if there was no connection and a reconnection was attempted
* (bropat) Fixed "guard mode" and "current mode" event not emittet in some conditions
* (bropat) Fixed possible race conditions processing unordered p2p packets
* (bropat) Optimized p2p lookup functionality
* (bropat) Other small bugfixes and code cleanup
* (bropat) Updated versions of the package dependencies
### 0.8.3 (2021-06-01)
* (bropat) Fixed regression in p2p protocol
### 0.8.2 (2021-05-26)
* (bropat) Fixed issue [#2](https://github.com/bropat/eufy-security-client/issues/2)
* (bropat) Added new high level property "type" for devices/stations
* (bropat) Updated versions of the package dependencies
### 0.8.1 (2021-05-14)
* (bropat) Fixed (raw) property value refresh for devices and stations
* (bropat) Fixed "enabled" property for standalone devices
* (bropat) Fixed "lanIpAddress" property for standalone devices
* (bropat) Fixed "macAddress" property for standalone devices
* (bropat) Added "station raw property changed" and "device raw property changed" event for high level class EufySecurity
### 0.8.0 (2021-05-12)
* (bropat) **Breaking Changes** (renamed emitter, renamed some functions etc.)
* (bropat) Added high level class EufySecurity
* (bropat) Added high level properties with metadata information
* (bropat) Better error handling
* (bropat) Fixed Guard Mode Emitter
* (bropat) Fixed push notification for indoor and floodlight cams
* (bropat) Cleanup code
* (bropat) Updated versions of the package dependencies
### 0.7.2 (2021-04-10)
* (bropat) Added new HTTP API methods: getVideoEvents, getAlarmEvents, getHistoryEvents, getAllVideoEvents, getAllAlarmEvents, getAllHistoryEvents
* (bropat) P2P session: Added station serial number to logging entries for debugging purposes
* (bropat) Updated versions of the package dependencies
### 0.7.1 (2021-04-02)
* (bropat) Lowered UDP receive buffer size for FreeBSD
* (bropat) Fixed lookup timeout issue on "local prefered" connection establishment
### 0.7.0 (2021-03-30)
* (bropat) Added support for smart locks
* (bropat) Added new P2P feature: lock/unlock smart lock products
* (bropat) Optimized speed of P2P connection establishment
* (bropat) Implemented P2P connection setup preference: local prefered, local only or quickest connection
* (bropat) Trying to solve issue [#2](https://github.com/bropat/eufy-security-client/issues/2)
* (bropat) Dropped support for NodeJS 10.x (min. requirement 12)
* (bropat) Updated versions of the package dependencies
### 0.6.0 (2021-03-11)
* (bropat) Added new command types to enum CommandType
* (bropat) Added new P2P feature: enable/disable pet detection for indoor cameras
* (bropat) Added new P2P feature: enable/disable sound detection for indoor cameras
* (bropat) Added new P2P feature: enable/disable led for wired doorbells
* (bropat) Added some functions to p2p station class: getLANIPAddress, getGuardMode, getCurrentMode
* (bropat) Added new device class: BatteryDoorbellCamera, IndoorCamera, SoloCamera
* (bropat) Added new functions to some device classes returning specific parameter values
* (bropat) Renamed interface ParameterValue to StringValue and added new: BooleanValue, NumberValue
* (bropat) All functions of the Device base class that return parameter values, return now the value and timestamp of the last modification
* (bropat) Fixed enable/disable led (for battery doorbells, indoor cameras, floodlight camera and solo cameras)
* (bropat) Fixed enable/disable motion detection (for wired doorbells, indoor cameras, floodlight camera and solo cameras)
* (bropat) Fixed change video watermark setting (for wired doorbells, battery doorbells, indoor cameras and floodlight camera)
* (bropat) Fixed issue with multibyte string with function buildCommandWithStringTypePayload
* (bropat) Fixed issue on PushMessage interface (fixed parsing of file_path)
### 0.5.1 (2021-03-05)
* (bropat) Fixed download of videos via p2p (wrong channel value in callback)
* (bropat) Updated versions of the dev package dependencies
### 0.5.0 (2021-03-03)
* (bropat) Added new P2P feature: enable/disable motion detection for camera products
* (bropat) Added new P2P feature: enable/disable rtsp stream for camera2 products, indoor and solo cameras
* (bropat) Added option to P2P session to enable quick start livestream (after receiving first video frame)
* (bropat) Added new methods to HTTPApi for setting custom HTTP session headers: PhoneModel, Country, Language
* (bropat) Changed return type of HTTPApi authenticate function
* (bropat) Fixed issue during livestreaming if p2p connection is lost
### 0.4.4 (2021-02-20)
* (bropat) Fixed possible race condition that sometimes interrupts the livestream
### 0.4.3 (2021-02-18)
* (bropat) Added new P2P feature: quick response for doorbell products
* (bropat) Fixed wired doorbell p2p livestream (should fix also indoor, floodlight and solo cameras)
* (bropat) Fixed issue on new PushMessage interface
* (bropat) Updated versions of the package dependencies
### 0.4.2 (2021-02-15)
* (bropat) Fixed battery doorbell start livestream P2P command
* (bropat) Added CMD_DOORBELL_SET_PAYLOAD as nested command type
### 0.4.1 (2021-02-14)
* (bropat) Fixed small typo
* (bropat) Uniform debug messages
### 0.4.0 (2021-02-13)
* (bropat) Added new P2P feature: Enable/disable device (for camera products)
* (bropat) Added new P2P feature: Enable/disable auto night vision (for camera products)
* (bropat) Added new P2P feature: Enable/disable led (for camera 2 products, indoor cameras, floodlight camera and solo cameras)
* (bropat) Added new P2P feature: Enable/disable anti-theft detection (for camera 2 products)
* (bropat) Added new P2P feature: Change video watermark setting (for camera products)
* (bropat) Fixed P2P command retry on error 503
* (bropat) Fixed issue on new PushMessage interface
* (bropat) Fixed issue with handling unencrypted video data
### 0.3.0 (2021-02-11)
* (bropat) Added new P2P feature: Download video
* (bropat) Implemented refreshing of device and station parameters via P2P
* (bropat) Migrated to TypedEmitter (tiny-typed-emitter)
* (bropat) Implemented new managed push notification class: PushNotificationService
* (bropat) Removed old push notification class: PushRegisterService
* (bropat) Renamed previous PushMessage interface to RawPushMessage
* (bropat) Introduced new PushMessage interface that normalizes all push notification types into one
* (bropat) Fixed issue where readable streams were not correctly destroyed when terminating p2p video streams
* (bropat) Fixed P2P start livestream command for Floodlight / Indoor / Solo cameras
* (bropat) Implemented refresh of GUARD_MODE on change of SCHEDULE_MODE over p2p (instantly)
### 0.2.2 (2021-02-06)
* (bropat) Exported missing P2P interface: StreamMetadata
### 0.2.1 (2021-02-06)
* (bropat) Added typescript declaration files
### 0.2.0 (2021-02-06)
* (bropat) initial release
## License
MIT License
Copyright (c) 2021-2024 bropat <patrick.broetto@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

127
build/error.d.ts vendored Normal file
View File

@ -0,0 +1,127 @@
export type Jsonable = string | number | boolean | object | null | undefined | readonly Jsonable[] | {
readonly [key: string]: Jsonable;
} | {
toJSON(): Jsonable;
};
export declare class BaseError extends Error {
readonly context?: Jsonable;
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare function ensureError(value: unknown): BaseError;
export declare class InvalidCountryCodeError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class InvalidLanguageCodeError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class StationNotFoundError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class DeviceNotFoundError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class NotSupportedError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class WrongStationError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class RTSPPropertyNotEnabledError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class InvalidPropertyValueError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class InvalidCommandValueError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class ReadOnlyPropertyError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class LivestreamError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class TalkbackError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class StationConnectTimeoutError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class AddUserError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class DeleteUserError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class UpdateUserUsernameError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class UpdateUserScheduleError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class UpdateUserPasscodeError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class PinNotVerifiedError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}

178
build/error.js Normal file
View File

@ -0,0 +1,178 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PinNotVerifiedError = exports.UpdateUserPasscodeError = exports.UpdateUserScheduleError = exports.UpdateUserUsernameError = exports.DeleteUserError = exports.AddUserError = exports.StationConnectTimeoutError = exports.TalkbackError = exports.LivestreamError = exports.ReadOnlyPropertyError = exports.InvalidCommandValueError = exports.InvalidPropertyValueError = exports.RTSPPropertyNotEnabledError = exports.WrongStationError = exports.NotSupportedError = exports.DeviceNotFoundError = exports.StationNotFoundError = exports.InvalidLanguageCodeError = exports.InvalidCountryCodeError = exports.BaseError = void 0;
exports.ensureError = ensureError;
class BaseError extends Error {
context;
constructor(message, options = {}) {
const { cause, context } = options;
super(message, { cause }); //NodeJs 16.9.0
this.name = this.constructor.name;
this.context = context;
}
}
exports.BaseError = BaseError;
function ensureError(value) {
if (value instanceof Error)
return value;
let stringified = "[Unable to stringify the thrown value]";
try {
stringified = JSON.stringify(value);
}
catch { }
const error = new Error(`This value was thrown as is, not through an Error: ${stringified}`);
return error;
}
class InvalidCountryCodeError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = InvalidCountryCodeError.name;
}
}
exports.InvalidCountryCodeError = InvalidCountryCodeError;
class InvalidLanguageCodeError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = InvalidLanguageCodeError.name;
}
}
exports.InvalidLanguageCodeError = InvalidLanguageCodeError;
class StationNotFoundError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = StationNotFoundError.name;
}
}
exports.StationNotFoundError = StationNotFoundError;
class DeviceNotFoundError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = DeviceNotFoundError.name;
}
}
exports.DeviceNotFoundError = DeviceNotFoundError;
class NotSupportedError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = NotSupportedError.name;
}
}
exports.NotSupportedError = NotSupportedError;
class WrongStationError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = WrongStationError.name;
}
}
exports.WrongStationError = WrongStationError;
class RTSPPropertyNotEnabledError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = RTSPPropertyNotEnabledError.name;
}
}
exports.RTSPPropertyNotEnabledError = RTSPPropertyNotEnabledError;
class InvalidPropertyValueError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = InvalidPropertyValueError.name;
}
}
exports.InvalidPropertyValueError = InvalidPropertyValueError;
class InvalidCommandValueError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = InvalidCommandValueError.name;
}
}
exports.InvalidCommandValueError = InvalidCommandValueError;
class ReadOnlyPropertyError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = ReadOnlyPropertyError.name;
}
}
exports.ReadOnlyPropertyError = ReadOnlyPropertyError;
class LivestreamError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = LivestreamError.name;
}
}
exports.LivestreamError = LivestreamError;
class TalkbackError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = TalkbackError.name;
}
}
exports.TalkbackError = TalkbackError;
class StationConnectTimeoutError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = StationConnectTimeoutError.name;
}
}
exports.StationConnectTimeoutError = StationConnectTimeoutError;
class AddUserError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = AddUserError.name;
}
}
exports.AddUserError = AddUserError;
class DeleteUserError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = DeleteUserError.name;
}
}
exports.DeleteUserError = DeleteUserError;
class UpdateUserUsernameError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = UpdateUserUsernameError.name;
}
}
exports.UpdateUserUsernameError = UpdateUserUsernameError;
class UpdateUserScheduleError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = UpdateUserScheduleError.name;
}
}
exports.UpdateUserScheduleError = UpdateUserScheduleError;
class UpdateUserPasscodeError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = UpdateUserPasscodeError.name;
}
}
exports.UpdateUserPasscodeError = UpdateUserPasscodeError;
class PinNotVerifiedError extends BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = PinNotVerifiedError.name;
}
}
exports.PinNotVerifiedError = PinNotVerifiedError;
//# sourceMappingURL=error.js.map

1
build/error.js.map Normal file

File diff suppressed because one or more lines are too long

179
build/eufysecurity.d.ts vendored Normal file
View File

@ -0,0 +1,179 @@
import { TypedEmitter } from "tiny-typed-emitter";
import { EufySecurityEvents, EufySecurityConfig } from "./interfaces";
import { HTTPApi } from "./http/api";
import { LoginOptions, Schedule } from "./http/interfaces";
import { Station } from "./http/station";
import { PushNotificationService } from "./push/service";
import { Credentials } from "./push/models";
import { Device } from "./http/device";
import { P2PConnectionType } from "./p2p/types";
import { Logger, LoggingCategories } from "./logging";
import { LogLevel } from "typescript-logging";
export declare class EufySecurity extends TypedEmitter<EufySecurityEvents> {
private config;
private api;
private houses;
private stations;
private devices;
private readonly P2P_REFRESH_INTERVAL_MIN;
private cameraMaxLivestreamSeconds;
private cameraStationLivestreamTimeout;
private pushService;
private mqttService;
private pushCloudRegistered;
private pushCloudChecked;
private persistentFile;
private persistentData;
private connected;
private retries;
private refreshEufySecurityCloudTimeout?;
private refreshEufySecurityP2PTimeout;
private deviceSnoozeTimeout;
private loadingEmitter;
private stationsLoaded?;
private devicesLoaded?;
private constructor();
static initialize(config: EufySecurityConfig, log?: Logger): Promise<EufySecurity>;
protected _initializeInternals(): Promise<void>;
private initMQTT;
setLoggingLevel(category: LoggingCategories, level: LogLevel): void;
getLoggingLevel(category: LoggingCategories): number;
setInternalLogger(logger: Logger): void;
getInternalLogger(): Logger | undefined;
getPushService(): PushNotificationService;
private addStation;
private removeStation;
private updateStation;
private addDevice;
private removeDevice;
private updateDevice;
getDevices(): Promise<Array<Device>>;
getDevicesFromStation(stationSN: string): Promise<Array<Device>>;
getDevice(deviceSN: string): Promise<Device>;
getStationDevice(stationSN: string, channel: number): Promise<Device>;
getStations(): Promise<Array<Station>>;
getStation(stationSN: string): Promise<Station>;
getApi(): HTTPApi;
connectToStation(stationSN: string, p2pConnectionType?: P2PConnectionType): Promise<void>;
isStationConnected(stationSN: string): Promise<boolean>;
isStationEnergySavingDevice(stationSN: string): Promise<boolean>;
private handleHouses;
private handleHubs;
private refreshP2PData;
private onStationConnect;
private onStationConnectionError;
private onStationClose;
private handleDevices;
refreshCloudData(): Promise<void>;
close(): void;
setCameraMaxLivestreamDuration(seconds: number): void;
getCameraMaxLivestreamDuration(): number;
registerPushNotifications(credentials?: Credentials, persistentIds?: string[]): Promise<void>;
connect(options?: LoginOptions): Promise<void>;
getPushPersistentIds(): string[];
private updateDeviceProperties;
private onAPIClose;
private onAPIConnect;
private onAPIConnectionError;
startStationLivestream(deviceSN: string): Promise<void>;
stopStationLivestream(deviceSN: string): Promise<void>;
private writePersistentData;
private saveCloudToken;
private savePushCredentials;
private savePushPersistentIds;
getVersion(): string;
isPushConnected(): boolean;
isMQTTConnected(): boolean;
isConnected(): boolean;
private processInvitations;
private onPushMessage;
startStationDownload(deviceSN: string, path: string, cipherID: number): Promise<void>;
cancelStationDownload(deviceSN: string): Promise<void>;
getConfig(): EufySecurityConfig;
setDeviceProperty(deviceSN: string, name: string, value: unknown): Promise<void>;
setStationProperty(stationSN: string, name: string, value: unknown): Promise<void>;
private onStartStationLivestream;
private onStopStationLivestream;
private onErrorStationLivestream;
private onStartStationRTSPLivestream;
private onStopStationRTSPLivestream;
private onStationStartDownload;
private onStationFinishDownload;
private onStationCommandResult;
private onStationSecondaryCommandResult;
private onStationRtspUrl;
private onStationGuardMode;
private onStationCurrentMode;
private onStationPropertyChanged;
private onStationRawPropertyChanged;
private onStationAlarmEvent;
private onStationAlarmDelayEvent;
private onStationArmDelayEvent;
private onStationAlarmArmedEvent;
private onDevicePropertyChanged;
private onDeviceRawPropertyChanged;
private onDeviceCryingDetected;
private onDeviceSoundDetected;
private onDevicePetDetected;
private onDeviceVehicleDetected;
private onDeviceMotionDetected;
private onDevicePersonDetected;
private onDeviceRings;
private onDeviceLocked;
private onDeviceOpen;
private onDevicePackageDelivered;
private onDevicePackageStranded;
private onDevicePackageTaken;
private onDeviceSomeoneLoitering;
private onDeviceRadarMotionDetected;
private onDevice911Alarm;
private onDeviceShakeAlarm;
private onDeviceWrongTryProtectAlarm;
private onDeviceLongTimeNotClose;
private onDeviceLowBattery;
private onDeviceJammed;
private onDeviceStrangerPersonDetected;
private onDeviceDogDetected;
private onDeviceDogLickDetected;
private onDeviceDogPoopDetected;
private onDeviceReady;
private onStationRuntimeState;
private onStationChargingState;
private onStationWifiRssi;
private onCaptchaRequest;
private onFloodlightManualSwitch;
private onAuthTokenInvalidated;
private onTfaRequest;
private onStationTalkbackStart;
private onStationTalkbackStop;
private onStationTalkbackError;
startStationTalkback(deviceSN: string): Promise<void>;
stopStationTalkback(deviceSN: string): Promise<void>;
private onStationDeviceShakeAlarm;
private onStationDevice911Alarm;
private onStationDeviceJammed;
private onStationDeviceLowBattery;
private onStationDeviceWrongTryProtectAlarm;
addUser(deviceSN: string, username: string, passcode: string, schedule?: Schedule): Promise<void>;
deleteUser(deviceSN: string, username: string): Promise<void>;
updateUser(deviceSN: string, username: string, newUsername: string): Promise<void>;
updateUserPasscode(deviceSN: string, username: string, passcode: string): Promise<void>;
updateUserSchedule(deviceSN: string, username: string, schedule: Schedule): Promise<void>;
private onStationDevicePinVerified;
private onStationSdInfoEx;
private _emitStationImageDownload;
private onStationImageDownload;
private onStationDatabaseQueryLatest;
private onStationDatabaseQueryLocal;
private onStationDatabaseCountByDate;
private onStationDatabaseDelete;
private onStationSensorStatus;
private onStationGarageDoorStatus;
private onStorageInfoHb3;
private onDeviceTampering;
private onDeviceLowTemperature;
private onDeviceHighTemperature;
private onDevicePinIncorrect;
private onDeviceLidStuck;
private onDeviceBatteryFullyCharged;
}

2634
build/eufysecurity.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

90
build/http/api.d.ts vendored Normal file
View File

@ -0,0 +1,90 @@
import { TypedEmitter } from "tiny-typed-emitter";
import { TrustDevice, Cipher, EventRecordResponse, ConfirmInvite, SensorHistoryEntry, ApiResponse, HouseDetail, DeviceListResponse, StationListResponse, HouseInviteListResponse, HouseListResponse, PassportProfileResponse, User, AddUserResponse } from "./models";
import { HTTPApiEvents, Ciphers, FullDevices, Hubs, Voices, Invites, HTTPApiRequest, HTTPApiPersistentData, LoginOptions, Schedule } from "./interfaces";
import { EventFilterType, PublicKeyType, VerfyCodeTypes } from "./types";
export declare class HTTPApi extends TypedEmitter<HTTPApiEvents> {
private static apiDomainBase;
private readonly SERVER_PUBLIC_KEY;
private apiBase;
private username;
private password;
private ecdh;
private token;
private tokenExpiration;
private renewAuthTokenJob?;
private connected;
private requestEufyCloud;
private throttle;
private devices;
private hubs;
private houses;
private persistentData;
private headers;
private constructor();
static getApiBaseFromCloud(country: string): Promise<string>;
private loadLibraries;
static initialize(country: string, username: string, password: string, persistentData?: HTTPApiPersistentData): Promise<HTTPApi>;
private clearScheduleRenewAuthToken;
private scheduleRenewAuthToken;
private invalidateToken;
setPhoneModel(model: string): void;
getPhoneModel(): string;
getCountry(): string;
setLanguage(language: string): void;
getLanguage(): string;
login(options?: LoginOptions): Promise<void>;
sendVerifyCode(type?: VerfyCodeTypes): Promise<boolean>;
listTrustDevice(): Promise<Array<TrustDevice>>;
addTrustDevice(verifyCode: string): Promise<boolean>;
getStationList(): Promise<Array<StationListResponse>>;
getDeviceList(): Promise<Array<DeviceListResponse>>;
refreshHouseData(): Promise<void>;
refreshStationData(): Promise<void>;
refreshDeviceData(): Promise<void>;
refreshAllData(): Promise<void>;
request(request: HTTPApiRequest, withoutUrlPrefix?: boolean): Promise<ApiResponse>;
checkPushToken(): Promise<boolean>;
registerPushToken(token: string): Promise<boolean>;
setParameters(stationSN: string, deviceSN: string, params: {
paramType: number;
paramValue: any;
}[]): Promise<boolean>;
getCiphers(/*stationSN: string, */ cipherIDs: Array<number>, userID: string): Promise<Ciphers>;
getVoices(deviceSN: string): Promise<Voices>;
getCipher(/*stationSN: string, */ cipherID: number, userID: string): Promise<Cipher>;
getDevices(): FullDevices;
getHubs(): Hubs;
getToken(): string | null;
getTokenExpiration(): Date | null;
setToken(token: string): void;
setTokenExpiration(tokenExpiration: Date): void;
getAPIBase(): string;
setOpenUDID(openudid: string): void;
setSerialNumber(serialnumber: string): void;
private _getEvents;
getVideoEvents(startTime: Date, endTime: Date, filter?: EventFilterType, maxResults?: number): Promise<Array<EventRecordResponse>>;
getAlarmEvents(startTime: Date, endTime: Date, filter?: EventFilterType, maxResults?: number): Promise<Array<EventRecordResponse>>;
getHistoryEvents(startTime: Date, endTime: Date, filter?: EventFilterType, maxResults?: number): Promise<Array<EventRecordResponse>>;
getAllVideoEvents(filter?: EventFilterType, maxResults?: number): Promise<Array<EventRecordResponse>>;
getAllAlarmEvents(filter?: EventFilterType, maxResults?: number): Promise<Array<EventRecordResponse>>;
getAllHistoryEvents(filter?: EventFilterType, maxResults?: number): Promise<Array<EventRecordResponse>>;
isConnected(): boolean;
getInvites(): Promise<Invites>;
confirmInvites(confirmInvites: Array<ConfirmInvite>): Promise<boolean>;
getPublicKey(deviceSN: string, type: PublicKeyType): Promise<string>;
decryptAPIData(data?: string, json?: boolean): any;
getSensorHistory(stationSN: string, deviceSN: string): Promise<Array<SensorHistoryEntry>>;
getHouseDetail(houseID: string): Promise<HouseDetail | null>;
getHouseList(): Promise<Array<HouseListResponse>>;
getHouseInviteList(isInviter?: number): Promise<Array<HouseInviteListResponse>>;
confirmHouseInvite(houseID: string, inviteID: number): Promise<boolean>;
getPersistentData(): HTTPApiPersistentData | undefined;
getPassportProfile(): Promise<PassportProfileResponse | null>;
addUser(deviceSN: string, nickname: string, stationSN?: string): Promise<AddUserResponse | null>;
deleteUser(deviceSN: string, shortUserId: string, stationSN?: string): Promise<boolean>;
getUsers(deviceSN: string, stationSN: string): Promise<Array<User> | null>;
getUser(deviceSN: string, stationSN: string, shortUserId: string): Promise<User | null>;
updateUser(deviceSN: string, stationSN: string, shortUserId: string, nickname: string): Promise<boolean>;
getImage(deviceSN: string, url: string): Promise<Buffer>;
updateUserPassword(deviceSN: string, shortUserId: string, passwordId: string, schedule: Schedule, stationSN?: string): Promise<boolean>;
}

1578
build/http/api.js Normal file

File diff suppressed because it is too large Load Diff

1
build/http/api.js.map Normal file

File diff suppressed because one or more lines are too long

8
build/http/cache.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
export declare class Cache extends Map {
private ttl;
private schedules;
constructor(ttl?: number);
delete(key: any): boolean;
set(key: any, value: any, ttl?: number): this;
get(key: any): any;
}

34
build/http/cache.js Normal file
View File

@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Cache = void 0;
class Cache extends Map {
ttl = 60000;
schedules = new Map();
constructor(ttl) {
super();
if (ttl !== undefined)
this.ttl = ttl;
}
delete(key) {
const result = super.delete(key);
clearTimeout(this.schedules.get(key));
this.schedules.delete(key);
return result;
}
set(key, value, ttl = this.ttl) {
super.set(key, value);
if (this.schedules.has(key)) {
clearTimeout(this.schedules.get(key));
}
const schedule = setTimeout(() => {
this.delete(key);
}, ttl);
this.schedules.set(key, schedule);
return this;
}
get(key) {
return super.get(key);
}
}
exports.Cache = Cache;
//# sourceMappingURL=cache.js.map

1
build/http/cache.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/http/cache.ts"],"names":[],"mappings":";;;AAAA,MAAa,KAAM,SAAQ,GAAG;IAElB,GAAG,GAAG,KAAK,CAAC;IACZ,SAAS,GAAI,IAAI,GAAG,EAAE,CAAC;IAE/B,YAAY,GAAY;QACpB,KAAK,EAAE,CAAC;QACR,IAAI,GAAG,KAAK,SAAS;YACjB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACvB,CAAC;IAEM,MAAM,CAAC,GAAQ;QAClB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3B,OAAO,MAAM,CAAC;IAClB,CAAC;IAEM,GAAG,CAAC,GAAQ,EAAE,KAAU,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG;QAC3C,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACtB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1C,CAAC;QAED,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,EAAE;YAC7B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC,EAAE,GAAG,CAAC,CAAC;QACR,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IAChB,CAAC;IAEM,GAAG,CAAC,GAAQ;QACf,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;CACJ;AAlCD,sBAkCC"}

3
build/http/const.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
import { EufyTimezone } from "./utils";
export declare const PhoneModels: Array<string>;
export declare const timeZoneData: Array<EufyTimezone>;

8546
build/http/const.js Normal file

File diff suppressed because it is too large Load Diff

1
build/http/const.js.map Normal file

File diff suppressed because one or more lines are too long

474
build/http/device.d.ts vendored Normal file
View File

@ -0,0 +1,474 @@
import { TypedEmitter } from "tiny-typed-emitter";
import { HTTPApi } from "./api";
import { CommandName, DeviceEvent, SourceType, TrackerType } from "./types";
import { DeviceListResponse } from "./models";
import { DeviceEvents, PropertyValue, PropertyValues, PropertyMetadataAny, IndexedProperty, RawValues, Schedule, Voices, DeviceConfig } from "./interfaces";
import { PushMessage } from "../push/models";
import { DeviceSmartLockNotifyData } from "../mqtt/model";
import { Station } from "./station";
export declare class Device extends TypedEmitter<DeviceEvents> {
protected api: HTTPApi;
protected rawDevice: DeviceListResponse;
protected eventTimeouts: Map<DeviceEvent, NodeJS.Timeout>;
protected pictureEventTimeouts: Map<string, NodeJS.Timeout>;
protected properties: PropertyValues;
protected config: DeviceConfig;
private rawProperties;
private ready;
protected constructor(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig);
protected initializeState(): void;
initialize(): void;
getRawDevice(): DeviceListResponse;
update(device: DeviceListResponse): void;
updateProperty(name: string, value: PropertyValue, force?: boolean): boolean;
updateRawProperties(values: RawValues): void;
protected handlePropertyChange(metadata: PropertyMetadataAny, oldValue: PropertyValue, newValue: PropertyValue): void;
updateRawProperty(type: number, value: string, source: SourceType): boolean;
protected convertRawPropertyValue(property: PropertyMetadataAny, value: string): PropertyValue;
getPropertyMetadata(name: string, hidden?: boolean): PropertyMetadataAny;
getPropertyValue(name: string): PropertyValue;
hasPropertyValue(name: string): boolean;
getRawProperty(type: number): string | undefined;
getRawProperties(): RawValues;
getProperties(): PropertyValues;
getPropertiesMetadata(hidden?: boolean): IndexedProperty;
hasProperty(name: string, hidden?: boolean): boolean;
getCommands(): Array<CommandName>;
hasCommand(name: CommandName): boolean;
processPushNotification(_station: Station, _message: PushMessage, _eventDurationSeconds: number): void;
setCustomPropertyValue(name: string, value: PropertyValue): void;
destroy(): void;
protected clearEventTimeout(eventType: DeviceEvent): void;
static isSupported(type: number): boolean;
static isCamera(type: number): boolean;
static hasBattery(type: number): boolean;
static isStation(type: number): boolean;
static isCamera1(type: number): boolean;
static isCameraE(type: number): boolean;
static isSensor(type: number): boolean;
static isKeyPad(type: number): boolean;
static isDoorbell(type: number): boolean;
static isWiredDoorbell(type: number): boolean;
static isWiredDoorbellT8200X(type: number, serialnumber: string): boolean;
static isWiredDoorbellDual(type: number): boolean;
static isIndoorCamera(type: number): boolean;
static isPanAndTiltCamera(type: number): boolean;
static isOutdoorPanAndTiltCamera(type: number): boolean;
static isIndoorPanAndTiltCameraS350(type: number): boolean;
static isFloodLight(type: number): boolean;
static isFloodLightT8420X(type: number, serialnumber: string): boolean;
static isFloodLightT8423(type: number): boolean;
static isFloodLightT8425(type: number): boolean;
static isWallLightCam(type: number): boolean;
static isLock(type: number): boolean;
static isLockKeypad(type: number): boolean;
static isLockBle(type: number): boolean;
static isLockBleNoFinger(type: number): boolean;
static isLockWifi(type: number, serialnumber: string): boolean;
static isLockWifiNoFinger(type: number): boolean;
static isLockWifiR10(type: number): boolean;
static isLockWifiR20(type: number): boolean;
static isLockWifiVideo(type: number): boolean;
static isLockWifiR10Keypad(type: number): boolean;
static isLockWifiR20Keypad(type: number): boolean;
static isLockWifiT8506(type: number): boolean;
static isLockWifiT8502(type: number): boolean;
static isLockWifiT8510P(type: number, serialnumber: string): boolean;
static isLockWifiT8520P(type: number, serialnumber: string): boolean;
static isBatteryDoorbell1(type: number): boolean;
static isBatteryDoorbell2(type: number): boolean;
static isBatteryDoorbellDual(type: number): boolean;
static isBatteryDoorbellDualE340(type: number): boolean;
static isBatteryDoorbellC30(type: number): boolean;
static isBatteryDoorbellC31(type: number): boolean;
static isDoorbellDual(type: number): boolean;
static isBatteryDoorbell(type: number): boolean;
static isSoloCamera(type: number): boolean;
static isSoloCameraPro(type: number): boolean;
static isSoloCameraSpotlight1080(type: number): boolean;
static isSoloCameraSpotlight2k(type: number): boolean;
static isSoloCameraSpotlightSolar(type: number): boolean;
static isSoloCameraSolar(type: number): boolean;
static isSoloCameraC210(type: number): boolean;
static isSoloCameraE30(type: number): boolean;
static isSoloCameras(type: number): boolean;
static isStarlight4GLTE(type: number): boolean;
static isIndoorOutdoorCamera1080p(type: number): boolean;
static isIndoorOutdoorCamera1080pNoLight(type: number): boolean;
static isIndoorOutdoorCamera2k(type: number): boolean;
static isIndoorCamMini(type: number): boolean;
static isCamera1Product(type: number): boolean;
static isCamera2(type: number): boolean;
static isCamera2C(type: number): boolean;
static isCamera2Pro(type: number): boolean;
static isCamera2CPro(type: number): boolean;
static isCamera2Product(type: number): boolean;
static isCamera3(type: number): boolean;
static isCamera3C(type: number): boolean;
static isCamera3Pro(type: number): boolean;
static isCameraProfessional247(type: number): boolean;
static isCamera3Product(type: number): boolean;
static isEntrySensor(type: number): boolean;
static isMotionSensor(type: number): boolean;
static isSmartDrop(type: number): boolean;
static isSmartSafe(type: number): boolean;
static isGarageCamera(type: number): boolean;
static isIntegratedDeviceBySn(sn: string): boolean;
static isSoloCameraBySn(sn: string): boolean;
static isSmartDropBySn(sn: string): boolean;
static isLockBySn(sn: string): boolean;
static isGarageCameraBySn(sn: string): boolean;
static isFloodlightBySn(sn: string): boolean;
static isIndoorCameraBySn(sn: string): boolean;
static is4GCameraBySn(sn: string): boolean;
static isSmartSafeBySn(sn: string): boolean;
static isSmartTrackCard(type: number): boolean;
static isSmartTrackLink(type: number): boolean;
static isSmartTrack(type: number): boolean;
isCamera(): boolean;
isFloodLight(): boolean;
isFloodLightT8420X(): boolean;
isFloodLightT8423(): boolean;
isFloodLightT8425(): boolean;
isWallLightCam(): boolean;
isDoorbell(): boolean;
isWiredDoorbell(): boolean;
isWiredDoorbellT8200X(): boolean;
isWiredDoorbellDual(): boolean;
isLock(): boolean;
isLockKeypad(): boolean;
isLockBle(): boolean;
isLockBleNoFinger(): boolean;
isLockWifi(): boolean;
isLockWifiNoFinger(): boolean;
isLockWifiR10(): boolean;
isLockWifiR20(): boolean;
isLockWifiVideo(): boolean;
isLockWifiR10Keypad(): boolean;
isLockWifiR20Keypad(): boolean;
isLockWifiT8506(): boolean;
isLockWifiT8502(): boolean;
isLockWifiT8510P(): boolean;
isLockWifiT8520P(): boolean;
isBatteryDoorbell1(): boolean;
isBatteryDoorbell2(): boolean;
isBatteryDoorbellDual(): boolean;
isBatteryDoorbellDualE340(): boolean;
isBatteryDoorbellC30(): boolean;
isBatteryDoorbellC31(): boolean;
isDoorbellDual(): boolean;
isBatteryDoorbell(): boolean;
isSoloCamera(): boolean;
isSoloCameraPro(): boolean;
isSoloCameraSpotlight1080(): boolean;
isSoloCameraSpotlight2k(): boolean;
isSoloCameraSpotlightSolar(): boolean;
isSoloCameraSolar(): boolean;
isSoloCameraC210(): boolean;
isSoloCameraE30(): boolean;
isStarlight4GLTE(): boolean;
isIndoorOutdoorCamera1080p(): boolean;
isIndoorOutdoorCamera1080pNoLight(): boolean;
isIndoorOutdoorCamera2k(): boolean;
isIndoorCamMini(): boolean;
isSoloCameras(): boolean;
isCamera2(): boolean;
isCamera2C(): boolean;
isCamera2Pro(): boolean;
isCamera2CPro(): boolean;
isCamera2Product(): boolean;
isCamera3(): boolean;
isCamera3C(): boolean;
isCameraProfessional247(): boolean;
isCamera3Pro(): boolean;
isCamera3Product(): boolean;
isEntrySensor(): boolean;
isKeyPad(): boolean;
isMotionSensor(): boolean;
isIndoorCamera(): boolean;
isPanAndTiltCamera(): boolean;
isOutdoorPanAndTiltCamera(): boolean;
isIndoorPanAndTiltCameraS350(): boolean;
isSmartDrop(): boolean;
isSmartSafe(): boolean;
isGarageCamera(): boolean;
isIntegratedDevice(): boolean;
isSmartTrack(): boolean;
isSmartTrackCard(): boolean;
isSmartTrackLink(): boolean;
hasBattery(): boolean;
getDeviceKey(): string;
getDeviceType(): number;
getHardwareVersion(): string;
getSoftwareVersion(): string;
getModel(): string;
getName(): string;
getSerial(): string;
getStationSerial(): string;
setParameters(params: {
paramType: number;
paramValue: any;
}[]): Promise<boolean>;
getChannel(): number;
getStateID(state: string, level?: number): string;
getStateChannel(): string;
getWifiRssi(): PropertyValue;
getStoragePath(filename: string): string;
isEnabled(): PropertyValue;
}
export declare class Camera extends Device {
protected constructor(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig);
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<Camera>;
getStateChannel(): string;
protected convertRawPropertyValue(property: PropertyMetadataAny, value: string): PropertyValue;
getLastCameraImageURL(): PropertyValue;
getMACAddress(): string;
startDetection(): Promise<void>;
stopDetection(): Promise<void>;
getState(): PropertyValue;
close(): Promise<void>;
getLastChargingDays(): number;
getLastChargingFalseEvents(): number;
getLastChargingRecordedEvents(): number;
getLastChargingTotalEvents(): number;
getBatteryValue(): PropertyValue;
getBatteryTemperature(): PropertyValue;
isMotionDetectionEnabled(): PropertyValue;
isLedEnabled(): PropertyValue;
isAutoNightVisionEnabled(): PropertyValue;
isRTSPStreamEnabled(): PropertyValue;
isAntiTheftDetectionEnabled(): PropertyValue;
getWatermark(): PropertyValue;
isMotionDetected(): boolean;
isPersonDetected(): boolean;
getDetectedPerson(): string;
protected handlePropertyChange(metadata: PropertyMetadataAny, oldValue: PropertyValue, newValue: PropertyValue): void;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
}
export declare class SoloCamera extends Camera {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<SoloCamera>;
isLedEnabled(): PropertyValue;
isMotionDetectionEnabled(): PropertyValue;
protected convertRawPropertyValue(property: PropertyMetadataAny, value: string): PropertyValue;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
}
export declare class IndoorCamera extends Camera {
protected constructor(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig);
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<IndoorCamera>;
isLedEnabled(): PropertyValue;
isMotionDetectionEnabled(): PropertyValue;
isPetDetectionEnabled(): PropertyValue;
isSoundDetectionEnabled(): PropertyValue;
isPetDetected(): boolean;
isSoundDetected(): boolean;
isCryingDetected(): boolean;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
destroy(): void;
}
export declare class DoorbellCamera extends Camera {
protected voices: Voices;
protected constructor(api: HTTPApi, device: DeviceListResponse, voices: Voices, deviceConfig: DeviceConfig);
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<DoorbellCamera>;
private loadMetadataVoiceStates;
getVoiceName(id: number): string;
getVoices(): Voices;
getPropertiesMetadata(hidden?: boolean): IndexedProperty;
isRinging(): boolean;
protected handlePropertyChange(metadata: PropertyMetadataAny, oldValue: PropertyValue, newValue: PropertyValue): void;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
}
export declare class WiredDoorbellCamera extends DoorbellCamera {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<WiredDoorbellCamera>;
isLedEnabled(): PropertyValue;
isAutoNightVisionEnabled(): PropertyValue;
isMotionDetectionEnabled(): PropertyValue;
}
export declare class BatteryDoorbellCamera extends DoorbellCamera {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<BatteryDoorbellCamera>;
isLedEnabled(): PropertyValue;
}
export declare class FloodlightCamera extends Camera {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<FloodlightCamera>;
isLedEnabled(): PropertyValue;
isMotionDetectionEnabled(): PropertyValue;
protected convertRawPropertyValue(property: PropertyMetadataAny, value: string): PropertyValue;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
}
export declare class WallLightCam extends Camera {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<WallLightCam>;
isLedEnabled(): PropertyValue;
isMotionDetectionEnabled(): PropertyValue;
protected convertRawPropertyValue(property: PropertyMetadataAny, value: string): PropertyValue;
getPropertiesMetadata(hidden?: boolean): IndexedProperty;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
}
export declare class GarageCamera extends Camera {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<GarageCamera>;
isLedEnabled(): PropertyValue;
isMotionDetectionEnabled(): PropertyValue;
protected convertRawPropertyValue(property: PropertyMetadataAny, value: string): PropertyValue;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
}
export declare class Sensor extends Device {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<Sensor>;
getStateChannel(): string;
getState(): PropertyValue;
}
export declare class EntrySensor extends Sensor {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<EntrySensor>;
isSensorOpen(): PropertyValue;
getSensorChangeTime(): PropertyValue;
isBatteryLow(): PropertyValue;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
protected handlePropertyChange(metadata: PropertyMetadataAny, oldValue: PropertyValue, newValue: PropertyValue): void;
}
export declare class MotionSensor extends Sensor {
static readonly MOTION_COOLDOWN_MS = 120000;
protected constructor(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig);
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<MotionSensor>;
isMotionDetected(): boolean;
getMotionSensorPIREvent(): PropertyValue;
isBatteryLow(): PropertyValue;
protected handlePropertyChange(metadata: PropertyMetadataAny, oldValue: PropertyValue, newValue: PropertyValue): void;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
}
export declare class Lock extends Device {
static readonly VERSION_CODE_SMART_LOCK = 3;
static readonly VERSION_CODE_LOCKV12 = 18;
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<Lock>;
getStateChannel(): string;
protected handlePropertyChange(metadata: PropertyMetadataAny, oldValue: PropertyValue, newValue: PropertyValue): void;
getState(): PropertyValue;
getBatteryValue(): PropertyValue;
getWifiRssi(): PropertyValue;
isLocked(): PropertyValue;
getLockStatus(): PropertyValue;
static encodeESLCmdOnOff(short_user_id: number, nickname: string, lock: boolean): Buffer;
static encodeESLCmdQueryStatus(admin_user_id: string): Buffer;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
processMQTTNotification(message: DeviceSmartLockNotifyData, eventDurationSeconds: number): void;
private processNotification;
private static getCurrentTimeInSeconds;
private static getUInt8Buffer;
private static getUint16LEBuffer;
private static getUint16BEBuffer;
static encodeCmdStatus(user_id: string): Buffer;
static encodeCmdUnlock(short_user_id: string, value: number, username: string): Buffer;
static encodeCmdCalibrate(user_id: string): Buffer;
static encodeCmdAddUser(short_user_id: string, passcode: string, username: string, schedule?: Schedule, user_permission?: number): Buffer;
static encodeCmdAddTemporaryUser(schedule?: Schedule, unlimited?: boolean): Buffer;
static encodeCmdDeleteTemporaryUser(password_id: string): Buffer;
static encodeCmdDeleteUser(short_user_id: string): Buffer;
static encodeCmdVerifyPw(password: string): Buffer;
static encodeCmdQueryLockRecord(index: number): Buffer;
static encodeCmdQueryUser(short_user_id: string): Buffer;
static encodeCmdQueryPassword(password_id: string): Buffer;
static encodeCmdModifyPassword(password_id: string, passcode: string): Buffer;
static encodeCmdUpdateSchedule(short_user_id: string, schedule: Schedule): Buffer;
static encodeCmdModifyUsername(username: string, password_id: string): Buffer;
static encodeCmdGetLockParam(user_id: string): Buffer;
static encodeCmdSetLockParamAutoLock(enabled: boolean, lockTimeSeconds: number): Buffer;
private static hexTime;
static encodeCmdSetLockParamAutoLockSchedule(enabled: boolean, schedule_start: string, schedule_end: string): Buffer;
static encodeCmdSetLockParamOneTouchLock(enabled: boolean): Buffer;
static encodeCmdSetLockParamWrongTryProtect(enabled: boolean, lockdownTime: number, attempts: number): Buffer;
static encodeCmdSetLockParamScramblePasscode(enabled: boolean): Buffer;
static encodeCmdSetLockParamSound(value: number): Buffer;
protected convertRawPropertyValue(property: PropertyMetadataAny, value: string): PropertyValue;
static encodeCmdSmartLockUnlock(adminUserId: string, lock: boolean, username: string, shortUserId: string): Buffer;
static encodeCmdSmartLockCalibrate(adminUserId: string): Buffer;
static encodeCmdSetSmartLockParamWrongTryProtect(adminUserId: string, enabled: boolean, attempts: number, lockdownTime: number): Buffer;
private static hexTimeSmartLock;
static encodeCmdSetSmartLockParamAutoLock(adminUserId: string, enabled: boolean, lockTimeSeconds: number, schedule: boolean, scheduleStart: string, scheduleEnd: string): Buffer;
static encodeCmdSetSmartLockParamOneTouchLock(adminUserId: string, enabled: boolean): Buffer;
static encodeCmdSetSmartLockParamScramblePasscode(adminUserId: string, enabled: boolean): Buffer;
static encodeCmdSetSmartLockParamSound(adminUserId: string, value: number): Buffer;
static encodeCmdSmartLockAddUser(adminUserId: string, shortUserId: string, passcode: string, username: string, schedule?: Schedule, userPermission?: number): Buffer;
static encodeCmdSmartLockDeleteUser(adminUserId: string, shortUserId: string): Buffer;
static encodeCmdSmartLockUpdateSchedule(adminUserId: string, shortUserId: string, username: string, schedule: Schedule, userPermission?: number): Buffer;
static encodeCmdSmartLockModifyPassword(adminUserId: string, passwordId: string, passcode: string): Buffer;
static encodeCmdSmartLockGetUserList(adminUserId: string): Buffer;
static encodeCmdSmartLockStatus(adminUserId: string): Buffer;
static encodeCmdSmartLockGetParams(adminUserId: string): Buffer;
}
export declare class LockKeypad extends Device {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<LockKeypad>;
getStateChannel(): string;
}
export declare class Keypad extends Device {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<Keypad>;
getStateChannel(): string;
getState(): PropertyValue;
isBatteryLow(): PropertyValue;
isBatteryCharging(): PropertyValue;
protected convertRawPropertyValue(property: PropertyMetadataAny, value: string): PropertyValue;
}
export declare class SmartSafe extends Device {
static readonly IV = "052E19EB3F880512E99EBB684D4DC1FE";
static readonly DATA_HEADER: number[];
static readonly VERSION_CODE = 1;
static readonly PUSH_NOTIFICATION_POSITION: {
[index: string]: number;
};
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<SmartSafe>;
getStateChannel(): string;
private static getCurrentTimeInSeconds;
private static getUInt8Buffer;
private static getUint16LEBuffer;
private static encodeCmdSingleUInt8;
static encodeCmdWrongTryProtect(user_id: string, enabled: boolean, attempts: number, lockdownTime: number): Buffer;
static encodeCmdLeftOpenAlarm(user_id: string, enabled: boolean, duration: number): Buffer;
static encodeCmdDualUnlock(user_id: string, enabled: boolean): Buffer;
static encodeCmdScramblePIN(user_id: string, enabled: boolean): Buffer;
static encodeCmdPowerSave(user_id: string, enabled: boolean): Buffer;
static encodeCmdInteriorBrightness(user_id: string, interiorBrightness: number, duration: number): Buffer;
static encodeCmdTamperAlarm(user_id: string, option: number): Buffer;
static encodeCmdRemoteUnlock(user_id: string, option: number): Buffer;
static encodeCmdAlertVolume(user_id: string, volume: number): Buffer;
static encodeCmdPromptVolume(user_id: string, volume: number): Buffer;
static encodeCmdPushNotification(user_id: string, modes: number): Buffer;
static encodeCmdUnlock(user_id: string): Buffer;
static encodeCmdVerifyPIN(user_id: string, pin: string): Buffer;
protected convertRawPropertyValue(property: PropertyMetadataAny, value: string): PropertyValue;
shakeEvent(event: number, eventDurationSeconds: number): void;
alarm911Event(event: number, eventDurationSeconds: number): void;
jammedEvent(eventDurationSeconds: number): void;
lowBatteryEvent(eventDurationSeconds: number): void;
wrongTryProtectAlarmEvent(eventDurationSeconds: number): void;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
protected handlePropertyChange(metadata: PropertyMetadataAny, oldValue: PropertyValue, newValue: PropertyValue): void;
getState(): PropertyValue;
getBatteryValue(): PropertyValue;
getWifiRssi(): PropertyValue;
isLocked(): boolean;
}
export declare class Tracker extends Device {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<Tracker>;
getStateChannel(): string;
protected convertRawPropertyValue(property: PropertyMetadataAny, value: string): PropertyValue;
setFindPhone(value: boolean): Promise<boolean>;
setLeftBehindAlarm(value: boolean): Promise<boolean>;
setTrackerType(value: TrackerType): Promise<boolean>;
}
export declare class DoorbellLock extends DoorbellCamera {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<DoorbellLock>;
getStateChannel(): string;
protected handlePropertyChange(metadata: PropertyMetadataAny, oldValue: PropertyValue, newValue: PropertyValue): void;
protected convertRawPropertyValue(property: PropertyMetadataAny, value: string): PropertyValue;
getState(): PropertyValue;
getBatteryValue(): PropertyValue;
getWifiRssi(): PropertyValue;
isLocked(): PropertyValue;
getLockStatus(): PropertyValue;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
}
export declare class SmartDrop extends Camera {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<SmartDrop>;
getStateChannel(): string;
processPushNotification(station: Station, message: PushMessage, eventDurationSeconds: number): void;
protected handlePropertyChange(metadata: PropertyMetadataAny, oldValue: PropertyValue, newValue: PropertyValue): void;
}
export declare class UnknownDevice extends Device {
static getInstance(api: HTTPApi, device: DeviceListResponse, deviceConfig: DeviceConfig): Promise<UnknownDevice>;
getStateChannel(): string;
}

4306
build/http/device.js Normal file

File diff suppressed because it is too large Load Diff

1
build/http/device.js.map Normal file

File diff suppressed because one or more lines are too long

73
build/http/error.d.ts vendored Normal file
View File

@ -0,0 +1,73 @@
import { BaseError, Jsonable } from "../error";
export declare class InvalidPropertyError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class LivestreamAlreadyRunningError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class LivestreamNotRunningError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class PropertyNotSupportedError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class ApiResponseCodeError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class ApiInvalidResponseError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class ApiHTTPResponseCodeError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class ApiGenericError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class ApiBaseLoadError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class ApiRequestError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class ImageBaseCodeError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class ImageSeedError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}

101
build/http/error.js Normal file
View File

@ -0,0 +1,101 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ImageSeedError = exports.ImageBaseCodeError = exports.ApiRequestError = exports.ApiBaseLoadError = exports.ApiGenericError = exports.ApiHTTPResponseCodeError = exports.ApiInvalidResponseError = exports.ApiResponseCodeError = exports.PropertyNotSupportedError = exports.LivestreamNotRunningError = exports.LivestreamAlreadyRunningError = exports.InvalidPropertyError = void 0;
const error_1 = require("../error");
class InvalidPropertyError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = InvalidPropertyError.name;
}
}
exports.InvalidPropertyError = InvalidPropertyError;
class LivestreamAlreadyRunningError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = LivestreamAlreadyRunningError.name;
}
}
exports.LivestreamAlreadyRunningError = LivestreamAlreadyRunningError;
class LivestreamNotRunningError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = LivestreamNotRunningError.name;
}
}
exports.LivestreamNotRunningError = LivestreamNotRunningError;
class PropertyNotSupportedError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = PropertyNotSupportedError.name;
}
}
exports.PropertyNotSupportedError = PropertyNotSupportedError;
class ApiResponseCodeError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = ApiResponseCodeError.name;
}
}
exports.ApiResponseCodeError = ApiResponseCodeError;
class ApiInvalidResponseError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = ApiInvalidResponseError.name;
}
}
exports.ApiInvalidResponseError = ApiInvalidResponseError;
class ApiHTTPResponseCodeError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = ApiHTTPResponseCodeError.name;
}
}
exports.ApiHTTPResponseCodeError = ApiHTTPResponseCodeError;
class ApiGenericError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = ApiGenericError.name;
}
}
exports.ApiGenericError = ApiGenericError;
class ApiBaseLoadError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = ApiBaseLoadError.name;
}
}
exports.ApiBaseLoadError = ApiBaseLoadError;
class ApiRequestError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = ApiRequestError.name;
}
}
exports.ApiRequestError = ApiRequestError;
class ImageBaseCodeError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = ImageBaseCodeError.name;
}
}
exports.ImageBaseCodeError = ImageBaseCodeError;
class ImageSeedError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = ImageSeedError.name;
}
}
exports.ImageSeedError = ImageSeedError;
//# sourceMappingURL=error.js.map

1
build/http/error.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/http/error.ts"],"names":[],"mappings":";;;AAAA,oCAA+C;AAE/C,MAAa,oBAAqB,SAAQ,iBAAS;IAC/C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC,IAAI,CAAC;IAC1C,CAAC;CACJ;AAND,oDAMC;AAED,MAAa,6BAA8B,SAAQ,iBAAS;IACxD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC,IAAI,CAAC;IACnD,CAAC;CACJ;AAND,sEAMC;AAED,MAAa,yBAA0B,SAAQ,iBAAS;IACpD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC;IAC/C,CAAC;CACJ;AAND,8DAMC;AAED,MAAa,yBAA0B,SAAQ,iBAAS;IACpD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC;IAC/C,CAAC;CACJ;AAND,8DAMC;AAED,MAAa,oBAAqB,SAAQ,iBAAS;IAC/C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC,IAAI,CAAC;IAC1C,CAAC;CACJ;AAND,oDAMC;AAED,MAAa,uBAAwB,SAAQ,iBAAS;IAClD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC,IAAI,CAAC;IAC7C,CAAC;CACJ;AAND,0DAMC;AAED,MAAa,wBAAyB,SAAQ,iBAAS;IACnD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC,IAAI,CAAC;IAC9C,CAAC;CACJ;AAND,4DAMC;AAED,MAAa,eAAgB,SAAQ,iBAAS;IAC1C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC;IACrC,CAAC;CACJ;AAND,0CAMC;AAED,MAAa,gBAAiB,SAAQ,iBAAS;IAE3C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;IACtC,CAAC;CACJ;AAPD,4CAOC;AAED,MAAa,eAAgB,SAAQ,iBAAS;IAE1C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC;IACrC,CAAC;CACJ;AAPD,0CAOC;AAED,MAAa,kBAAmB,SAAQ,iBAAS;IAE7C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC;IACxC,CAAC;CACJ;AAPD,gDAOC;AAED,MAAa,cAAe,SAAQ,iBAAS;IAEzC,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC;IACpC,CAAC;CACJ;AAPD,wCAOC"}

10
build/http/index.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
export * from "./api";
export * from "./cache";
export * from "./device";
export * from "./interfaces";
export * from "./models";
export * from "./parameter";
export * from "./station";
export * from "./types";
export * from "./error";
export { isGreaterEqualMinVersion, getAbsoluteFilePath } from "./utils";

30
build/http/index.js Normal file
View File

@ -0,0 +1,30 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAbsoluteFilePath = exports.isGreaterEqualMinVersion = void 0;
__exportStar(require("./api"), exports);
__exportStar(require("./cache"), exports);
__exportStar(require("./device"), exports);
__exportStar(require("./interfaces"), exports);
__exportStar(require("./models"), exports);
__exportStar(require("./parameter"), exports);
__exportStar(require("./station"), exports);
__exportStar(require("./types"), exports);
__exportStar(require("./error"), exports);
var utils_1 = require("./utils");
Object.defineProperty(exports, "isGreaterEqualMinVersion", { enumerable: true, get: function () { return utils_1.isGreaterEqualMinVersion; } });
Object.defineProperty(exports, "getAbsoluteFilePath", { enumerable: true, get: function () { return utils_1.getAbsoluteFilePath; } });
//# sourceMappingURL=index.js.map

1
build/http/index.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,wCAAsB;AACtB,0CAAwB;AACxB,2CAAyB;AACzB,+CAA6B;AAC7B,2CAAyB;AACzB,8CAA4B;AAC5B,4CAA0B;AAC1B,0CAAwB;AACxB,0CAAwB;AACxB,iCAAuE;AAA9D,iHAAA,wBAAwB,OAAA;AAAE,4GAAA,mBAAmB,OAAA"}

241
build/http/interfaces.d.ts vendored Normal file
View File

@ -0,0 +1,241 @@
import { Readable } from "stream";
import type { Method } from "got" with {
"resolution-mode": "import"
};
import type { ImageFileExtension } from "image-type" with {
"resolution-mode": "import"
};
import { DatabaseCountByDate, DatabaseQueryLatestInfo, DatabaseQueryLocal, StreamMetadata } from "../p2p/interfaces";
import { CommandResult, StorageInfoBodyHB3 } from "../p2p/models";
import { AlarmEvent, DatabaseReturnCode, SmartSafeAlarm911Event, SmartSafeShakeAlarmEvent, TFCardStatus } from "../p2p/types";
import { Camera, Device } from "./device";
import { Cipher, Voice, Invite, DeviceListResponse, StationListResponse, HouseListResponse } from "./models";
import { Station } from "./station";
import { CommandName, PropertyName, SourceType } from "./types";
import { TalkbackStream } from "../p2p/talkback";
export type PropertyValue = number | boolean | string | object;
export interface PropertyValues {
[index: string]: PropertyValue;
}
export interface DeviceConfig {
simultaneousDetections?: boolean;
}
export interface RawValue {
value: string;
source: SourceType;
}
export interface RawValues {
[index: number]: RawValue;
}
export interface Devices {
[index: string]: Device;
}
export interface Cameras {
[index: string]: Camera;
}
export interface Stations {
[index: string]: Station;
}
export interface Houses {
[index: string]: HouseListResponse;
}
export interface Hubs {
[index: string]: StationListResponse;
}
export interface FullDevices {
[index: string]: DeviceListResponse;
}
export interface Ciphers {
[index: number]: Cipher;
}
export interface Voices {
[index: number]: Voice;
}
export interface Invites {
[index: number]: Invite;
}
export interface HTTPApiRequest {
method: Method;
endpoint: string | URL;
responseType?: "text" | "json" | "buffer";
data?: any;
}
export type PropertyMetadataType = "number" | "boolean" | "string" | "object";
export interface PropertyMetadataAny {
key: number | string;
name: PropertyName;
type: PropertyMetadataType;
default?: any;
readable: boolean;
writeable: boolean;
description?: string;
label?: string;
commandId?: number;
}
export interface PropertyMetadataNumeric extends PropertyMetadataAny {
type: "number";
min?: number;
max?: number;
steps?: number;
default?: number;
states?: Record<number, string>;
unit?: string;
}
export interface PropertyMetadataBoolean extends PropertyMetadataAny {
type: "boolean";
default?: boolean;
}
export interface PropertyMetadataString extends PropertyMetadataAny {
type: "string";
minLength?: number;
maxLength?: number;
default?: string;
format?: RegExp;
}
export interface PropertyMetadataObject extends PropertyMetadataAny {
type: "object";
isValidObject?: (obj: any) => boolean;
default?: any;
}
export interface IndexedProperty {
[index: string]: PropertyMetadataAny;
}
export interface Properties {
[index: number]: IndexedProperty;
}
export interface Commands {
[index: number]: Array<CommandName>;
}
export interface HTTPApiPersistentData {
user_id: string;
email: string;
nick_name: string;
device_public_keys: {
[index: string]: string;
};
clientPrivateKey: string;
serverPublicKey: string;
}
export interface CaptchaOptions {
captchaCode: string;
captchaId: string;
}
export interface LoginOptions {
verifyCode?: string;
captcha?: CaptchaOptions;
force: boolean;
}
export interface Schedule {
startDateTime?: Date;
endDateTime?: Date;
week?: {
monday: boolean;
tuesday: boolean;
wednesday: boolean;
thursday: boolean;
friday: boolean;
saturday: boolean;
sunday: boolean;
};
}
export interface ImageType {
ext: ImageFileExtension | "unknown";
mime: string;
}
export interface Picture {
data: Buffer;
type: ImageType;
}
export interface HTTPApiEvents {
"devices": (devices: FullDevices) => void;
"hubs": (hubs: Hubs) => void;
"houses": (houses: Houses) => void;
"connect": () => void;
"close": () => void;
"connection error": (error: Error) => void;
"tfa request": () => void;
"captcha request": (id: string, captcha: string) => void;
"auth token invalidated": () => void;
}
export interface StationEvents {
"connect": (station: Station) => void;
"close": (station: Station) => void;
"connection error": (station: Station, error: Error) => void;
"raw device property changed": (deviceSN: string, params: RawValues) => void;
"property changed": (station: Station, name: string, value: PropertyValue, ready: boolean) => void;
"raw property changed": (station: Station, type: number, value: string) => void;
"command result": (station: Station, result: CommandResult) => void;
"download start": (station: Station, channel: number, metadata: StreamMetadata, videostream: Readable, audiostream: Readable) => void;
"download finish": (station: Station, channel: number) => void;
"livestream start": (station: Station, channel: number, metadata: StreamMetadata, videostream: Readable, audiostream: Readable) => void;
"livestream stop": (station: Station, channel: number) => void;
"livestream error": (station: Station, channel: number, error: Error) => void;
"rtsp livestream start": (station: Station, channel: number) => void;
"rtsp livestream stop": (station: Station, channel: number) => void;
"rtsp url": (station: Station, channel: number, value: string) => void;
"guard mode": (station: Station, guardMode: number) => void;
"current mode": (station: Station, currentMode: number) => void;
"alarm event": (station: Station, alarmEvent: AlarmEvent) => void;
"ready": (station: Station) => void;
"runtime state": (station: Station, channel: number, batteryLevel: number, temperature: number) => void;
"charging state": (station: Station, channel: number, chargeType: number, batteryLevel: number) => void;
"wifi rssi": (station: Station, channel: number, rssi: number) => void;
"floodlight manual switch": (station: Station, channel: number, enabled: boolean) => void;
"alarm delay event": (station: Station, alarmDelayEvent: AlarmEvent, alarmDelay: number) => void;
"alarm arm delay event": (station: Station, armDelay: number) => void;
"alarm armed event": (station: Station) => void;
"talkback started": (station: Station, channel: number, talkbackStream: TalkbackStream) => void;
"talkback stopped": (station: Station, channel: number) => void;
"talkback error": (station: Station, channel: number, error: Error) => void;
"secondary command result": (station: Station, result: CommandResult) => void;
"device shake alarm": (deviceSN: string, event: SmartSafeShakeAlarmEvent) => void;
"device 911 alarm": (deviceSN: string, event: SmartSafeAlarm911Event) => void;
"device jammed": (deviceSN: string) => void;
"device low battery": (deviceSN: string) => void;
"device wrong try-protect alarm": (deviceSN: string) => void;
"device pin verified": (deviceSN: string, successfull: boolean) => void;
"sd info ex": (station: Station, sdStatus: TFCardStatus, sdCapacity: number, sdCapacityAvailable: number) => void;
"image download": (station: Station, file: string, image: Buffer) => void;
"database query latest": (station: Station, returnCode: DatabaseReturnCode, data: Array<DatabaseQueryLatestInfo>) => void;
"database query local": (station: Station, returnCode: DatabaseReturnCode, data: Array<DatabaseQueryLocal>) => void;
"database count by date": (station: Station, returnCode: DatabaseReturnCode, data: Array<DatabaseCountByDate>) => void;
"database delete": (station: Station, returnCode: DatabaseReturnCode, failedIds: Array<unknown>) => void;
"sensor status": (station: Station, channel: number, status: number) => void;
"garage door status": (station: Station, channel: number, doorId: number, status: number) => void;
"storage info hb3": (station: Station, channel: number, storageInfo: StorageInfoBodyHB3) => void;
}
export interface DeviceEvents {
"property changed": (device: Device, name: string, value: PropertyValue, ready: boolean) => void;
"raw property changed": (device: Device, type: number, value: string) => void;
"motion detected": (device: Device, state: boolean) => void;
"person detected": (device: Device, state: boolean, person: string) => void;
"pet detected": (device: Device, state: boolean) => void;
"sound detected": (device: Device, state: boolean) => void;
"crying detected": (device: Device, state: boolean) => void;
"vehicle detected": (device: Device, state: boolean) => void;
"dog detected": (device: Device, state: boolean) => void;
"dog lick detected": (device: Device, state: boolean) => void;
"dog poop detected": (device: Device, state: boolean) => void;
"stranger person detected": (device: Device, state: boolean) => void;
"rings": (device: Device, state: boolean) => void;
"locked": (device: Device, state: boolean) => void;
"open": (device: Device, state: boolean) => void;
"ready": (device: Device) => void;
"package delivered": (device: Device, state: boolean) => void;
"package stranded": (device: Device, state: boolean) => void;
"package taken": (device: Device, state: boolean) => void;
"someone loitering": (device: Device, state: boolean) => void;
"radar motion detected": (device: Device, state: boolean) => void;
"911 alarm": (device: Device, state: boolean, detail: SmartSafeAlarm911Event) => void;
"shake alarm": (device: Device, state: boolean, detail: SmartSafeShakeAlarmEvent) => void;
"wrong try-protect alarm": (device: Device, state: boolean) => void;
"long time not close": (device: Device, state: boolean) => void;
"low battery": (device: Device, state: boolean) => void;
"jammed": (device: Device, state: boolean) => void;
"tampering": (device: Device, state: boolean) => void;
"low temperature": (device: Device, state: boolean) => void;
"high temperature": (device: Device, state: boolean) => void;
"pin incorrect": (device: Device, state: boolean) => void;
"lid stuck": (device: Device, state: boolean) => void;
"battery fully charged": (device: Device, state: boolean) => void;
}

3
build/http/interfaces.js Normal file
View File

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=interfaces.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../../src/http/interfaces.ts"],"names":[],"mappings":""}

608
build/http/models.d.ts vendored Normal file
View File

@ -0,0 +1,608 @@
import { UserPasswordType, UserType } from "./types";
export interface ApiResponse {
status: number;
statusText: string;
data: any;
headers: any;
}
export interface ResultResponse {
code: number;
msg: string;
data?: any;
outline?: any;
}
export interface LoginResultResponse {
user_id: string;
email: string;
nick_name: string;
auth_token: string;
token_expires_at: number;
avatar: string;
invitation_code: string;
inviter_code: string;
verify_code_url: string;
mac_addr: string;
domain: string;
ab_code: string;
geo_key: string;
privilege: number;
phone: string;
phone_code: string;
server_secret_info: {
public_key: string;
} | null;
params: Array<{
param_type: number;
param_value: string;
}> | null;
trust_list: Array<TrustDevice>;
}
export interface CaptchaResponse {
captcha_id: string;
item: string;
}
export interface LoginRequest {
ab: string;
client_secret_info: {
public_key: string;
};
enc: number;
email: string;
password: string;
time_zone: number;
verify_code?: string;
captcha_id?: string;
answer?: string;
transaction: string;
}
export interface Member {
family_id: number;
station_sn: string;
admin_user_id: string;
member_user_id: string;
short_user_id: string;
member_type: number;
permissions: number;
member_nick: string;
action_user_id: string;
fence_state: number;
extra: string;
member_avatar: string;
house_id: string;
create_time: number;
update_time: number;
status: number;
email: string;
nick_name: string;
avatar: string;
action_user_email: string;
action_user_name: string;
}
export interface StationListDevice {
device_id: number;
is_init_complete: boolean;
device_sn: string;
device_name: string;
device_model: string;
time_zone: string;
device_type: number;
device_channel: number;
station_sn: string;
schedule: string;
schedulex: string;
wifi_mac: string;
sub1g_mac: string;
main_sw_version: string;
main_hw_version: string;
sec_sw_version: string;
sec_hw_version: string;
sector_id: number;
event_num: number;
wifi_ssid: string;
ip_addr: string;
main_sw_time: number;
sec_sw_time: number;
bind_time: number;
local_ip: string;
language: string;
sku_number: string;
lot_number: string;
cpu_id: string;
create_time: number;
update_time: number;
status: number;
}
export interface StationListResponse {
readonly [index: string]: unknown;
station_id: number;
station_sn: string;
station_name: string;
station_model: string;
time_zone: string;
wifi_ssid: string;
ip_addr: string;
wifi_mac: string;
sub1g_mac: string;
main_sw_version: string;
main_hw_version: string;
sec_sw_version: string;
sec_hw_version: string;
volume: string;
main_sw_time: number;
sec_sw_time: number;
bt_mac: string;
setup_code: string;
setup_id: string;
device_type: number;
event_num: number;
sku_number: string;
lot_number: string;
create_time: number;
update_time: number;
status: number;
station_status: number;
status_change_time: number;
p2p_did: string;
push_did: string;
p2p_license: string;
push_license: string;
ndt_did: string;
ndt_license: string;
wakeup_flag: number;
p2p_conn: string;
app_conn: string;
wipn_enc_dec_key: string;
wipn_ndt_aes128key: string;
query_server_did: string;
prefix: string;
wakeup_key: string;
member: Member;
params: Array<ParameterResponse>;
devices: Array<StationListDevice>;
sensor_info: null;
is_init_complete: boolean;
virtual_version: string;
house_id?: string;
}
export interface ParameterResponse {
param_id: number;
station_sn: string;
param_type: number;
param_value: string;
create_time: number;
update_time: number;
status: number;
}
export interface DeviceResponse {
device_id: number;
is_init_complete: boolean;
device_sn: string;
device_name: string;
device_model: string;
time_zone: string;
device_type: number;
device_channel: number;
station_sn: string;
schedule: string;
schedulex: string;
wifi_mac: string;
sub1g_mac: string;
main_sw_version: string;
main_hw_version: string;
sec_sw_version: string;
sec_hw_version: string;
sector_id: number;
event_num: number;
wifi_ssid: string;
ip_addr: string;
main_sw_time: number;
sec_sw_time: number;
bind_time: number;
cover_path: string;
cover_time: number;
local_ip: string;
language: string;
sku_number: string;
lot_number: string;
create_time: number;
update_time: number;
status: number;
}
export interface DeviceRequest {
device_sn: string;
num: number;
orderby: string;
page: number;
station_sn: string;
}
export interface DeviceListResponse {
readonly [index: string]: unknown;
device_id: number;
is_init_complete: boolean;
device_sn: string;
device_name: string;
device_model: string;
time_zone: string;
device_type: number;
device_channel: number;
station_sn: string;
schedule: string;
schedulex: string;
wifi_mac: string;
sub1g_mac: string;
main_sw_version: string;
main_hw_version: string;
sec_sw_version: string;
sec_hw_version: string;
sector_id: number;
event_num: number;
wifi_ssid: string;
ip_addr: string;
volume: string;
main_sw_time: number;
sec_sw_time: number;
bind_time: number;
bt_mac: string;
cover_path: string;
cover_time: number;
local_ip: string;
language: string;
sku_number: string;
lot_number: string;
cpu_id: string;
create_time: number;
update_time: number;
status: number;
svr_domain: string;
svr_port: number;
station_conn: {
station_sn: string;
station_name: string;
station_model: string;
main_sw_version: string;
main_hw_version: string;
p2p_did: string;
push_did: string;
ndt_did: string;
p2p_conn: string;
app_conn: string;
binded: false;
setup_code: string;
setup_id: string;
bt_mac: string;
wifi_mac: string;
dsk_key: string;
expiration: number;
};
family_num: number;
member: Member;
permission: any;
params: Array<ParameterResponse>;
pir_total: number;
pir_none: number;
pir_missing: number;
week_pir_total: number;
week_pir_none: number;
month_pir_total: number;
month_pir_none: number;
charging_days: number;
charing_total: number;
charging_reserve: number;
charging_missing: number;
battery_usage_last_week: number;
virtual_version: string;
relate_devices: any;
house_id?: string;
}
export interface DskKeyResponse {
enabled: boolean;
dsk_keys: Array<{
station_sn: string;
dsk_key: string;
expiration: number;
about_to_be_replaced: boolean;
}>;
}
export interface EventRecordResponse {
monitor_id: number;
transfer_monitor_id: number;
station_sn: string;
device_sn: string;
storage_type: number;
storage_path: string;
hevc_storage_path: string;
cloud_path: string;
frame_num: number;
thumb_path: string;
thumb_data: string;
start_time: number;
end_time: number;
cipher_id: number;
cipher_user_id: string;
has_human: number;
volume: string;
vision: number;
device_name: string;
device_type: number;
video_type: number;
extra: string;
user_range_id: number;
viewed: boolean;
create_time: number;
update_time: number;
status: number;
station_name: string;
p2p_did: string;
push_did: string;
p2p_license: string;
push_license: string;
ndt_did: string;
ndt_license: string;
wakeup_flag: number;
p2p_conn: string;
app_conn: string;
wipn_enc_dec_key: string;
wipn_ndt_aes128key: string;
query_server_did: string;
prefix: string;
wakeup_key: string;
ai_faces: Array<{
is_stranger: number;
face_url: string;
owner_id: string;
user_range_id: number;
}>;
is_favorite: boolean;
storage_alias: number;
}
export interface EventRecordRequest {
device_sn: string;
end_time: number;
id: number;
id_type: number;
is_favorite: boolean;
num: number;
pullup: boolean;
shared: boolean;
start_time: number;
station_sn: string;
storage: number;
}
export interface StreamRequest {
device_sn: string;
station_sn: string;
proto?: number;
}
export interface TrustDevice {
open_udid: string;
phone_model: string;
is_current_device: number;
}
export interface Cipher {
cipher_id: number;
user_id: string;
private_key: string;
}
export interface Voice {
voice_id: number;
user_id: string;
desc: string;
device_sn: string;
voice_link: string;
voice_type: number;
key_prefix: string;
}
export interface DeviceInvite {
device_sn: string;
checked: boolean;
}
export interface Invite {
invite_id: number;
station_sn: string;
email: string;
devices: Array<DeviceInvite>;
action_user_id: string;
member_nick: string;
member_type: number;
permissions: number;
create_time: number;
update_time: number;
status: number;
action_user_email: string;
action_user_nick: string;
}
export interface ConfirmInvite {
device_sns: Array<string>;
invite_id: number;
station_sn: string;
}
export interface SensorHistoryEntry {
trigger_time: number;
create_time: number;
status: string;
}
export interface HouseUser {
id: number;
house_id: string;
email: string;
avatar: string;
user_id: string;
admin_user_id: string;
state: string;
role_type: number;
}
export interface HouseDetail {
house_id: string;
house_name: string;
is_default: number;
id: number;
geofence_id: number;
address: string;
latitude: number;
longitude: number;
radius_range: number;
away_mode: number;
home_mode: number;
location_msg: number;
create_time: number;
house_users: Array<HouseUser>;
house_stations: any;
}
export interface HouseListResponse {
readonly [index: string]: unknown;
house_id: string;
user_id: string;
admin_user_id: string;
role_type: number;
house_name: string;
is_default: number;
geofence_id: number;
address: string;
latitude: number;
longitude: number;
radius_range: number;
location_msg: number;
create_time: number;
away_mode: number;
home_mode: number;
}
export interface HouseInviteListResponse {
readonly [index: string]: unknown;
id: number;
house_name: string;
action_user_nick: string;
action_user_email: string;
house_id: string;
email: string;
user_id: string;
role_type: number;
}
export interface ConfirmHouseInvite {
house_id: string;
invite_id: number;
is_inviter: number;
user_id: string;
}
export interface PassportProfileResponse {
user_id: string;
email: string;
nick_name: string;
avatar: string;
invitation_code: string;
inviter_code: string;
verify_code_url: string;
mac_addr: string;
country: {
id: number;
name: string;
code: string;
};
}
export interface StationSecuritySettings {
account_id: string;
count_down_alarm: StationSecuritySettingsDelayDetails;
count_down_arm: StationSecuritySettingsDelayDetails;
devices: StationSecuritySettingsDeviceDetails;
}
export interface StationSecuritySettingsDelayDetails {
account_id: string;
channel_list: number[];
delay_time: number;
}
export interface StationSecuritySettingsDeviceDetails {
action: number;
device_channel: number;
}
export interface SnoozeDetail {
snooze_time: number;
snooze_chime?: boolean;
snooze_motion?: boolean;
snooze_homebase?: boolean;
}
export interface RawSchedule {
endDay: string;
week: string;
startDay: string;
startTime: string;
endTime: string;
}
export interface UserPassword {
expiration_time: number;
is_permanent: number;
password: string;
password_id: string;
password_type: UserPasswordType;
name: string;
schedule: RawSchedule;
}
export interface User {
avatar: string;
password_list: Array<UserPassword>;
user_id: string;
short_user_id: string;
user_name: string;
user_type: UserType;
is_show: boolean;
}
export interface UsersResponse {
device_sn: string;
user_list: Array<User>;
}
export interface AddUserResponse {
user_id: string;
short_user_id: string;
}
export interface GarageDoorSensorsProperty {
cmd: number;
data: {
door_1: {
power: number;
mac_address: string;
version: string;
name: string;
sn: string;
playalarm: number;
ota: number;
needota: number;
};
door_2: {
power: number;
mac_address: string;
version: string;
name: string;
sn: string;
playalarm: number;
ota: number;
needota: number;
};
};
}
export interface FloodlightDetectionRangeT8425Property {
cur_mode: number;
test_mode: number;
mode0: Array<{
id: number;
sst: number;
}>;
mode1: Array<{
id: number;
sst: number;
}>;
mode2: Array<{
id: number;
sst: number;
}>;
}
export interface FloodlightLightSettingsBrightnessScheduleT8425Property {
sunset2rise: number;
longtitude: string;
latitude: string;
brightness: number;
schedule: Array<unknown>;
}
export interface FloodlightLightSettingsMotionT8425Property {
brightness: number;
enable: number;
mode: number;
time: number;
}

3
build/http/models.js Normal file
View File

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=models.js.map

1
build/http/models.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/http/models.ts"],"names":[],"mappings":""}

5
build/http/parameter.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import { Category } from "typescript-logging-category-style";
export declare class ParameterHelper {
static readValue(serialNumber: string, type: number, value: string, log: Category): string | undefined;
static writeValue(type: number, value: string): string;
}

103
build/http/parameter.js Normal file
View File

@ -0,0 +1,103 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ParameterHelper = void 0;
const types_1 = require("../p2p/types");
const utils_1 = require("../p2p/utils");
const utils_2 = require("../utils");
const types_2 = require("./types");
const utils_3 = require("./utils");
const error_1 = require("../error");
class ParameterHelper {
static readValue(serialNumber, type, value, log) {
if (value) {
if (type === types_2.ParamType.SNOOZE_MODE ||
type === types_2.ParamType.CAMERA_MOTION_ZONES ||
type === types_1.CommandType.CMD_SET_DOORSENSOR_ALWAYS_OPEN_DELAY ||
type === types_1.CommandType.CMD_SET_DOORSENSOR_ALWAYS_OPEN ||
type === types_1.CommandType.ARM_DELAY_HOME ||
type === types_1.CommandType.ARM_DELAY_AWAY ||
type === types_1.CommandType.ARM_DELAY_CUS1 ||
type === types_1.CommandType.ARM_DELAY_CUS2 ||
type === types_1.CommandType.ARM_DELAY_CUS3 ||
type === types_1.CommandType.ARM_DELAY_OFF ||
type === types_1.CommandType.CELLULAR_INFO ||
type === types_1.CommandType.CMD_WALL_LIGHT_SETTINGS_MANUAL_COLORED_LIGHTING ||
type === types_1.CommandType.CMD_WALL_LIGHT_SETTINGS_SCHEDULE_COLORED_LIGHTING ||
type === types_1.CommandType.CMD_WALL_LIGHT_SETTINGS_MANUAL_COLORED_LIGHTING ||
type === types_1.CommandType.CMD_WALL_LIGHT_SETTINGS_COLORED_LIGHTING_COLORS ||
type === types_1.CommandType.CMD_WALL_LIGHT_SETTINGS_DYNAMIC_LIGHTING_THEMES ||
type === types_1.CommandType.CMD_INDOOR_DET_SET_ACTIVE_ZONE ||
type === types_1.CommandType.CMD_SET_PRIVACYPARAM ||
type === types_1.CommandType.CMD_BAT_DOORBELL_VIDEO_QUALITY2 ||
type === types_1.CommandType.CMD_BAT_DOORBELL_RECORD_QUALITY2 ||
type === types_1.CommandType.CMD_SET_CROSS_TRACKING_CAMERA_LIST ||
type === types_1.CommandType.CMD_SET_CROSS_TRACKING_GROUP_LIST ||
type === types_1.CommandType.CMD_FLOODLIGHT_SET_DETECTION_RANGE_T8425 ||
type === types_1.CommandType.CMD_SET_LIGHT_CTRL_BRIGHT_PIR_T8425 ||
type === types_1.CommandType.CMD_SET_LIGHT_CTRL_BRIGHT_SCH_T8425) {
if (typeof value === "string") {
const parsedValue = (0, utils_2.parseJSON)((0, utils_1.getNullTerminatedString)((0, utils_1.decodeBase64)(value), "utf-8"), log);
if (parsedValue === undefined) {
log.debug("Non-parsable parameter value received from eufy cloud. Will be ignored.", { serialNumber: serialNumber, type: type, value: value });
}
return parsedValue;
}
else {
return value; //return object
}
}
else if (type === types_1.CommandType.CMD_BAT_DOORBELL_SET_NOTIFICATION_MODE ||
type === types_1.CommandType.CMD_DOORBELL_DUAL_RADAR_WD_DETECTION_SENSITIVITY ||
type === types_1.CommandType.CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE ||
type === types_1.CommandType.CMD_DOORBELL_DUAL_PACKAGE_STRAND_TIME ||
type === types_1.CommandType.CMD_DOORBELL_DUAL_RING_AUTO_RESPONSE ||
type === types_1.CommandType.CMD_DOORBELL_DUAL_PACKAGE_GUARD_TIME ||
type === types_1.CommandType.CMD_DOORBELL_DUAL_RADAR_WD_DISTANCE ||
type === types_1.CommandType.CMD_DOORBELL_DUAL_RADAR_WD_TIME ||
type === types_1.CommandType.CMD_DOORBELL_DUAL_DELIVERY_GUARD_SWITCH ||
type === types_1.CommandType.CMD_DOORBELL_DUAL_PACKAGE_GUARD_VOICE ||
type === types_1.CommandType.CMD_CAMERA_GARAGE_DOOR_SENSORS ||
type === types_1.CommandType.CMD_MOTION_SET_LEAVING_REACTIONS) {
if (typeof value === "string") {
const parsedValue = (0, utils_2.parseJSON)(value, log);
if (parsedValue === undefined) {
log.debug("Non-parsable parameter value received from eufy cloud. Will be ignored.", { serialNumber: serialNumber, type: type, value: value });
}
return parsedValue;
}
else {
return value; //return object
}
}
else if (type === types_1.TrackerCommandType.COMMAND_NEW_LOCATION ||
type === types_1.TrackerCommandType.LOCATION_NEW_ADDRESS) {
try {
const decrypted = (0, utils_3.decryptTrackerData)(Buffer.from(value, "hex"), Buffer.from(serialNumber));
if (decrypted !== undefined) {
return decrypted.toString("utf8").trim();
}
}
catch (err) {
const error = (0, error_1.ensureError)(err);
log.debug("Non-parsable parameter value received from eufy cloud. Will be ignored.", { serialNumber: serialNumber, type: type, value: value, error: (0, utils_2.getError)(error) });
}
return "";
}
}
return value;
}
static writeValue(type, value) {
if (value) {
if (type === types_2.ParamType.SNOOZE_MODE ||
type === types_2.ParamType.CAMERA_MOTION_ZONES ||
type === types_1.CommandType.CMD_SET_DOORSENSOR_ALWAYS_OPEN_DELAY ||
type === types_1.CommandType.CMD_SET_DOORSENSOR_ALWAYS_OPEN) {
return Buffer.from(JSON.stringify(value)).toString("base64");
}
return value;
}
return "";
}
}
exports.ParameterHelper = ParameterHelper;
//# sourceMappingURL=parameter.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"parameter.js","sourceRoot":"","sources":["../../src/http/parameter.ts"],"names":[],"mappings":";;;AAEA,wCAA+D;AAC/D,wCAAqE;AACrE,oCAA+C;AAC/C,mCAAoC;AACpC,mCAA6C;AAC7C,oCAAuC;AAEvC,MAAa,eAAe;IAEjB,MAAM,CAAC,SAAS,CAAC,YAAoB,EAAE,IAAY,EAAE,KAAa,EAAE,GAAa;QACpF,IAAI,KAAK,EAAE,CAAC;YACR,IAAI,IAAI,KAAK,iBAAS,CAAC,WAAW;gBAC9B,IAAI,KAAK,iBAAS,CAAC,mBAAmB;gBACtC,IAAI,KAAK,mBAAW,CAAC,oCAAoC;gBACzD,IAAI,KAAK,mBAAW,CAAC,8BAA8B;gBACnD,IAAI,KAAK,mBAAW,CAAC,cAAc;gBACnC,IAAI,KAAK,mBAAW,CAAC,cAAc;gBACnC,IAAI,KAAK,mBAAW,CAAC,cAAc;gBACnC,IAAI,KAAK,mBAAW,CAAC,cAAc;gBACnC,IAAI,KAAK,mBAAW,CAAC,cAAc;gBACnC,IAAI,KAAK,mBAAW,CAAC,aAAa;gBAClC,IAAI,KAAK,mBAAW,CAAC,aAAa;gBAClC,IAAI,KAAK,mBAAW,CAAC,+CAA+C;gBACpE,IAAI,KAAK,mBAAW,CAAC,iDAAiD;gBACtE,IAAI,KAAK,mBAAW,CAAC,+CAA+C;gBACpE,IAAI,KAAK,mBAAW,CAAC,+CAA+C;gBACpE,IAAI,KAAK,mBAAW,CAAC,+CAA+C;gBACpE,IAAI,KAAK,mBAAW,CAAC,8BAA8B;gBACnD,IAAI,KAAK,mBAAW,CAAC,oBAAoB;gBACzC,IAAI,KAAK,mBAAW,CAAC,+BAA+B;gBACpD,IAAI,KAAK,mBAAW,CAAC,gCAAgC;gBACrD,IAAI,KAAK,mBAAW,CAAC,kCAAkC;gBACvD,IAAI,KAAK,mBAAW,CAAC,iCAAiC;gBACtD,IAAI,KAAK,mBAAW,CAAC,wCAAwC;gBAC7D,IAAI,KAAK,mBAAW,CAAC,mCAAmC;gBACxD,IAAI,KAAK,mBAAW,CAAC,mCAAmC,EAAE,CAAC;gBAC3D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC5B,MAAM,WAAW,GAAG,IAAA,iBAAS,EAAC,IAAA,+BAAuB,EAAC,IAAA,oBAAY,EAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;oBAC1F,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;wBAC5B,GAAG,CAAC,KAAK,CAAC,yEAAyE,EAAE,EAAE,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;oBACnJ,CAAC;oBACD,OAAO,WAAW,CAAC;gBACvB,CAAC;qBAAM,CAAC;oBACJ,OAAO,KAAK,CAAC,CAAC,eAAe;gBACjC,CAAC;YACL,CAAC;iBAAM,IAAI,IAAI,KAAK,mBAAW,CAAC,sCAAsC;gBAClE,IAAI,KAAK,mBAAW,CAAC,gDAAgD;gBACrE,IAAI,KAAK,mBAAW,CAAC,wCAAwC;gBAC7D,IAAI,KAAK,mBAAW,CAAC,qCAAqC;gBAC1D,IAAI,KAAK,mBAAW,CAAC,oCAAoC;gBACzD,IAAI,KAAK,mBAAW,CAAC,oCAAoC;gBACzD,IAAI,KAAK,mBAAW,CAAC,mCAAmC;gBACxD,IAAI,KAAK,mBAAW,CAAC,+BAA+B;gBACpD,IAAI,KAAK,mBAAW,CAAC,uCAAuC;gBAC5D,IAAI,KAAK,mBAAW,CAAC,qCAAqC;gBAC1D,IAAI,KAAK,mBAAW,CAAC,8BAA8B;gBACnD,IAAI,KAAK,mBAAW,CAAC,gCAAgC,EAAE,CAAC;gBACxD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC5B,MAAM,WAAW,GAAG,IAAA,iBAAS,EAAC,KAAK,EAAE,GAAG,CAAC,CAAC;oBAC1C,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;wBAC5B,GAAG,CAAC,KAAK,CAAC,yEAAyE,EAAE,EAAE,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;oBACnJ,CAAC;oBACD,OAAO,WAAW,CAAC;gBACvB,CAAC;qBAAM,CAAC;oBACJ,OAAO,KAAK,CAAC,CAAC,eAAe;gBACjC,CAAC;YACL,CAAC;iBAAM,IAAI,IAAI,KAAK,0BAAkB,CAAC,oBAAoB;gBACvD,IAAI,KAAK,0BAAkB,CAAC,oBAAoB,EAAE,CAAC;gBACnD,IAAI,CAAC;oBACD,MAAM,SAAS,GAAG,IAAA,0BAAkB,EAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAG,KAAK,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;oBAC5F,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;wBAC1B,OAAO,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;oBAC7C,CAAC;gBACL,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACX,MAAM,KAAK,GAAG,IAAA,mBAAW,EAAC,GAAG,CAAC,CAAC;oBAC/B,GAAG,CAAC,KAAK,CAAC,yEAAyE,EAAE,EAAE,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAA,gBAAQ,EAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC3K,CAAC;gBACD,OAAO,EAAE,CAAC;YACd,CAAC;QACL,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAEM,MAAM,CAAC,UAAU,CAAC,IAAY,EAAE,KAAa;QAChD,IAAI,KAAK,EAAE,CAAC;YACR,IAAI,IAAI,KAAK,iBAAS,CAAC,WAAW;gBAC9B,IAAI,KAAK,iBAAS,CAAC,mBAAmB;gBACtC,IAAI,KAAK,mBAAW,CAAC,oCAAoC;gBACzD,IAAI,KAAK,mBAAW,CAAC,8BAA8B,EAAE,CAAC;gBACtD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACjE,CAAC;YACD,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,OAAO,EAAE,CAAC;IACd,CAAC;CAEJ;AAzFD,0CAyFC"}

364
build/http/station.d.ts vendored Normal file
View File

@ -0,0 +1,364 @@
import { TypedEmitter } from "tiny-typed-emitter";
import { HTTPApi } from "./api";
import { AlarmTone, NotificationSwitchMode, DeviceType, FloodlightMotionTriggeredDistance, GuardMode, NotificationType, PowerSource, PropertyName, TimeFormat, CommandName, VideoTypeStoreToNAS, HB3DetectionTypes, WalllightNotificationType, DailyLightingType, MotionActivationMode, LightingActiveMode, SourceType, T8170DetectionTypes, IndoorS350NotificationTypes, SoloCameraDetectionTypes, MotionDetectionRangeType, ViewModeType, FloodlightT8425NotificationTypes, PresetPositionType, IndoorS350DetectionTypes } from "./types";
import { SnoozeDetail, StationListResponse } from "./models";
import { IndexedProperty, PropertyMetadataAny, PropertyValue, PropertyValues, RawValues, StationEvents, Schedule } from "./interfaces";
import { CrossTrackingGroupEntry, DynamicLighting, MotionZone, RGBColor } from "../p2p/interfaces";
import { CalibrateGarageType, FilterDetectType, FilterEventType, FilterStorageType, P2PConnectionType, PanTiltDirection, VideoCodec, WatermarkSetting1, WatermarkSetting2, WatermarkSetting3, WatermarkSetting4, WatermarkSetting5 } from "../p2p/types";
import { Device } from "./device";
import { PushMessage } from "../push/models";
export declare class Station extends TypedEmitter<StationEvents> {
private api;
private rawStation;
private p2pSession;
private properties;
private rawProperties;
private ready;
private lockPublicKey;
private currentDelay;
private reconnectTimeout?;
private terminating;
private p2pConnectionType;
static readonly CHANNEL: number;
static readonly CHANNEL_INDOOR: number;
private pinVerified;
protected constructor(api: HTTPApi, station: StationListResponse, ipAddress?: string, listeningPort?: number, publicKey?: string, enableEmbeddedPKCS1Support?: boolean);
protected initializeState(): void;
initialize(): void;
static getInstance(api: HTTPApi, stationData: StationListResponse, ipAddress?: string, listeningPort?: number, enableEmbeddedPKCS1Support?: boolean): Promise<Station>;
getStateID(state: string, level?: number): string;
getStateChannel(): string;
getRawStation(): StationListResponse;
update(station: StationListResponse): void;
updateProperty(name: string, value: PropertyValue, force?: boolean): boolean;
updateRawProperties(values: RawValues): void;
protected handlePropertyChange(metadata: PropertyMetadataAny, oldValue: PropertyValue, newValue: PropertyValue): void;
updateRawProperty(type: number, value: string, source: SourceType): boolean;
protected convertRawPropertyValue(property: PropertyMetadataAny, value: string): PropertyValue;
getPropertyMetadata(name: string, hidden?: boolean): PropertyMetadataAny;
getPropertyValue(name: string): PropertyValue;
hasPropertyValue(name: string): boolean;
getRawProperty(type: number): string | undefined;
getRawProperties(): RawValues;
getProperties(): PropertyValues;
getPropertiesMetadata(hidden?: boolean): IndexedProperty;
hasProperty(name: string, hidden?: boolean): boolean;
getCommands(): Array<CommandName>;
hasCommand(name: CommandName): boolean;
static getChannel(type: number): number;
static isStation(type: number): boolean;
isStation(): boolean;
static isStationHomeBase3(type: number): boolean;
static isStationHomeBase3BySn(sn: string): boolean;
isStationHomeBase3(): boolean;
isIntegratedDevice(): boolean;
isP2PConnectableDevice(): boolean;
getDeviceType(): number;
getHardwareVersion(): string;
getMACAddress(): string;
getModel(): string;
getName(): string;
getSerial(): string;
getSoftwareVersion(): string;
getIPAddress(): string;
getLANIPAddress(): PropertyValue;
getGuardMode(): PropertyValue;
getCurrentMode(): PropertyValue;
processPushNotification(message: PushMessage): void;
isConnected(): boolean;
close(): void;
isEnergySavingDevice(): boolean;
connect(): Promise<void>;
private onFinishDownload;
private onStartDownload;
private onStopLivestream;
private onErrorLivestream;
private onStartLivestream;
private onStopRTSPLivestream;
private onStartRTSPLivestream;
private onWifiRssiChanged;
private onRTSPUrl;
private onParameter;
private onAlarmDelay;
private onAlarmArmed;
private onAlarmEvent;
setGuardMode(mode: GuardMode): void;
getCameraInfo(): void;
getStorageInfoEx(): void;
private onAlarmMode;
private getArmDelay;
private _getDeviceSerial;
private _handleCameraInfoParameters;
private onCameraInfo;
private onCommandResponse;
private onSecondaryCommandResponse;
private onConnect;
private onDisconnect;
private onTimeout;
private getCurrentDelay;
private resetCurrentDelay;
private scheduleReconnect;
rebootHUB(): void;
setStatusLed(device: Device, value: boolean): void;
setAutoNightVision(device: Device, value: boolean): void;
setNightVision(device: Device, value: number): void;
setMotionDetection(device: Device, value: boolean): void;
setSoundDetection(device: Device, value: boolean): void;
setSoundDetectionType(device: Device, value: number): void;
setSoundDetectionSensitivity(device: Device, value: number): void;
setPetDetection(device: Device, value: boolean): void;
panAndTilt(device: Device, direction: PanTiltDirection, command?: number): void;
switchLight(device: Device, value: boolean): void;
setMotionDetectionSensitivity(device: Device, value: number): void;
setMotionDetectionType(device: Device, value: number): void;
setMotionDetectionTypeHB3(device: Device, type: HB3DetectionTypes | T8170DetectionTypes | SoloCameraDetectionTypes | IndoorS350DetectionTypes, value: boolean): void;
setMotionZone(device: Device, value: MotionZone): void;
setMotionTracking(device: Device, value: boolean): void;
setPanAndTiltRotationSpeed(device: Device, value: number): void;
setMicMute(device: Device, value: boolean): void;
setAudioRecording(device: Device, value: boolean): void;
enableSpeaker(device: Device, value: boolean): void;
setSpeakerVolume(device: Device, value: number): void;
setRingtoneVolume(device: Device, value: number): void;
enableIndoorChime(device: Device, value: boolean): void;
enableHomebaseChime(device: Device, value: boolean): void;
setHomebaseChimeRingtoneVolume(device: Device, value: number): void;
setHomebaseChimeRingtoneType(device: Device, value: number): void;
setNotificationType(device: Device, value: NotificationType | WalllightNotificationType): void;
setNotificationPerson(device: Device, value: boolean): void;
setNotificationPet(device: Device, value: boolean): void;
setNotificationAllOtherMotion(device: Device, value: boolean): void;
setNotificationAllSound(device: Device, value: boolean): void;
setNotificationCrying(device: Device, value: boolean): void;
setNotificationRing(device: Device, value: boolean): void;
setNotificationMotion(device: Device, value: boolean): void;
setPowerSource(device: Device, value: PowerSource): void;
setPowerWorkingMode(device: Device, value: number): void;
setRecordingClipLength(device: Device, value: number): void;
setRecordingRetriggerInterval(device: Device, value: number): void;
setRecordingEndClipMotionStops(device: Device, value: boolean): void;
setVideoStreamingQuality(device: Device, value: number): void;
setVideoRecordingQuality(device: Device, value: number): void;
setWDR(device: Device, value: boolean): void;
setFloodlightLightSettingsEnable(device: Device, value: boolean): void;
setFloodlightLightSettingsBrightnessManual(device: Device, value: number): void;
setFloodlightLightSettingsBrightnessMotion(device: Device, value: number): void;
setFloodlightLightSettingsBrightnessSchedule(device: Device, value: number): void;
setFloodlightLightSettingsMotionTriggered(device: Device, value: boolean): void;
setFloodlightLightSettingsMotionTriggeredDistance(device: Device, value: FloodlightMotionTriggeredDistance): void;
setFloodlightLightSettingsMotionTriggeredTimer(device: Device, seconds: number): void;
triggerStationAlarmSound(seconds: number): void;
resetStationAlarmSound(): void;
triggerDeviceAlarmSound(device: Device, seconds: number): void;
resetDeviceAlarmSound(device: Device): void;
setStationAlarmRingtoneVolume(value: number): void;
setStationAlarmTone(value: AlarmTone): void;
setStationPromptVolume(value: number): void;
setStationNotificationSwitchMode(mode: NotificationSwitchMode, value: boolean): void;
setStationNotificationStartAlarmDelay(value: boolean): void;
setStationTimeFormat(value: TimeFormat): void;
setRTSPStream(device: Device, value: boolean): void;
setAntiTheftDetection(device: Device, value: boolean): void;
setWatermark(device: Device, value: WatermarkSetting1 | WatermarkSetting2 | WatermarkSetting3 | WatermarkSetting4 | WatermarkSetting5): void;
enableDevice(device: Device, value: boolean): void;
startDownload(device: Device, path: string, cipher_id?: number): Promise<void>;
cancelDownload(device: Device): void;
startLivestream(device: Device, videoCodec?: VideoCodec): void;
stopLivestream(device: Device): void;
isLiveStreaming(device: Device): boolean;
isDownloading(device: Device): boolean;
quickResponse(device: Device, voice_id: number): void;
setChirpVolume(device: Device, value: number): void;
setChirpTone(device: Device, value: number): void;
setHDR(device: Device, value: boolean): void;
setDistortionCorrection(device: Device, value: boolean): void;
setRingRecord(device: Device, value: number): void;
lockDevice(device: Device, value: boolean): void;
setStationSwitchModeWithAccessCode(value: boolean): void;
setStationAutoEndAlarm(value: boolean): void;
setStationTurnOffAlarmWithButton(value: boolean): void;
startRTSPStream(device: Device): void;
stopRTSPStream(device: Device): void;
setMotionDetectionRange(device: Device, type: MotionDetectionRangeType): void;
setMotionDetectionRangeStandardSensitivity(device: Device, sensitivity: number): void;
setMotionDetectionRangeAdvancedLeftSensitivity(device: Device, sensitivity: number): void;
setMotionDetectionRangeAdvancedMiddleSensitivity(device: Device, sensitivity: number): void;
setMotionDetectionRangeAdvancedRightSensitivity(device: Device, sensitivity: number): void;
setMotionDetectionTestMode(device: Device, enabled: boolean): void;
setMotionTrackingSensitivity(device: Device, sensitivity: number): void;
setMotionAutoCruise(device: Device, enabled: boolean): void;
setMotionOutOfViewDetection(device: Device, enabled: boolean): void;
setLightSettingsColorTemperatureManual(device: Device, value: number): void;
setLightSettingsColorTemperatureMotion(device: Device, value: number): void;
setLightSettingsColorTemperatureSchedule(device: Device, value: number): void;
setLightSettingsMotionActivationMode(device: Device, value: MotionActivationMode): void;
setVideoNightvisionImageAdjustment(device: Device, enabled: boolean): void;
setVideoColorNightvision(device: Device, enabled: boolean): void;
setAutoCalibration(device: Device, enabled: boolean): void;
isRTSPLiveStreaming(device: Device): boolean;
setConnectionType(type: P2PConnectionType): void;
getConnectionType(): P2PConnectionType;
private onRuntimeState;
private onChargingState;
hasDevice(deviceSN: string): boolean;
hasDeviceWithType(deviceType: DeviceType): boolean;
private onFloodlightManualSwitch;
calibrateLock(device: Device): void;
private convertAdvancedLockSettingValue;
private convertAdvancedLockSettingValueT8530;
private getAdvancedLockSettingsPayload;
private getAdvancedLockSettingsPayloadT8530;
private getAdvancedLockSettingName;
private getAdvancedLockSettingNameT8530;
setAdvancedLockParams(device: Device, property: PropertyName, value: PropertyValue): void;
setLoiteringDetection(device: Device, value: boolean): void;
setLoiteringDetectionRange(device: Device, value: number): void;
setLoiteringDetectionLength(device: Device, value: number): void;
private _setMotionDetectionSensitivity;
private _getMotionDetectionSensitivityAdvanced;
setMotionDetectionSensitivityMode(device: Device, value: number): void;
setMotionDetectionSensitivityStandard(device: Device, value: number): void;
setMotionDetectionSensitivityAdvancedA(device: Device, value: number): void;
setMotionDetectionSensitivityAdvancedB(device: Device, value: number): void;
setMotionDetectionSensitivityAdvancedC(device: Device, value: number): void;
setMotionDetectionSensitivityAdvancedD(device: Device, value: number): void;
setMotionDetectionSensitivityAdvancedE(device: Device, value: number): void;
setMotionDetectionSensitivityAdvancedF(device: Device, value: number): void;
setMotionDetectionSensitivityAdvancedG(device: Device, value: number): void;
setMotionDetectionSensitivityAdvancedH(device: Device, value: number): void;
private _setLoiteringCustomResponse;
setLoiteringCustomResponseAutoVoiceResponse(device: Device, value: boolean): void;
setLoiteringCustomResponseAutoVoiceResponseVoice(device: Device, value: number): void;
setLoiteringCustomResponseHomeBaseNotification(device: Device, value: boolean): void;
setLoiteringCustomResponsePhoneNotification(device: Device, value: boolean): void;
setLoiteringCustomResponseTimeFrom(device: Device, value: string): void;
setLoiteringCustomResponseTimeTo(device: Device, value: string): void;
setDeliveryGuard(device: Device, value: boolean): void;
setDeliveryGuardPackageGuarding(device: Device, value: boolean): void;
setDeliveryGuardPackageGuardingVoiceResponseVoice(device: Device, value: number): void;
private setDeliveryGuardPackageGuardingActivatedTime;
setDeliveryGuardPackageGuardingActivatedTimeFrom(device: Device, value: string): void;
setDeliveryGuardPackageGuardingActivatedTimeTo(device: Device, value: string): void;
setDeliveryGuardUncollectedPackageAlert(device: Device, value: boolean): void;
setDeliveryGuardUncollectedPackageAlertTimeToCheck(device: Device, value: string): void;
setDeliveryGuardPackageLiveCheckAssistance(device: Device, value: boolean): void;
setDualCamWatchViewMode(device: Device, value: ViewModeType): void;
private _setRingAutoResponse;
setRingAutoResponse(device: Device, value: boolean): void;
setRingAutoResponseVoiceResponse(device: Device, value: boolean): void;
setRingAutoResponseVoiceResponseVoice(device: Device, value: number): void;
setRingAutoResponseTimeFrom(device: Device, value: string): void;
setRingAutoResponseTimeTo(device: Device, value: string): void;
setNotificationRadarDetector(device: Device, value: boolean): void;
calibrate(device: Device): void;
setContinuousRecording(device: Device, value: boolean): void;
setContinuousRecordingType(device: Device, value: number): void;
enableDefaultAngle(device: Device, value: boolean): void;
setDefaultAngleIdleTime(device: Device, value: number): void;
setDefaultAngle(device: Device): void;
setPrivacyAngle(device: Device): void;
setNotificationIntervalTime(device: Device, value: number): void;
setSoundDetectionRoundLook(device: Device, value: boolean): void;
startTalkback(device: Device): void;
stopTalkback(device: Device): void;
private onTalkbackStarted;
private onTalkbackStopped;
private onTalkbackError;
isTalkbackOngoing(device: Device): boolean;
setScramblePasscode(device: Device, value: boolean): void;
setWrongTryProtection(device: Device, value: boolean): void;
setWrongTryAttempts(device: Device, value: number): void;
setWrongTryLockdownTime(device: Device, value: number): void;
private _sendSmartSafeCommand;
setSmartSafeParams(device: Device, property: PropertyName, value: PropertyValue): void;
unlock(device: Device): void;
verifyPIN(device: Device, pin: string): void;
private onDeviceShakeAlarm;
private onDevice911Alarm;
private onDeviceJammed;
private onDeviceLowBattery;
private onDeviceWrongTryProtectAlarm;
private onSdInfoEx;
setVideoTypeStoreToNAS(device: Device, value: VideoTypeStoreToNAS): void;
snooze(device: Device, value: SnoozeDetail): void;
addUser(device: Device, username: string, shortUserId: string, passcode: string, schedule?: Schedule): void;
deleteUser(device: Device, username: string, shortUserId: string): void;
updateUserSchedule(device: Device, username: string, shortUserId: string, schedule: Schedule): void;
updateUserPasscode(device: Device, username: string, passwordId: string, passcode: string): void;
setLockV12Params(device: Device, property: PropertyName, value: PropertyValue): void;
setSmartLockParams(device: Device, property: PropertyName, value: PropertyValue): void;
setAutoLock(device: Device, value: boolean): void;
setAutoLockSchedule(device: Device, value: boolean): void;
setAutoLockScheduleStartTime(device: Device, value: string): void;
setAutoLockScheduleEndTime(device: Device, value: string): void;
setAutoLockTimer(device: Device, value: number): void;
setOneTouchLocking(device: Device, value: boolean): void;
setSound(device: Device, value: number): void;
setNotification(device: Device, value: boolean): void;
setNotificationLocked(device: Device, value: boolean): void;
setNotificationUnlocked(device: Device, value: boolean): void;
private _sendLockV12P2PCommand;
queryAllUserId(device: Device): void;
chimeHomebase(value: number): void;
private onImageDownload;
downloadImage(cover_path: string): void;
private onTFCardStatus;
databaseQueryLatestInfo(failureCallback?: () => void): void;
databaseQueryLocal(serialNumbers: Array<string>, startDate: Date, endDate: Date, eventType?: FilterEventType, detectionType?: FilterDetectType, storageType?: FilterStorageType): void;
databaseDelete(ids: Array<number>): void;
databaseCountByDate(startDate: Date, endDate: Date): void;
private onDatabaseQueryLatest;
private onDatabaseQueryLocal;
private onDatabaseCountByDate;
private onDatabaseDelete;
private onSensorStatus;
setMotionDetectionTypeHuman(device: Device, value: boolean): void;
setMotionDetectionTypeAllOtherMotions(device: Device, value: boolean): void;
private _setLightSettingsLightingActiveMode;
setLightSettingsManualLightingActiveMode(device: Device, value: LightingActiveMode): void;
setLightSettingsManualDailyLighting(device: Device, value: DailyLightingType): void;
setLightSettingsManualColoredLighting(device: Device, value: RGBColor): void;
setLightSettingsManualDynamicLighting(device: Device, value: number): void;
setLightSettingsMotionLightingActiveMode(device: Device, value: LightingActiveMode): void;
setLightSettingsMotionDailyLighting(device: Device, value: DailyLightingType): void;
setLightSettingsMotionColoredLighting(device: Device, value: RGBColor): void;
setLightSettingsMotionDynamicLighting(device: Device, value: number): void;
setLightSettingsScheduleLightingActiveMode(device: Device, value: LightingActiveMode): void;
setLightSettingsScheduleDailyLighting(device: Device, value: DailyLightingType): void;
setLightSettingsScheduleColoredLighting(device: Device, value: RGBColor): void;
setLightSettingsScheduleDynamicLighting(device: Device, value: number): void;
setLightSettingsColoredLightingColors(device: Device, value: Array<RGBColor>): void;
setLightSettingsDynamicLightingThemes(device: Device, value: Array<DynamicLighting>): void;
setDoorControlWarning(device: Device, value: boolean): void;
openDoor(device: Device, value: boolean, doorId?: number): void;
private onGarageDoorStatus;
calibrateGarageDoor(device: Device, doorId: number, type: CalibrateGarageType): void;
private onStorageInfoHB3;
setMirrorMode(device: Device, value: boolean): void;
setFlickerAdjustment(device: Device, value: number): void;
setCrossCameraTracking(value: boolean): void;
setContinuousTrackingTime(value: number): void;
setTrackingAssistance(value: boolean): void;
setCrossTrackingCameraList(value: Array<string>): void;
setCrossTrackingGroupList(value: Array<CrossTrackingGroupEntry>): void;
setNotificationIndoor(device: Device, type: IndoorS350NotificationTypes, value: boolean): void;
setNotificationFloodlightT8425(device: Device, type: FloodlightT8425NotificationTypes, value: boolean): void;
presetPosition(device: Device, position: PresetPositionType): void;
savePresetPosition(device: Device, position: PresetPositionType): void;
deletePresetPosition(device: Device, position: PresetPositionType): void;
setLeavingDetection(device: Device, value: boolean): void;
private _setLeavingReactions;
setLeavingReactionNotification(device: Device, value: boolean): void;
setLeavingReactionStartTime(device: Device, value: string): void;
setLeavingReactionEndTime(device: Device, value: string): void;
setBeepVolume(device: Device, value: number): void;
setNightvisionOptimization(device: Device, value: boolean): void;
setNightvisionOptimizationSide(device: Device, value: number): void;
getLockParameters(): void;
getLockStatus(): void;
private onSequenceError;
updateUsername(device: Device, username: string, passwordId: string): void;
setOpenMethod(device: Device, value: number): void;
setMotionActivatedPrompt(device: Device, value: boolean): void;
open(device: Device): void;
}

10561
build/http/station.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

1333
build/http/types.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

9684
build/http/types.js Normal file

File diff suppressed because it is too large Load Diff

1
build/http/types.js.map Normal file

File diff suppressed because one or more lines are too long

79
build/http/utils.d.ts vendored Normal file
View File

@ -0,0 +1,79 @@
import { Device } from "./device";
import { Picture, Schedule } from "./interfaces";
import { NotificationSwitchMode, SignalLevel, HB3DetectionTypes, SourceType, T8170DetectionTypes, IndoorS350NotificationTypes, FloodlightT8425NotificationTypes, SmartLockNotification, IndoorS350DetectionTypes } from "./types";
import { HTTPApi } from "./api";
import { LockPushEvent } from "./../push/types";
import { Station } from "./station";
import { PushMessage } from "../push/models";
export declare const isGreaterEqualMinVersion: (minimal_version: string, current_version: string) => boolean;
export declare const pad: (num: number) => string;
export declare const getTimezoneGMTString: () => string;
export declare const getAbsoluteFilePath: (device_type: number, channel: number, filename: string) => string;
export declare const getImageFilePath: (device_type: number, channel: number, filename: string) => string;
export declare const isNotificationSwitchMode: (value: number, mode: NotificationSwitchMode) => boolean;
export declare const switchNotificationMode: (currentValue: number, mode: NotificationSwitchMode, enable: boolean) => number;
export declare const calculateWifiSignalLevel: (device: Device, rssi: number) => SignalLevel;
export declare const calculateCellularSignalLevel: (rssi: number) => SignalLevel;
export declare const encryptAPIData: (data: string, key: Buffer) => string;
export declare const decryptAPIData: (data: string, key: Buffer) => Buffer;
export declare const getBlocklist: (directions: Array<number>) => Array<number>;
export declare const getDistances: (blocklist: Array<number>) => Array<number>;
export declare const isHB3DetectionModeEnabled: (value: number, type: HB3DetectionTypes) => boolean;
export declare const getHB3DetectionMode: (value: number, type: HB3DetectionTypes, enable: boolean) => number;
export interface EufyTimezone {
timeZoneName: string;
timeId: string;
timeSn: string;
timeZoneGMT: string;
}
export declare const getEufyTimezone: () => EufyTimezone | undefined;
export declare const getAdvancedLockTimezone: (stationSN: string) => string;
export declare class WritePayload {
private split_byte;
private data;
write(bytes: Buffer): void;
getData(): Buffer;
}
export declare class ParsePayload {
private data;
constructor(data: Buffer);
readUint32BE(indexValue: number): number;
readUint32LE(indexValue: number): number;
readUint16BE(indexValue: number): number;
readUint16LE(indexValue: number): number;
readString(indexValue: number): string;
readStringHex(indexValue: number): string;
readInt8(indexValue: number): number;
readData(indexValue: number): Buffer;
private getDataPosition;
private getNextStep;
}
export declare const encodePasscode: (pass: string) => string;
export declare const hexDate: (date: Date) => string;
export declare const hexTime: (date: Date) => string;
export declare const hexWeek: (schedule: Schedule) => string;
export declare const hexStringScheduleToSchedule: (startDay: string, startTime: string, endDay: string, endTime: string, week: string) => Schedule;
export declare const randomNumber: (min: number, max: number) => number;
export declare const getIdSuffix: (p2pDid: string) => number;
export declare const getImageBaseCode: (serialnumber: string, p2pDid: string) => string;
export declare const getImageSeed: (p2pDid: string, code: string) => string;
export declare const getImageKey: (serialnumber: string, p2pDid: string, code: string) => string;
export declare const decodeImage: (p2pDid: string, data: Buffer) => Buffer;
export declare const getImagePath: (path: string) => string;
export declare const getImage: (api: HTTPApi, serial: string, url: string) => Promise<Picture>;
export declare const isPrioritySourceType: (current: SourceType | undefined, update: SourceType) => boolean;
export declare const decryptTrackerData: (data: Buffer, key: Buffer) => Buffer;
export declare const isT8170DetectionModeEnabled: (value: number, type: T8170DetectionTypes) => boolean;
export declare const getT8170DetectionMode: (value: number, type: T8170DetectionTypes, enable: boolean) => number;
export declare const isIndoorS350DetectionModeEnabled: (value: number, type: IndoorS350DetectionTypes) => boolean;
export declare const getIndoorS350DetectionMode: (value: number, type: IndoorS350DetectionTypes, enable: boolean) => number;
export declare const isIndoorNotitficationEnabled: (value: number, type: IndoorS350NotificationTypes) => boolean;
export declare const getIndoorNotification: (value: number, type: IndoorS350NotificationTypes, enable: boolean) => number;
export declare const isFloodlightT8425NotitficationEnabled: (value: number, type: FloodlightT8425NotificationTypes) => boolean;
export declare const getFloodLightT8425Notification: (value: number, type: FloodlightT8425NotificationTypes, enable: boolean) => number;
export declare const getLockEventType: (event: LockPushEvent) => number;
export declare const switchSmartLockNotification: (currentValue: number, mode: SmartLockNotification, enable: boolean) => number;
export declare const isSmartLockNotification: (value: number, mode: SmartLockNotification) => boolean;
export declare const getWaitSeconds: (device: Device) => number;
export declare const loadImageOverP2P: (station: Station, device: Device, id: string, p2pTimeouts: Map<string, NodeJS.Timeout>) => void;
export declare const loadEventImage: (station: Station, api: HTTPApi, device: Device, message: PushMessage, p2pTimeouts: Map<string, NodeJS.Timeout>) => void;

789
build/http/utils.js Normal file
View File

@ -0,0 +1,789 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadEventImage = exports.loadImageOverP2P = exports.getWaitSeconds = exports.isSmartLockNotification = exports.switchSmartLockNotification = exports.getLockEventType = exports.getFloodLightT8425Notification = exports.isFloodlightT8425NotitficationEnabled = exports.getIndoorNotification = exports.isIndoorNotitficationEnabled = exports.getIndoorS350DetectionMode = exports.isIndoorS350DetectionModeEnabled = exports.getT8170DetectionMode = exports.isT8170DetectionModeEnabled = exports.decryptTrackerData = exports.isPrioritySourceType = exports.getImage = exports.getImagePath = exports.decodeImage = exports.getImageKey = exports.getImageSeed = exports.getImageBaseCode = exports.getIdSuffix = exports.randomNumber = exports.hexStringScheduleToSchedule = exports.hexWeek = exports.hexTime = exports.hexDate = exports.encodePasscode = exports.ParsePayload = exports.WritePayload = exports.getAdvancedLockTimezone = exports.getEufyTimezone = exports.getHB3DetectionMode = exports.isHB3DetectionModeEnabled = exports.getDistances = exports.getBlocklist = exports.decryptAPIData = exports.encryptAPIData = exports.calculateCellularSignalLevel = exports.calculateWifiSignalLevel = exports.switchNotificationMode = exports.isNotificationSwitchMode = exports.getImageFilePath = exports.getAbsoluteFilePath = exports.getTimezoneGMTString = exports.pad = exports.isGreaterEqualMinVersion = void 0;
const crypto_1 = require("crypto");
const const_1 = require("./const");
const md5_1 = __importDefault(require("crypto-js/md5"));
const enc_hex_1 = __importDefault(require("crypto-js/enc-hex"));
const sha256_1 = __importDefault(require("crypto-js/sha256"));
const types_1 = require("./types");
const error_1 = require("../error");
const error_2 = require("./error");
const types_2 = require("./../push/types");
const logging_1 = require("../logging");
const utils_1 = require("../utils");
const normalizeVersionString = function (version) {
const trimmed = version ? version.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1") : "";
const pieces = trimmed.split(RegExp("\\."));
const parts = [];
let value, piece, num, i;
for (i = 0; i < pieces.length; i += 1) {
piece = pieces[i].replace(RegExp("\\D"), "");
num = parseInt(piece, 10);
if (isNaN(num)) {
num = 0;
}
parts.push(num);
}
const partsLength = parts.length;
for (i = partsLength - 1; i >= 0; i -= 1) {
value = parts[i];
if (value === 0) {
parts.length -= 1;
}
else {
break;
}
}
return parts;
};
const isGreaterEqualMinVersion = function (minimal_version, current_version) {
const x = normalizeVersionString(minimal_version);
const y = normalizeVersionString(current_version);
const size = Math.min(x.length, y.length);
let i;
for (i = 0; i < size; i += 1) {
if (x[i] !== y[i]) {
return x[i] < y[i] ? true : false;
}
}
if (x.length === y.length) {
return true;
}
return (x.length < y.length) ? true : false;
};
exports.isGreaterEqualMinVersion = isGreaterEqualMinVersion;
const pad = function (num) {
const norm = Math.floor(Math.abs(num));
return (norm < 10 ? "0" : "") + norm;
};
exports.pad = pad;
const getTimezoneGMTString = function () {
const tzo = -new Date().getTimezoneOffset();
const dif = tzo >= 0 ? "+" : "-";
return `GMT${dif}${(0, exports.pad)(tzo / 60)}:${(0, exports.pad)(tzo % 60)}`;
};
exports.getTimezoneGMTString = getTimezoneGMTString;
const getAbsoluteFilePath = function (device_type, channel, filename) {
if (device_type === types_1.DeviceType.FLOODLIGHT) {
return `/mnt/data/Camera${String(channel).padStart(2, "0")}/${filename}.dat`;
}
return `/media/mmcblk0p1/Camera${String(channel).padStart(2, "0")}/${filename}.dat`;
};
exports.getAbsoluteFilePath = getAbsoluteFilePath;
const getImageFilePath = function (device_type, channel, filename) {
if (device_type === types_1.DeviceType.FLOODLIGHT) {
return `/mnt/data/video/${filename}_c${String(channel).padStart(2, "0")}.jpg`;
}
return `/media/mmcblk0p1/video/${filename}_c${String(channel).padStart(2, "0")}.jpg`;
};
exports.getImageFilePath = getImageFilePath;
const isNotificationSwitchMode = function (value, mode) {
if (value === 1)
value = 240;
return (value & mode) !== 0;
};
exports.isNotificationSwitchMode = isNotificationSwitchMode;
const switchNotificationMode = function (currentValue, mode, enable) {
let result = 0;
if (!enable && currentValue === 1 /* ALL */) {
currentValue = 240;
}
if (enable) {
result = mode | currentValue;
}
else {
result = ~mode & currentValue;
}
if ((0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.SCHEDULE) && (0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.APP) && (0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.GEOFENCE) && (0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.KEYPAD)) {
result = 1; /* ALL */
}
return result;
};
exports.switchNotificationMode = switchNotificationMode;
const calculateWifiSignalLevel = function (device, rssi) {
if (device.isWiredDoorbell()) {
if (rssi >= -65) {
return types_1.SignalLevel.FULL;
}
if (rssi >= -75) {
return types_1.SignalLevel.STRONG;
}
return rssi >= -80 ? types_1.SignalLevel.NORMAL : types_1.SignalLevel.WEAK;
}
else if (device.isCamera2Product()) {
if (rssi >= 0) {
return types_1.SignalLevel.NO_SIGNAL;
}
if (rssi >= -65) {
return types_1.SignalLevel.FULL;
}
if (rssi >= -75) {
return types_1.SignalLevel.STRONG;
}
return rssi >= -85 ? types_1.SignalLevel.NORMAL : types_1.SignalLevel.WEAK;
}
else if (device.isFloodLight()) {
if (rssi >= 0) {
return types_1.SignalLevel.NO_SIGNAL;
}
if (rssi >= -60) {
return types_1.SignalLevel.FULL;
}
if (rssi >= -70) {
return types_1.SignalLevel.STRONG;
}
return rssi >= -80 ? types_1.SignalLevel.NORMAL : types_1.SignalLevel.WEAK;
}
else if (device.isBatteryDoorbell()) {
if (rssi >= -65) {
return types_1.SignalLevel.FULL;
}
if (rssi >= -75) {
return types_1.SignalLevel.STRONG;
}
return rssi >= -85 ? types_1.SignalLevel.NORMAL : types_1.SignalLevel.WEAK;
}
else {
if (rssi >= 0) {
return types_1.SignalLevel.NO_SIGNAL;
}
if (rssi >= -65) {
return types_1.SignalLevel.FULL;
}
if (rssi >= -75) {
return types_1.SignalLevel.STRONG;
}
return rssi >= -85 ? types_1.SignalLevel.NORMAL : types_1.SignalLevel.WEAK;
}
};
exports.calculateWifiSignalLevel = calculateWifiSignalLevel;
const calculateCellularSignalLevel = function (rssi) {
if (rssi >= 0) {
return types_1.SignalLevel.NO_SIGNAL;
}
if (rssi >= -90) {
return types_1.SignalLevel.FULL;
}
if (rssi >= -95) {
return types_1.SignalLevel.STRONG;
}
return rssi >= -105 ? types_1.SignalLevel.NORMAL : types_1.SignalLevel.WEAK;
};
exports.calculateCellularSignalLevel = calculateCellularSignalLevel;
const encryptAPIData = (data, key) => {
const cipher = (0, crypto_1.createCipheriv)("aes-256-cbc", key, key.subarray(0, 16));
return (cipher.update(data, "utf8", "base64") +
cipher.final("base64"));
};
exports.encryptAPIData = encryptAPIData;
const decryptAPIData = (data, key) => {
const cipher = (0, crypto_1.createDecipheriv)("aes-256-cbc", key, key.subarray(0, 16));
return Buffer.concat([
cipher.update(data, "base64"),
cipher.final()
]);
};
exports.decryptAPIData = decryptAPIData;
const getBlocklist = function (directions) {
const result = [];
for (let distance = 1; distance <= 5; distance++) {
let i = 0;
let j = 0;
let k = 1;
for (const directionDistance of directions) {
if (directionDistance >= distance) {
j += k;
}
k <<= 1;
}
if (j == 0) {
i = 65535;
}
else if (!(j == 255 || j == 65535)) {
i = (j ^ 255) + 65280;
}
result.push(65535 & i);
}
return result;
};
exports.getBlocklist = getBlocklist;
const getDistances = function (blocklist) {
const result = [3, 3, 3, 3, 3, 3, 3, 3];
let calcDistance = 0;
for (const blockElement of blocklist) {
let valueOf = blockElement ^ 65535;
calcDistance++;
if (valueOf !== 0) {
for (let i = 0; i < result.length; i++) {
const intValue = valueOf & 1;
if (intValue > 0) {
result[i] = calcDistance;
}
valueOf = valueOf >> 1;
}
}
}
return result;
};
exports.getDistances = getDistances;
const isHB3DetectionModeEnabled = function (value, type) {
if (type === types_1.HB3DetectionTypes.HUMAN_RECOGNITION) {
return (type & value) == type && (value & 65536) == 65536;
}
else if (type === types_1.HB3DetectionTypes.HUMAN_DETECTION) {
return (type & value) == type && (value & 1) == 1;
}
return (type & value) == type;
};
exports.isHB3DetectionModeEnabled = isHB3DetectionModeEnabled;
const getHB3DetectionMode = function (value, type, enable) {
let result = 0;
if (!enable) {
if (type === types_1.HB3DetectionTypes.HUMAN_RECOGNITION) {
const tmp = (type & value) == type ? type ^ value : value;
result = (value & 65536) == 65536 ? tmp ^ 65536 : tmp;
}
else if (type === types_1.HB3DetectionTypes.HUMAN_DETECTION) {
const tmp = (type & value) == type ? type ^ value : value;
result = (value & 1) == 1 ? tmp ^ 1 : tmp;
}
else {
result = type ^ value;
}
}
else {
if (type === types_1.HB3DetectionTypes.HUMAN_RECOGNITION) {
result = type | value | 65536;
}
else if (type === types_1.HB3DetectionTypes.HUMAN_DETECTION) {
result = type | value | 1;
}
else {
result = type | value;
}
}
return result;
};
exports.getHB3DetectionMode = getHB3DetectionMode;
const getEufyTimezone = function () {
for (const timezone of const_1.timeZoneData) {
if (timezone.timeId === Intl.DateTimeFormat().resolvedOptions().timeZone) {
return timezone;
}
}
return undefined;
};
exports.getEufyTimezone = getEufyTimezone;
const getAdvancedLockTimezone = function (stationSN) {
const timezone = (0, exports.getEufyTimezone)();
if (timezone !== undefined) {
if (stationSN.startsWith("T8520") && (0, exports.isGreaterEqualMinVersion)("1.2.8.6", stationSN))
return `${timezone.timeZoneGMT}|1.${timezone.timeSn}`;
else
return timezone.timeZoneGMT;
}
return "";
};
exports.getAdvancedLockTimezone = getAdvancedLockTimezone;
class WritePayload {
split_byte = -95;
data = Buffer.from([]);
write(bytes) {
const tmp_data = Buffer.from(bytes);
this.data = Buffer.concat([this.data, Buffer.from([this.split_byte]), Buffer.from([tmp_data.length & 255]), tmp_data]);
this.split_byte += 1;
}
getData() {
return this.data;
}
}
exports.WritePayload = WritePayload;
class ParsePayload {
data;
constructor(data) {
this.data = data;
}
readUint32BE(indexValue) {
return this.readData(indexValue).readUint32BE();
}
readUint32LE(indexValue) {
return this.readData(indexValue).readUint32LE();
}
readUint16BE(indexValue) {
return this.readData(indexValue).readUint16BE();
}
readUint16LE(indexValue) {
return this.readData(indexValue).readUint16LE();
}
readString(indexValue) {
return this.readData(indexValue).toString();
}
readStringHex(indexValue) {
return this.readData(indexValue).toString("hex");
}
readInt8(indexValue) {
let dataPosition = this.getDataPosition(indexValue);
if (dataPosition == -1) {
return 0;
}
dataPosition = dataPosition + 2;
if (dataPosition >= this.data.length) {
return 0;
}
return this.data.readInt8(dataPosition);
}
readData(indexValue) {
let dataPosition = this.getDataPosition(indexValue);
if (dataPosition == -1) {
return Buffer.from("");
}
dataPosition++;
if (dataPosition >= this.data.length) {
return Buffer.from("");
}
const nextStep = this.getNextStep(indexValue, dataPosition, this.data);
let tmp;
if (nextStep == 1) {
tmp = this.data.readInt8(dataPosition);
}
else {
tmp = this.data.readUint16LE(dataPosition);
}
if (dataPosition + nextStep + tmp > this.data.length) {
return Buffer.from("");
}
return this.data.subarray(dataPosition + nextStep, dataPosition + nextStep + tmp);
}
getDataPosition(indexValue) {
if (this.data && this.data.length >= 1) {
for (let currentPosition = 0; currentPosition < this.data.length;) {
if (this.data.readInt8(currentPosition) == indexValue) {
return currentPosition;
}
else {
const value = this.data.readInt8(currentPosition);
currentPosition++;
if (currentPosition >= this.data.length) {
break;
}
const nextStep = this.getNextStep(value, currentPosition, this.data);
if ((currentPosition + nextStep) >= this.data.length) {
break;
}
if (nextStep == 1) {
currentPosition = this.data.readInt8(currentPosition) + currentPosition + nextStep;
}
else {
currentPosition = this.data.readUint16LE(currentPosition) + currentPosition + nextStep;
}
}
}
}
return -1;
}
getNextStep(indexValue, position, data) {
const newPosition = position + 1 + data.readUInt8(position);
return (newPosition == data.length || newPosition > data.length || data.readInt8(newPosition) == indexValue + 1) ? 1 : 2;
}
}
exports.ParsePayload = ParsePayload;
/*export const generateHash = function(data: Buffer): number {
let result = 0;
for (const value of data) {
result = result ^ value;
}
return result;
}
export const encodeSmartSafeData = function(command: number, payload: Buffer): Buffer {
const header = Buffer.from(SmartSafe.DATA_HEADER);
const size = Buffer.allocUnsafe(2);
size.writeInt16LE(payload.length + 9);
const versionCode = Buffer.from([SmartSafe.VERSION_CODE]);
const dataType = Buffer.from([-1]);
const commandCode = Buffer.from([command]);
const packageFlag = Buffer.from([-64]);
const data = Buffer.concat([header, size, versionCode, dataType, commandCode, packageFlag, payload]);
const hash = generateHash(data);
return Buffer.concat([data, Buffer.from([hash])]);
}*/
const encodePasscode = function (pass) {
let result = "";
for (let i = 0; i < pass.length; i++)
result += pass.charCodeAt(i).toString(16);
return result;
};
exports.encodePasscode = encodePasscode;
const hexDate = function (date) {
const buf = Buffer.allocUnsafe(4);
buf.writeUint8(date.getDate());
buf.writeUint8(date.getMonth() + 1, 1);
buf.writeUint16BE(date.getFullYear(), 2);
return buf.readUInt32LE().toString(16).padStart(8, "0");
};
exports.hexDate = hexDate;
const hexTime = function (date) {
const buf = Buffer.allocUnsafe(2);
buf.writeUint8(date.getHours());
buf.writeUint8(date.getMinutes(), 1);
return buf.readUInt16BE().toString(16).padStart(4, "0");
};
exports.hexTime = hexTime;
const hexWeek = function (schedule) {
const SUNDAY = 1;
const MONDAY = 2;
const TUESDAY = 4;
const WEDNESDAY = 8;
const THUERSDAY = 16;
const FRIDAY = 32;
const SATURDAY = 64;
let result = 0;
if (schedule.week !== undefined) {
if (schedule.week.sunday) {
result |= SUNDAY;
}
if (schedule.week.monday) {
result |= MONDAY;
}
if (schedule.week.tuesday) {
result |= TUESDAY;
}
if (schedule.week.wednesday) {
result |= WEDNESDAY;
}
if (schedule.week.thursday) {
result |= THUERSDAY;
}
if (schedule.week.friday) {
result |= FRIDAY;
}
if (schedule.week.saturday) {
result |= SATURDAY;
}
return result.toString(16);
}
return "ff";
};
exports.hexWeek = hexWeek;
const hexStringScheduleToSchedule = function (startDay, startTime, endDay, endTime, week) {
const SUNDAY = 1;
const MONDAY = 2;
const TUESDAY = 4;
const WEDNESDAY = 8;
const THUERSDAY = 16;
const FRIDAY = 32;
const SATURDAY = 64;
const weekNumber = Number.parseInt(week, 16);
return {
startDateTime: startDay === "00000000" ? undefined : new Date(Number.parseInt(`${startDay.substring(2, 4)}${startDay.substring(0, 2)}`, 16), Number.parseInt(startDay.substring(4, 6), 16) - 1, Number.parseInt(startDay.substring(6, 8), 16), Number.parseInt(startTime.substring(0, 2), 16), Number.parseInt(startTime.substring(2, 4), 16)),
endDateTime: endDay === "ffffffff" ? undefined : new Date(Number.parseInt(`${endDay.substring(2, 4)}${endDay.substring(0, 2)}`, 16), Number.parseInt(endDay.substring(4, 6), 16) - 1, Number.parseInt(endDay.substring(6, 8), 16), Number.parseInt(endTime.substring(0, 2), 16), Number.parseInt(endTime.substring(2, 4), 16)),
week: {
monday: (weekNumber & MONDAY) == MONDAY,
tuesday: (weekNumber & TUESDAY) == TUESDAY,
wednesday: (weekNumber & WEDNESDAY) == WEDNESDAY,
thursday: (weekNumber & THUERSDAY) == THUERSDAY,
friday: (weekNumber & FRIDAY) == FRIDAY,
saturday: (weekNumber & SATURDAY) == SATURDAY,
sunday: (weekNumber & SUNDAY) == SUNDAY,
},
};
};
exports.hexStringScheduleToSchedule = hexStringScheduleToSchedule;
const randomNumber = function (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
exports.randomNumber = randomNumber;
const getIdSuffix = function (p2pDid) {
let result = 0;
const match = p2pDid.match(/^[A-Z]+-(\d+)-[A-Z]+$/);
if (match?.length == 2) {
const num1 = Number.parseInt(match[1][0]);
const num2 = Number.parseInt(match[1][1]);
const num3 = Number.parseInt(match[1][3]);
const num4 = Number.parseInt(match[1][5]);
result = num1 + num2 + num3;
if (num3 < 5) {
result = result + num3;
}
result = result + num4;
}
return result;
};
exports.getIdSuffix = getIdSuffix;
const getImageBaseCode = function (serialnumber, p2pDid) {
let nr = 0;
try {
nr = Number.parseInt(`0x${serialnumber[serialnumber.length - 1]}`);
}
catch (err) {
const error = (0, error_1.ensureError)(err);
throw new error_2.ImageBaseCodeError("Error generating image base code", { cause: error, context: { serialnumber: serialnumber, p2pDid: p2pDid } });
}
nr = (nr + 10) % 10;
const base = serialnumber.substring(nr);
return `${base}${(0, exports.getIdSuffix)(p2pDid)}`;
};
exports.getImageBaseCode = getImageBaseCode;
const getImageSeed = function (p2pDid, code) {
try {
const ncode = Number.parseInt(code.substring(2));
const prefix = 1000 - (0, exports.getIdSuffix)(p2pDid);
return (0, md5_1.default)(`${prefix}${ncode}`).toString(enc_hex_1.default).toUpperCase();
}
catch (err) {
const error = (0, error_1.ensureError)(err);
throw new error_2.ImageBaseCodeError("Error generating image seed", { cause: error, context: { p2pDid: p2pDid, code: code } });
}
};
exports.getImageSeed = getImageSeed;
const getImageKey = function (serialnumber, p2pDid, code) {
const basecode = (0, exports.getImageBaseCode)(serialnumber, p2pDid);
const seed = (0, exports.getImageSeed)(p2pDid, code);
const data = `01${basecode}${seed}`;
const hash = (0, sha256_1.default)(data);
const hashBytes = [...Buffer.from(hash.toString(enc_hex_1.default), "hex")];
const startByte = hashBytes[10];
for (let i = 0; i < 32; i++) {
const byte = hashBytes[i];
let fixed_byte = startByte;
if (i < 31) {
fixed_byte = hashBytes[i + 1];
}
if ((i == 31) || ((i & 1) != 0)) {
hashBytes[10] = fixed_byte;
if ((126 < byte) || (126 < hashBytes[10])) {
if (byte < hashBytes[10] || (byte - hashBytes[10]) == 0) {
hashBytes[i] = hashBytes[10] - byte;
}
else {
hashBytes[i] = byte - hashBytes[10];
}
}
}
else if ((byte < 125) || (fixed_byte < 125)) {
hashBytes[i] = fixed_byte + byte;
}
}
return `${Buffer.from(hashBytes.slice(16)).toString("hex").toUpperCase()}`;
};
exports.getImageKey = getImageKey;
const decodeImage = function (p2pDid, data) {
if (data.length >= 12) {
const header = data.subarray(0, 12).toString();
if (header === "eufysecurity") {
const serialnumber = data.subarray(13, 29).toString();
const code = data.subarray(30, 40).toString();
const imageKey = (0, exports.getImageKey)(serialnumber, p2pDid, code);
const otherData = data.subarray(41);
const encryptedData = otherData.subarray(0, 256);
const cipher = (0, crypto_1.createDecipheriv)("aes-128-ecb", Buffer.from(imageKey, "utf-8").subarray(0, 16), null);
cipher.setAutoPadding(false);
const decryptedData = Buffer.concat([
cipher.update(encryptedData),
cipher.final()
]);
decryptedData.copy(otherData);
return otherData;
}
}
return data;
};
exports.decodeImage = decodeImage;
const getImagePath = function (path) {
const splittedPath = path.split("~");
if (splittedPath.length === 2) {
return splittedPath[1];
}
return path;
};
exports.getImagePath = getImagePath;
const getImage = async function (api, serial, url) {
const { default: imageType } = await import("image-type");
const image = await api.getImage(serial, url);
const type = await imageType(image);
return {
data: image,
type: type !== null && type !== undefined ? type : { ext: "unknown", mime: "application/octet-stream" }
};
};
exports.getImage = getImage;
const isPrioritySourceType = function (current, update) {
if (((current === "http" || current === "p2p" || current === "push" || current === "mqtt" || current === undefined) && (update === "p2p" || update === "push" || update === "mqtt")) ||
((current === "http" || current === undefined) && update === "http")) {
return true;
}
return false;
};
exports.isPrioritySourceType = isPrioritySourceType;
const decryptTrackerData = (data, key) => {
const decipher = (0, crypto_1.createDecipheriv)("aes-128-ecb", key, null);
decipher.setAutoPadding(false);
return Buffer.concat([
decipher.update(data),
decipher.final()
]);
};
exports.decryptTrackerData = decryptTrackerData;
const isT8170DetectionModeEnabled = function (value, type) {
return (type & value) == type;
};
exports.isT8170DetectionModeEnabled = isT8170DetectionModeEnabled;
const getT8170DetectionMode = function (value, type, enable) {
let result = 0;
if ((Object.values(types_1.T8170DetectionTypes).includes(type) && Object.values(types_1.T8170DetectionTypes).includes(value)) && !enable)
return value;
if (!enable) {
result = type ^ value;
}
else {
result = type | value;
}
return result;
};
exports.getT8170DetectionMode = getT8170DetectionMode;
const isIndoorS350DetectionModeEnabled = function (value, type) {
return (type & value) == type;
};
exports.isIndoorS350DetectionModeEnabled = isIndoorS350DetectionModeEnabled;
const getIndoorS350DetectionMode = function (value, type, enable) {
let result = 0;
if ((Object.values(types_1.IndoorS350DetectionTypes).includes(type) && Object.values(types_1.IndoorS350DetectionTypes).includes(value)) && !enable)
return value;
if (!enable) {
result = type ^ value;
}
else {
result = type | value;
}
return result;
};
exports.getIndoorS350DetectionMode = getIndoorS350DetectionMode;
const isIndoorNotitficationEnabled = function (value, type) {
return (type & value) == type;
};
exports.isIndoorNotitficationEnabled = isIndoorNotitficationEnabled;
const getIndoorNotification = function (value, type, enable) {
let result = 0;
if (!enable) {
result = (type ^ value) + 800;
}
else {
result = type | value;
}
return result;
};
exports.getIndoorNotification = getIndoorNotification;
const isFloodlightT8425NotitficationEnabled = function (value, type) {
return (type & value) == type;
};
exports.isFloodlightT8425NotitficationEnabled = isFloodlightT8425NotitficationEnabled;
const getFloodLightT8425Notification = function (value, type, enable) {
let result = 0;
if (!enable) {
result = (type ^ value);
}
else {
result = type | value;
}
return result;
};
exports.getFloodLightT8425Notification = getFloodLightT8425Notification;
const getLockEventType = function (event) {
switch (event) {
case types_2.LockPushEvent.AUTO_LOCK:
case types_2.LockPushEvent.AUTO_UNLOCK:
return 1;
case types_2.LockPushEvent.MANUAL_LOCK:
case types_2.LockPushEvent.MANUAL_UNLOCK:
return 2;
case types_2.LockPushEvent.APP_LOCK:
case types_2.LockPushEvent.APP_UNLOCK:
return 3;
case types_2.LockPushEvent.PW_LOCK:
case types_2.LockPushEvent.PW_UNLOCK:
return 4;
case types_2.LockPushEvent.FINGER_LOCK:
case types_2.LockPushEvent.FINGERPRINT_UNLOCK:
return 5;
case types_2.LockPushEvent.TEMPORARY_PW_LOCK:
case types_2.LockPushEvent.TEMPORARY_PW_UNLOCK:
return 6;
case types_2.LockPushEvent.KEYPAD_LOCK:
return 7;
}
return 0;
};
exports.getLockEventType = getLockEventType;
const switchSmartLockNotification = function (currentValue, mode, enable) {
let result = 0;
if (enable) {
result = mode | currentValue;
}
else {
result = ~mode & currentValue;
}
return result;
};
exports.switchSmartLockNotification = switchSmartLockNotification;
const isSmartLockNotification = function (value, mode) {
return (value & mode) !== 0;
};
exports.isSmartLockNotification = isSmartLockNotification;
const getWaitSeconds = (device) => {
let seconds = 60;
const workingMode = device.getPropertyValue(types_1.PropertyName.DevicePowerWorkingMode);
if (workingMode !== undefined && workingMode === 2) {
const customValue = device.getPropertyValue(types_1.PropertyName.DeviceRecordingClipLength);
if (customValue !== undefined) {
seconds = customValue;
}
}
return seconds;
};
exports.getWaitSeconds = getWaitSeconds;
const loadImageOverP2P = function (station, device, id, p2pTimeouts) {
if (station.hasCommand(types_1.CommandName.StationDatabaseQueryLatestInfo) && p2pTimeouts.get(id) === undefined) {
const seconds = (0, exports.getWaitSeconds)(device);
p2pTimeouts.set(id, setTimeout(async () => {
station.databaseQueryLatestInfo();
p2pTimeouts.delete(id);
}, seconds * 1000));
}
};
exports.loadImageOverP2P = loadImageOverP2P;
const loadEventImage = function (station, api, device, message, p2pTimeouts) {
if (message.notification_style === types_1.NotificationType.MOST_EFFICIENT) {
(0, exports.loadImageOverP2P)(station, device, device.getSerial(), p2pTimeouts);
}
else {
if (!(0, utils_1.isEmpty)(message.pic_url)) {
(0, exports.getImage)(api, device.getSerial(), message.pic_url).then((image) => {
if (image.data.length > 0) {
if (p2pTimeouts.get(device.getSerial()) !== undefined) {
clearTimeout(p2pTimeouts.get(device.getSerial()));
p2pTimeouts.delete(device.getSerial());
}
device.updateProperty(types_1.PropertyName.DevicePicture, image, true);
}
else {
//fallback
(0, exports.loadImageOverP2P)(station, device, device.getSerial(), p2pTimeouts);
}
}).catch((err) => {
const error = (0, error_1.ensureError)(err);
logging_1.rootHTTPLogger.debug(`Device load event image - Fallback Error`, { error: (0, utils_1.getError)(error), stationSN: station.getSerial(), deviceSN: device.getSerial(), message: JSON.stringify(message) });
(0, exports.loadImageOverP2P)(station, device, device.getSerial(), p2pTimeouts);
});
}
else {
//fallback
(0, exports.loadImageOverP2P)(station, device, device.getSerial(), p2pTimeouts);
}
}
};
exports.loadEventImage = loadEventImage;
//# sourceMappingURL=utils.js.map

1
build/http/utils.js.map Normal file

File diff suppressed because one or more lines are too long

8
build/index.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
export * from "./http";
export * from "./p2p";
export * from "./push";
export * from "./interfaces";
export * from "./eufysecurity";
export * from "./error";
export { LoggingCategories, LogLevel, Logger, dummyLogger } from "./logging";
export declare const libVersion: string;

29
build/index.js Normal file
View File

@ -0,0 +1,29 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.libVersion = exports.dummyLogger = exports.LogLevel = void 0;
__exportStar(require("./http"), exports);
__exportStar(require("./p2p"), exports);
__exportStar(require("./push"), exports);
__exportStar(require("./interfaces"), exports);
__exportStar(require("./eufysecurity"), exports);
__exportStar(require("./error"), exports);
var logging_1 = require("./logging");
Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return logging_1.LogLevel; } });
Object.defineProperty(exports, "dummyLogger", { enumerable: true, get: function () { return logging_1.dummyLogger; } });
// eslint-disable-next-line @typescript-eslint/no-var-requires
exports.libVersion = require("../package.json").version;
//# sourceMappingURL=index.js.map

1
build/index.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,yCAAuB;AACvB,wCAAsB;AACtB,yCAAuB;AACvB,+CAA6B;AAC7B,iDAA+B;AAC/B,0CAAwB;AACxB,qCAA6E;AAAjD,mGAAA,QAAQ,OAAA;AAAU,sGAAA,WAAW,OAAA;AAEzD,8DAA8D;AACjD,QAAA,UAAU,GAAW,OAAO,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC"}

142
build/interfaces.d.ts vendored Normal file
View File

@ -0,0 +1,142 @@
import { Readable } from "stream";
import { Device } from "./http/device";
import { HTTPApiPersistentData, Picture, PropertyValue, Schedule } from "./http/interfaces";
import { Station } from "./http/station";
import { DeviceSmartLockMessage } from "./mqtt/model";
import { DatabaseCountByDate, DatabaseQueryLatestInfo, DatabaseQueryLocal, StreamMetadata } from "./p2p/interfaces";
import { CommandResult } from "./p2p/models";
import { TalkbackStream } from "./p2p/talkback";
import { AlarmEvent, DatabaseReturnCode, SmartSafeAlarm911Event, SmartSafeShakeAlarmEvent } from "./p2p/types";
import { Credentials, PushMessage } from "./push/models";
import { Jsonable, LoggingCategories } from ".";
import { LogLevel } from "typescript-logging";
export interface StationIPAddresses {
[index: string]: string;
}
export interface EufySecurityConfig {
username: string;
password: string;
country?: string;
language?: string;
trustedDeviceName?: string;
persistentDir?: string;
persistentData?: string;
p2pConnectionSetup: number;
pollingIntervalMinutes: number;
eventDurationSeconds: number;
acceptInvitations?: boolean;
stationIPAddresses?: StationIPAddresses;
enableEmbeddedPKCS1Support?: boolean;
deviceConfig?: {
simultaneousDetections?: boolean;
};
logging?: {
level?: LogLevel;
categories?: Array<{
category: LoggingCategories;
level: LogLevel;
}>;
};
}
export interface EufySecurityPersistentData {
country: string;
login_hash: string;
openudid: string;
serial_number: string;
cloud_token?: string;
cloud_token_expiration?: number;
push_credentials: Credentials | undefined;
push_persistentIds: string[];
version: string;
httpApi?: HTTPApiPersistentData;
fallbackTrustedDeviceName?: string;
}
export interface EufySecurityEvents {
"device added": (device: Device) => void;
"device removed": (device: Device) => void;
"device property changed": (device: Device, name: string, value: PropertyValue) => void;
"device raw property changed": (device: Device, type: number, value: string) => void;
"device crying detected": (device: Device, state: boolean) => void;
"device sound detected": (device: Device, state: boolean) => void;
"device pet detected": (device: Device, state: boolean) => void;
"device vehicle detected": (device: Device, state: boolean) => void;
"device motion detected": (device: Device, state: boolean) => void;
"device person detected": (device: Device, state: boolean, person: string) => void;
"device stranger person detected": (device: Device, state: boolean) => void;
"device dog detected": (device: Device, state: boolean) => void;
"device dog lick detected": (device: Device, state: boolean) => void;
"device dog poop detected": (device: Device, state: boolean) => void;
"device rings": (device: Device, state: boolean) => void;
"device locked": (device: Device, state: boolean) => void;
"device open": (device: Device, state: boolean) => void;
"device package delivered": (device: Device, state: boolean) => void;
"device package stranded": (device: Device, state: boolean) => void;
"device package taken": (device: Device, state: boolean) => void;
"device someone loitering": (device: Device, state: boolean) => void;
"device radar motion detected": (device: Device, state: boolean) => void;
"device 911 alarm": (device: Device, state: boolean, detail: SmartSafeAlarm911Event) => void;
"device shake alarm": (device: Device, state: boolean, detail: SmartSafeShakeAlarmEvent) => void;
"device wrong try-protect alarm": (device: Device, state: boolean) => void;
"device long time not close": (device: Device, state: boolean) => void;
"device low battery": (device: Device, state: boolean) => void;
"device jammed": (device: Device, state: boolean) => void;
"device pin verified": (device: Device, successfull: boolean) => void;
"device tampering": (device: Device, state: boolean) => void;
"device low temperature": (device: Device, state: boolean) => void;
"device high temperature": (device: Device, state: boolean) => void;
"device pin incorrect": (device: Device, state: boolean) => void;
"device lid stuck": (device: Device, state: boolean) => void;
"device battery fully charged": (device: Device, state: boolean) => void;
"station added": (station: Station) => void;
"station removed": (station: Station) => void;
"station livestream start": (station: Station, device: Device, metadata: StreamMetadata, videostream: Readable, audiostream: Readable) => void;
"station livestream stop": (station: Station, device: Device) => void;
"station download start": (station: Station, device: Device, metadata: StreamMetadata, videoStream: Readable, audioStream: Readable) => void;
"station download finish": (station: Station, device: Device) => void;
"station command result": (station: Station, result: CommandResult) => void;
"station rtsp livestream start": (station: Station, device: Device) => void;
"station rtsp livestream stop": (station: Station, device: Device) => void;
"station rtsp url": (station: Station, device: Device, value: string) => void;
"station guard mode": (station: Station, guardMode: number) => void;
"station current mode": (station: Station, currentMode: number) => void;
"station property changed": (station: Station, name: string, value: PropertyValue) => void;
"station raw property changed": (station: Station, type: number, value: string) => void;
"station alarm event": (station: Station, alarmEvent: AlarmEvent) => void;
"station alarm delay event": (station: Station, alarmDelayEvent: AlarmEvent, alarmDelay: number) => void;
"station alarm armed": (station: Station) => void;
"station alarm arm delay event": (station: Station, armDelay: number) => void;
"station connect": (station: Station) => void;
"station connection error": (station: Station, error: Error) => void;
"station close": (station: Station) => void;
"station talkback start": (station: Station, device: Device, talkbackStream: TalkbackStream) => void;
"station talkback stop": (station: Station, device: Device) => void;
"station image download": (station: Station, file: string, image: Picture) => void;
"station database query latest": (station: Station, returnCode: DatabaseReturnCode, data: Array<DatabaseQueryLatestInfo>) => void;
"station database query local": (station: Station, returnCode: DatabaseReturnCode, data: Array<DatabaseQueryLocal>) => void;
"station database count by date": (station: Station, returnCode: DatabaseReturnCode, data: Array<DatabaseCountByDate>) => void;
"station database delete": (station: Station, returnCode: DatabaseReturnCode, failedIds: Array<unknown>) => void;
"push connect": () => void;
"push close": () => void;
"push message": (message: PushMessage) => void;
"connect": () => void;
"close": () => void;
"connection error": (error: Error) => void;
"tfa request": () => void;
"captcha request": (id: string, captcha: string) => void;
"persistent data": (data: string) => void;
"mqtt connect": () => void;
"mqtt close": () => void;
"mqtt lock message": (message: DeviceSmartLockMessage) => void;
"user added": (device: Device, username: string, schedule?: Schedule) => void;
"user deleted": (device: Device, username: string) => void;
"user error": (device: Device, username: string, error: Error) => void;
"user username updated": (device: Device, username: string) => void;
"user schedule updated": (device: Device, username: string, schedule: Schedule) => void;
"user passcode updated": (device: Device, username: string) => void;
}
export interface ErrorObject {
cause: unknown;
message: string;
context: Jsonable;
stacktrace?: string;
}

3
build/interfaces.js Normal file
View File

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=interfaces.js.map

1
build/interfaces.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":""}

22
build/logging.d.ts vendored Normal file
View File

@ -0,0 +1,22 @@
import { LogLevel } from "typescript-logging";
export type LoggingCategories = "all" | "main" | "http" | "p2p" | "push" | "mqtt";
export { LogLevel };
export interface Logger {
trace(message: unknown, ...args: unknown[]): void;
debug(message: unknown, ...args: unknown[]): void;
info(message: unknown, ...args: unknown[]): void;
warn(message: unknown, ...args: unknown[]): void;
error(message: unknown, ...args: unknown[]): void;
fatal?(message: unknown, ...args: unknown[]): void;
}
export declare const dummyLogger: Logger;
export declare class InternalLogger {
static logger: Logger | undefined;
}
export declare const rootMainLogger: import("typescript-logging-category-style").Category;
export declare const rootHTTPLogger: import("typescript-logging-category-style").Category;
export declare const rootMQTTLogger: import("typescript-logging-category-style").Category;
export declare const rootPushLogger: import("typescript-logging-category-style").Category;
export declare const rootP2PLogger: import("typescript-logging-category-style").Category;
export declare const setLoggingLevel: (category?: LoggingCategories, level?: LogLevel) => void;
export declare const getLoggingLevel: (category?: LoggingCategories) => number;

116
build/logging.js Normal file
View File

@ -0,0 +1,116 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLoggingLevel = exports.setLoggingLevel = exports.rootP2PLogger = exports.rootPushLogger = exports.rootMQTTLogger = exports.rootHTTPLogger = exports.rootMainLogger = exports.InternalLogger = exports.LogLevel = void 0;
const typescript_logging_1 = require("typescript-logging");
Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return typescript_logging_1.LogLevel; } });
const typescript_logging_category_style_1 = require("typescript-logging-category-style");
class InternalLogger {
static logger;
}
exports.InternalLogger = InternalLogger;
const getMethodName = function () {
const matches = new Error("").stack?.split("\n")[6].match(/ at( new){0,1} ([a-zA-Z0-9_\.]+) /);
if (matches !== null && matches !== undefined && matches[2] !== undefined && matches[2] !== "eval") {
return matches[2];
}
return undefined;
};
const provider = typescript_logging_category_style_1.CategoryProvider.createProvider("EufySecurityClientProvider", {
level: typescript_logging_1.LogLevel.Off,
channel: {
type: "RawLogChannel",
write: (msg, _formatArg) => {
const methodName = getMethodName();
const method = methodName ? `[${methodName}] ` : "";
switch (msg.level) {
case typescript_logging_1.LogLevel.Trace:
if (msg.args)
InternalLogger.logger?.trace(`[${msg.logNames}] ${method}${msg.message}`, ...msg.args);
else
InternalLogger.logger?.trace(`[${msg.logNames}] ${method}${msg.message}`);
break;
case typescript_logging_1.LogLevel.Debug:
if (msg.args)
InternalLogger.logger?.debug(`[${msg.logNames}] ${method}${msg.message}`, ...msg.args);
else
InternalLogger.logger?.debug(`[${msg.logNames}] ${method}${msg.message}`);
break;
case typescript_logging_1.LogLevel.Info:
if (msg.args)
InternalLogger.logger?.info(`[${msg.logNames}] ${method}${msg.message}`, ...msg.args);
else
InternalLogger.logger?.info(`[${msg.logNames}] ${method}${msg.message}`);
break;
case typescript_logging_1.LogLevel.Warn:
if (msg.args)
InternalLogger.logger?.warn(`[${msg.logNames}] ${method}${msg.message}`, ...msg.args);
else
InternalLogger.logger?.warn(`[${msg.logNames}] ${method}${msg.message}`);
break;
case typescript_logging_1.LogLevel.Error:
if (msg.args)
InternalLogger.logger?.error(`[${msg.logNames}] ${method}${msg.message}`, ...msg.args);
else
InternalLogger.logger?.error(`[${msg.logNames}] ${method}${msg.message}`);
break;
case typescript_logging_1.LogLevel.Fatal:
if (InternalLogger.logger && InternalLogger.logger.fatal)
if (msg.args)
InternalLogger.logger.fatal(`[${msg.logNames}] ${method}${msg.message}`, ...msg.args);
else
InternalLogger.logger.fatal(`[${msg.logNames}] ${method}${msg.message}`);
break;
}
},
},
});
exports.rootMainLogger = provider.getCategory("main");
exports.rootHTTPLogger = provider.getCategory("http");
exports.rootMQTTLogger = provider.getCategory("mqtt");
exports.rootPushLogger = provider.getCategory("push");
exports.rootP2PLogger = provider.getCategory("p2p");
const setLoggingLevel = function (category = "all", level = typescript_logging_1.LogLevel.Off) {
switch (category) {
case "all":
provider.updateRuntimeSettings({
level: level
});
break;
case "main":
provider.updateRuntimeSettingsCategory(exports.rootMainLogger, {
level: level
});
break;
case "http":
provider.updateRuntimeSettingsCategory(exports.rootHTTPLogger, {
level: level
});
break;
case "mqtt":
provider.updateRuntimeSettingsCategory(exports.rootMQTTLogger, {
level: level
});
break;
case "p2p":
provider.updateRuntimeSettingsCategory(exports.rootP2PLogger, {
level: level
});
break;
case "push":
provider.updateRuntimeSettingsCategory(exports.rootPushLogger, {
level: level
});
break;
}
};
exports.setLoggingLevel = setLoggingLevel;
const getLoggingLevel = function (category = "all") {
switch (category) {
case "all":
return provider.runtimeConfig.level;
default:
return provider.getCategory(category).logLevel;
}
};
exports.getLoggingLevel = getLoggingLevel;
//# sourceMappingURL=logging.js.map

1
build/logging.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"logging.js","sourceRoot":"","sources":["../src/logging.ts"],"names":[],"mappings":";;;AAAA,2DAA8C;AAKrC,yFALA,6BAAQ,OAKA;AAJjB,yFAAqE;AAiBrE,MAAa,cAAc;IAEhB,MAAM,CAAC,MAAM,CAAqB;CAE5C;AAJD,wCAIC;AAED,MAAM,aAAa,GAAG;IAClB,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAC/F,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;QACjG,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,SAAS,CAAC;AACrB,CAAC,CAAA;AAED,MAAM,QAAQ,GAAG,oDAAgB,CAAC,cAAc,CAAC,4BAA4B,EAAE;IAC3E,KAAK,EAAE,6BAAQ,CAAC,GAAG;IACnB,OAAO,EAAE;QACL,IAAI,EAAE,eAAe;QACrB,KAAK,EAAE,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE;YACvB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YACpD,QAAO,GAAG,CAAC,KAAK,EAAE,CAAC;gBACf,KAAK,6BAAQ,CAAC,KAAK;oBACf,IAAI,GAAG,CAAC,IAAI;wBACR,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;;wBAEvF,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;oBAC9E,MAAM;gBACV,KAAK,6BAAQ,CAAC,KAAK;oBACf,IAAI,GAAG,CAAC,IAAI;wBACR,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;;wBAEvF,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;oBAC9E,MAAM;gBACV,KAAK,6BAAQ,CAAC,IAAI;oBACd,IAAI,GAAG,CAAC,IAAI;wBACR,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;;wBAEtF,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;oBAC7E,MAAM;gBACV,KAAK,6BAAQ,CAAC,IAAI;oBACd,IAAI,GAAG,CAAC,IAAI;wBACR,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;;wBAEtF,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;oBAC7E,MAAM;gBACV,KAAK,6BAAQ,CAAC,KAAK;oBACf,IAAI,GAAG,CAAC,IAAI;wBACR,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;;wBAEvF,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;oBAC9E,MAAM;gBACV,KAAK,6BAAQ,CAAC,KAAK;oBACf,IAAI,cAAc,CAAC,MAAM,IAAI,cAAc,CAAC,MAAM,CAAC,KAAK;wBACpD,IAAI,GAAG,CAAC,IAAI;4BACR,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;;4BAEtF,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;oBACjF,MAAM;YACd,CAAC;QACL,CAAC;KACJ;CACJ,CAAC,CAAC;AAEU,QAAA,cAAc,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAC9C,QAAA,cAAc,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAC9C,QAAA,cAAc,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAC9C,QAAA,cAAc,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAC9C,QAAA,aAAa,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AAElD,MAAM,eAAe,GAAG,UAAS,WAA8B,KAAK,EAAE,QAAkB,6BAAQ,CAAC,GAAG;IACvG,QAAO,QAAQ,EAAE,CAAC;QACd,KAAK,KAAK;YACN,QAAQ,CAAC,qBAAqB,CAAC;gBAC3B,KAAK,EAAE,KAAK;aACf,CAAC,CAAC;YACH,MAAM;QACV,KAAK,MAAM;YACP,QAAQ,CAAC,6BAA6B,CAAC,sBAAc,EAAE;gBACnD,KAAK,EAAE,KAAK;aACf,CAAC,CAAC;YACH,MAAM;QACV,KAAK,MAAM;YACP,QAAQ,CAAC,6BAA6B,CAAC,sBAAc,EAAE;gBACnD,KAAK,EAAE,KAAK;aACf,CAAC,CAAC;YACH,MAAM;QACV,KAAK,MAAM;YACP,QAAQ,CAAC,6BAA6B,CAAC,sBAAc,EAAE;gBACnD,KAAK,EAAE,KAAK;aACf,CAAC,CAAC;YACH,MAAM;QACV,KAAK,KAAK;YACN,QAAQ,CAAC,6BAA6B,CAAC,qBAAa,EAAE;gBAClD,KAAK,EAAE,KAAK;aACf,CAAC,CAAC;YACH,MAAM;QACV,KAAK,MAAM;YACP,QAAQ,CAAC,6BAA6B,CAAC,sBAAc,EAAE;gBACnD,KAAK,EAAE,KAAK;aACf,CAAC,CAAC;YACH,MAAM;IACd,CAAC;AACL,CAAC,CAAA;AAjCY,QAAA,eAAe,mBAiC3B;AAEM,MAAM,eAAe,GAAG,UAAS,WAA8B,KAAK;IACvE,QAAO,QAAQ,EAAE,CAAC;QACd,KAAK,KAAK;YACN,OAAO,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;QACxC;YACI,OAAO,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC;IACvD,CAAC;AACL,CAAC,CAAA;AAPY,QAAA,eAAe,mBAO3B"}

6
build/mqtt/interface.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
import { DeviceSmartLockMessage } from "./model";
export interface MQTTServiceEvents {
"connect": () => void;
"close": () => void;
"lock message": (message: DeviceSmartLockMessage) => void;
}

3
build/mqtt/interface.js Normal file
View File

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=interface.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/mqtt/interface.ts"],"names":[],"mappings":""}

24
build/mqtt/model.d.ts vendored Normal file
View File

@ -0,0 +1,24 @@
export interface DeviceSmartLockNotifyData {
stationSn: string;
deviceSn: string;
eventType: number;
eventTime: number;
shortUserId: string;
unknown1: string;
nickName: string;
userId: string;
unknown2: string;
deviceName: string;
unknown3: string;
lockState: string;
}
export interface DeviceSmartLockNotify {
timestamp: number;
uuid: string;
data: DeviceSmartLockNotifyData;
}
export interface DeviceSmartLockMessage {
eventType: number;
userId: string;
data: DeviceSmartLockNotify;
}

3
build/mqtt/model.js Normal file
View File

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=model.js.map

1
build/mqtt/model.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/mqtt/model.ts"],"names":[],"mappings":""}

79
build/mqtt/mqtt-eufy.crt Normal file
View File

@ -0,0 +1,79 @@
-----BEGIN CERTIFICATE-----
MIIE0DCCA7igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAwMFoXDTMxMDUwMzA3
MDAwMFowgbQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEtMCsGA1UE
CxMkaHR0cDovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMwMQYDVQQD
EypHbyBEYWRkeSBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC54MsQ1K92vdSTYuswZLiBCGzD
BNliF44v/z5lz4/OYuY8UhzaFkVLVat4a2ODYpDOD2lsmcgaFItMzEUz6ojcnqOv
K/6AYZ15V8TPLvQ/MDxdR/yaFrzDN5ZBUY4RS1T4KL7QjL7wMDge87Am+GZHY23e
cSZHjzhHU9FGHbTj3ADqRay9vHHZqm8A29vNMDp5T19MR/gd71vCxJ1gO7GyQ5HY
pDNO6rPWJ0+tJYqlxvTV0KaudAVkV4i1RFXULSo6Pvi4vekyCgKUZMQWOlDxSq7n
eTOvDCAHf+jfBDnCaQJsY1L6d8EbyHSHyLmTGFBUNUtpTrw700kuH9zB0lL7AgMB
AAGjggEaMIIBFjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
HQ4EFgQUQMK9J47MNIMwojPX+2yz8LQsgM4wHwYDVR0jBBgwFoAUOpqFBxBnKLbv
9r0FQW4gwZTaD94wNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v
b2NzcC5nb2RhZGR5LmNvbS8wNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2NybC5n
b2RhZGR5LmNvbS9nZHJvb3QtZzIuY3JsMEYGA1UdIAQ/MD0wOwYEVR0gADAzMDEG
CCsGAQUFBwIBFiVodHRwczovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkv
MA0GCSqGSIb3DQEBCwUAA4IBAQAIfmyTEMg4uJapkEv/oV9PBO9sPpyIBslQj6Zz
91cxG7685C/b+LrTW+C05+Z5Yg4MotdqY3MxtfWoSKQ7CC2iXZDXtHwlTxFWMMS2
RJ17LJ3lXubvDGGqv+QqG+6EnriDfcFDzkSnE3ANkR/0yBOtg2DZ2HKocyQetawi
DsoXiWJYRBuriSUBAA/NxBti21G00w9RKpv0vHP8ds42pM3Z2Czqrpv1KrKQ0U11
GIo/ikGQI31bS/6kA1ibRrLDYGCD+H1QQc7CoZDDu+8CL9IVVO5EFdkKrqeKM+2x
LXY2JtwE65/3YR8V3Idv7kaWKK2hJn0KCacuBKONvPi8BDAB
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEfTCCA2WgAwIBAgIDG+cVMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVT
MSEwHwYDVQQKExhUaGUgR28gRGFkZHkgR3JvdXAsIEluYy4xMTAvBgNVBAsTKEdv
IERhZGR5IENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMTAx
MDcwMDAwWhcNMzEwNTMwMDcwMDAwWjCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHku
Y29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1
dGhvcml0eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv3Fi
CPH6WTT3G8kYo/eASVjpIoMTpsUgQwE7hPHmhUmfJ+r2hBtOoLTbcJjHMgGxBT4H
Tu70+k8vWTAi56sZVmvigAf88xZ1gDlRe+X5NbZ0TqmNghPktj+pA4P6or6KFWp/
3gvDthkUBcrqw6gElDtGfDIN8wBmIsiNaW02jBEYt9OyHGC0OPoCjM7T3UYH3go+
6118yHz7sCtTpJJiaVElBWEaRIGMLKlDliPfrDqBmg4pxRyp6V0etp6eMAo5zvGI
gPtLXcwy7IViQyU0AlYnAZG0O3AqP26x6JyIAX2f1PnbU21gnb8s51iruF9G/M7E
GwM8CetJMVxpRrPgRwIDAQABo4IBFzCCARMwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9BUFuIMGU2g/eMB8GA1Ud
IwQYMBaAFNLEsNKR1EwRcbNhyz2h/t2oatTjMDQGCCsGAQUFBwEBBCgwJjAkBggr
BgEFBQcwAYYYaHR0cDovL29jc3AuZ29kYWRkeS5jb20vMDIGA1UdHwQrMCkwJ6Al
oCOGIWh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Ryb290LmNybDBGBgNVHSAEPzA9
MDsGBFUdIAAwMzAxBggrBgEFBQcCARYlaHR0cHM6Ly9jZXJ0cy5nb2RhZGR5LmNv
bS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAWQtTvZKGEacke+1bMc8d
H2xwxbhuvk679r6XUOEwf7ooXGKUwuN+M/f7QnaF25UcjCJYdQkMiGVnOQoWCcWg
OJekxSOTP7QYpgEGRJHjp2kntFolfzq3Ms3dhP8qOCkzpN1nsoX+oYggHFCJyNwq
9kIDN0zmiN/VryTyscPfzLXs4Jlet0lUIDyUGAzHHFIYSaRt4bNYC8nY7NmuHDKO
KHAN4v6mF56ED71XcLNa6R+ghlO773z/aQvgSMO3kwvIClTErF0UZzdsyqUvMQg3
qm5vjLyb4lddJIGvl5echK1srDdMZvNhkREg5L4wn3qkKQmw4TRfZHcYQFHfjDCm
rw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
ReYNnyicsbkqWletNw+vHX/bvZ8=
-----END CERTIFICATE-----

View File

@ -0,0 +1,33 @@
// Copyright: (c) 2022-2024, Patrick Broetto <patrick.broetto@gmail.com>
// MIT License
syntax = "proto3";
package eufy_security_client.lock;
message DeviceSmartLockMessage {
optional uint32 event_type = 1;
optional string user_id = 2;
optional DeviceSmartLockNotify data = 3;
}
message DeviceSmartLockNotify {
optional uint64 timestamp = 1;
optional string uuid = 2;
optional DeviceSmartLockNotifyData data = 3;
}
message DeviceSmartLockNotifyData {
optional string station_sn = 1;
optional string device_sn = 2;
optional uint32 event_type = 3;
optional uint64 event_time = 4;
optional string short_user_id = 5;
optional string unknown1 = 6;
optional string nick_name = 7;
optional string user_id = 8;
optional string unknown2 = 9;
optional string device_name = 10;
optional string unknown3 = 11;
optional string lock_state = 12;
}

28
build/mqtt/service.d.ts vendored Normal file
View File

@ -0,0 +1,28 @@
import { TypedEmitter } from "tiny-typed-emitter";
import { MQTTServiceEvents } from "./interface";
export declare class MQTTService extends TypedEmitter<MQTTServiceEvents> {
private readonly CLIENT_ID_FORMAT;
private readonly USERNAME_FORMAT;
private readonly SUBSCRIBE_NOTICE_FORMAT;
private readonly SUBSCRIBE_LOCK_FORMAT;
private readonly SUBSCRIBE_DOORBELL_FORMAT;
private static proto;
private connected;
private client;
private connecting;
private clientID?;
private androidID?;
private apiBase?;
private email?;
private subscribeLocks;
private deviceSmartLockMessageModel;
private constructor();
static init(): Promise<MQTTService>;
private parseSmartLockMessage;
private getMQTTBrokerUrl;
connect(clientID: string, androidID: string, apiBase: string, email: string): void;
private _subscribeLock;
subscribeLock(deviceSN: string): void;
isConnected(): boolean;
close(): void;
}

177
build/mqtt/service.js Normal file
View File

@ -0,0 +1,177 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MQTTService = void 0;
const mqtt = __importStar(require("mqtt"));
const tiny_typed_emitter_1 = require("tiny-typed-emitter");
const fse = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const protobufjs_1 = require("protobufjs");
const utils_1 = require("../utils");
const logging_1 = require("../logging");
const error_1 = require("../error");
class MQTTService extends tiny_typed_emitter_1.TypedEmitter {
CLIENT_ID_FORMAT = "android_EufySecurity_<user_id>_<android_id>";
USERNAME_FORMAT = "eufy_<user_id>";
SUBSCRIBE_NOTICE_FORMAT = "/phone/<user_id>/notice";
SUBSCRIBE_LOCK_FORMAT = "/phone/smart_lock/<device_sn>/push_message";
SUBSCRIBE_DOORBELL_FORMAT = "/phone/doorbell/<device_sn>/push_message";
static proto = null;
connected = false;
client = null;
connecting = false;
clientID;
androidID;
apiBase;
email;
subscribeLocks = [];
deviceSmartLockMessageModel;
constructor() {
super();
this.deviceSmartLockMessageModel = MQTTService.proto.lookupType("DeviceSmartLockMessage");
}
static async init() {
try {
this.proto = await (0, protobufjs_1.load)(path.join(__dirname, "./proto/lock.proto"));
}
catch (error) {
logging_1.rootMainLogger.error("Error loading MQTT proto lock file", { error: (0, error_1.ensureError)(error) });
}
return new MQTTService();
}
parseSmartLockMessage(data) {
const message = this.deviceSmartLockMessageModel.decode(data);
const object = this.deviceSmartLockMessageModel.toObject(message, {
longs: String,
enums: String,
bytes: String,
});
return object;
}
getMQTTBrokerUrl(apiBase) {
switch (apiBase) {
case "https://security-app.eufylife.com":
return "mqtts://security-mqtt.eufylife.com";
case "https://security-app-ci.eufylife.com":
return "mqtts://security-mqtt-ci.eufylife.com";
case "https://security-app-qa.eufylife.com":
case "https://security-app-cn-qa.anker-in.com":
return "mqtts://security-mqtt-qa.eufylife.com";
case "https://security-app-eu.eufylife.com":
return "mqtts://security-mqtt-eu.eufylife.com";
case "https://security-app-short-qa.eufylife.com":
return "mqtts://security-mqtt-short-qa.eufylife.com";
default:
return "mqtts://security-mqtt.eufylife.com";
}
}
connect(clientID, androidID, apiBase, email) {
this.clientID = clientID;
this.androidID = androidID;
this.apiBase = apiBase;
this.email = email;
if (!this.connected && !this.connecting && this.clientID && this.androidID && this.apiBase && this.email && this.subscribeLocks.length > 0) {
this.connecting = true;
this.client = mqtt.connect(this.getMQTTBrokerUrl(apiBase), {
keepalive: 60,
clean: true,
reschedulePings: true,
resubscribe: true,
port: 8789,
username: this.USERNAME_FORMAT.replace("<user_id>", clientID),
password: email,
ca: fse.readFileSync(path.join(__dirname, "./mqtt-eufy.crt")),
clientId: this.CLIENT_ID_FORMAT.replace("<user_id>", clientID).replace("<android_id>", androidID),
rejectUnauthorized: false // Some eufy mqtt servers have an expired certificate :(
});
this.client.on("connect", (_connack) => {
this.connected = true;
this.connecting = false;
this.emit("connect");
this.client.subscribe(this.SUBSCRIBE_NOTICE_FORMAT.replace("<user_id>", clientID), { qos: 1 });
if (this.subscribeLocks.length > 0) {
let lock;
while ((lock = this.subscribeLocks.shift()) !== undefined) {
this._subscribeLock(lock);
}
}
});
this.client.on("close", () => {
this.connected = false;
this.emit("close");
});
this.client.on("error", (error) => {
this.connecting = false;
logging_1.rootMQTTLogger.error("MQTT Error", { error: (0, utils_1.getError)(error) });
if (error.code === 1 || error.code === 2 || error.code === 4 || error.code === 5)
this.client?.end();
});
this.client.on("message", (topic, message, _packet) => {
if (topic.includes("smart_lock")) {
const parsedMessage = this.parseSmartLockMessage(message);
logging_1.rootMQTTLogger.debug("Received a smart lock message over MQTT", { message: parsedMessage });
this.emit("lock message", parsedMessage);
}
else {
logging_1.rootMQTTLogger.debug("MQTT message received", { topic: topic, message: message.toString("hex") });
}
});
}
}
_subscribeLock(deviceSN) {
this.client?.subscribe(this.SUBSCRIBE_LOCK_FORMAT.replace("<device_sn>", deviceSN), { qos: 1 }, (error, granted) => {
if (error) {
logging_1.rootMQTTLogger.error(`Subscribe error for lock ${deviceSN}`, { error: (0, utils_1.getError)(error), deviceSN: deviceSN });
}
if (granted) {
logging_1.rootMQTTLogger.info(`Successfully registered to MQTT notifications for lock ${deviceSN}`);
}
});
}
subscribeLock(deviceSN) {
if (this.connected) {
this._subscribeLock(deviceSN);
}
else {
if (!this.subscribeLocks.includes(deviceSN)) {
this.subscribeLocks.push(deviceSN);
}
if (this.clientID && this.androidID && this.apiBase && this.email)
this.connect(this.clientID, this.androidID, this.apiBase, this.email);
}
}
isConnected() {
return this.connected;
}
close() {
if (this.connected) {
this.client?.end(true);
this.connected = false;
this.connecting = false;
}
}
}
exports.MQTTService = MQTTService;
//# sourceMappingURL=service.js.map

File diff suppressed because one or more lines are too long

59
build/p2p/ble.d.ts vendored Normal file
View File

@ -0,0 +1,59 @@
export declare enum BleParameterIndex {
ZERO = -96,
ONE = -95,
TWO = -94,
THREE = -93,
FOUR = -92,
FIVE = -91,
SIX = -90,
SEVEN = -89,
EIGHT = -88,
NINE = -87,
TEN = -86,
ELEVEN = -85,
TWELVE = -84,
THIRTEEN = -83
}
export declare class BleCommandFactory {
private static readonly HEADER;
private data?;
private commandCode?;
private versionCode?;
private dataType?;
private packageFlag?;
private unknown?;
private additionalDataSeparatorByte?;
private additionalData?;
private responseCode?;
private encrypted?;
private partial?;
static parseLockV12(data: string | Buffer): BleCommandFactory;
static parseSmartSafe(data: string | Buffer): BleCommandFactory;
static parseSmartLock(data: string | Buffer): BleCommandFactory;
toString: () => string;
private setResponseCode;
getResponseCode(): number | undefined;
setVersionCode(version: number): BleCommandFactory;
getVersionCode(): number | undefined;
setCommandCode(command: number): BleCommandFactory;
getCommandCode(): number | undefined;
setDataType(type: number): BleCommandFactory;
getDataType(): number | undefined;
setPackageFlag(flag: number): BleCommandFactory;
getPackageFlag(): number | undefined;
setAdditionalDataSeparator(separator: number): BleCommandFactory;
getAdditionalDataSeparator(): Buffer | undefined;
setAdditionalData(data: Buffer): BleCommandFactory;
getAdditionalData(): Buffer | undefined;
setData(data: Buffer): BleCommandFactory;
getData(): Buffer | undefined;
setUnknown(data: Buffer): BleCommandFactory;
static generateHash(data: Buffer): number;
isEncrypted(): boolean | undefined;
setEncrypted(encrypted: boolean): BleCommandFactory;
isPartial(): boolean | undefined;
setPartial(partial: boolean): BleCommandFactory;
getLockV12Command(): Buffer;
getSmartSafeCommand(): Buffer;
getSmartLockCommand(): Buffer;
}

280
build/p2p/ble.js Normal file
View File

@ -0,0 +1,280 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BleCommandFactory = exports.BleParameterIndex = void 0;
const error_1 = require("./error");
var BleParameterIndex;
(function (BleParameterIndex) {
BleParameterIndex[BleParameterIndex["ZERO"] = -96] = "ZERO";
BleParameterIndex[BleParameterIndex["ONE"] = -95] = "ONE";
BleParameterIndex[BleParameterIndex["TWO"] = -94] = "TWO";
BleParameterIndex[BleParameterIndex["THREE"] = -93] = "THREE";
BleParameterIndex[BleParameterIndex["FOUR"] = -92] = "FOUR";
BleParameterIndex[BleParameterIndex["FIVE"] = -91] = "FIVE";
BleParameterIndex[BleParameterIndex["SIX"] = -90] = "SIX";
BleParameterIndex[BleParameterIndex["SEVEN"] = -89] = "SEVEN";
BleParameterIndex[BleParameterIndex["EIGHT"] = -88] = "EIGHT";
BleParameterIndex[BleParameterIndex["NINE"] = -87] = "NINE";
BleParameterIndex[BleParameterIndex["TEN"] = -86] = "TEN";
BleParameterIndex[BleParameterIndex["ELEVEN"] = -85] = "ELEVEN";
BleParameterIndex[BleParameterIndex["TWELVE"] = -84] = "TWELVE";
BleParameterIndex[BleParameterIndex["THIRTEEN"] = -83] = "THIRTEEN";
})(BleParameterIndex || (exports.BleParameterIndex = BleParameterIndex = {}));
class BleCommandFactory {
static HEADER = Buffer.from([-1, 9]);
data;
commandCode;
versionCode;
dataType;
packageFlag;
unknown;
additionalDataSeparatorByte;
additionalData;
responseCode;
encrypted;
partial;
static parseLockV12(data) {
if (typeof data === "string") {
data = Buffer.from(data, "hex");
}
if (data.readInt8(0) !== BleCommandFactory.HEADER[0] && data.readInt8(1) !== BleCommandFactory.HEADER[1]) {
throw new error_1.BleInvalidDataHeaderError("Invalid BLE data header");
}
const fac = new BleCommandFactory();
fac.setVersionCode(data.readUint8(4));
fac.setCommandCode(data.readUint8(6));
fac.setDataType(data.readUint8());
fac.setPackageFlag(data.readInt8(7));
fac.setResponseCode(fac.getPackageFlag() === -64 ? data.readUint8(8) : data.readUint8(12));
fac.setData(data.subarray(fac.getPackageFlag() === -64 ? 8 : 12, data.length - 1)); //TODO: Verify if position 8 is correct for data (i think it should be 9 or 13)...
if (BleCommandFactory.generateHash(data.subarray(0, data.length - 1)) !== data.readUint8(data.length - 1)) {
throw new error_1.BleInvalidChecksumError("Invalid BLE data, checksum mismatch");
}
return fac;
}
static parseSmartSafe(data) {
return BleCommandFactory.parseLockV12(data);
}
static parseSmartLock(data) {
if (typeof data === "string") {
data = Buffer.from(data, "hex");
}
if (data.length < 9 || (data.readInt8(0) !== BleCommandFactory.HEADER[0] && data.readInt8(1) !== BleCommandFactory.HEADER[1])) {
throw new error_1.BleInvalidDataHeaderError("Invalid BLE data header");
}
if (BleCommandFactory.generateHash(data.subarray(0, data.length - 1)) !== data.readUint8(data.length - 1)) {
throw new error_1.BleInvalidChecksumError("Invalid BLE data, checksum mismatch");
}
const fac = new BleCommandFactory();
const flags = data.readUint16BE(7);
fac.setVersionCode(data.readUint8(4));
fac.setDataType(data.readUint8(6));
fac.setPartial((flags >> 15) === 1);
fac.setEncrypted(((flags << 1) >> 15) === 1);
fac.setCommandCode(((flags << 4) & 32767) >> 4);
fac.setData(data.subarray(9, data.length - 1));
return fac;
}
toString = () => {
return `BleCommandFactory (versionCode: ${this.versionCode} commandCode: ${this.commandCode} dataType: ${this.dataType} partial: ${this.partial} encrypted: ${this.encrypted} data: ${this.data?.toString("hex")} packageFlag: ${this.packageFlag} responseCode: ${this.responseCode})`;
};
setResponseCode(code) {
this.responseCode = code;
}
getResponseCode() {
return this.responseCode;
}
setVersionCode(version) {
this.versionCode = version;
return this;
}
getVersionCode() {
return this.versionCode;
}
setCommandCode(command) {
this.commandCode = command;
return this;
}
getCommandCode() {
return this.commandCode;
}
setDataType(type) {
this.dataType = type;
return this;
}
getDataType() {
return this.dataType;
}
setPackageFlag(flag) {
this.packageFlag = flag;
return this;
}
getPackageFlag() {
return this.packageFlag;
}
setAdditionalDataSeparator(separator) {
this.additionalDataSeparatorByte = Buffer.from([separator]);
return this;
}
getAdditionalDataSeparator() {
return this.additionalDataSeparatorByte;
}
setAdditionalData(data) {
this.additionalData = data;
return this;
}
getAdditionalData() {
return this.additionalData;
}
setData(data) {
this.data = data;
return this;
}
getData() {
return this.data;
}
setUnknown(data) {
this.unknown = data;
return this;
}
static generateHash(data) {
let result = 0;
for (const value of data) {
result = result ^ value;
}
return result;
}
isEncrypted() {
return this.encrypted;
}
setEncrypted(encrypted) {
this.encrypted = encrypted;
return this;
}
isPartial() {
return this.partial;
}
setPartial(partial) {
this.partial = partial;
return this;
}
getLockV12Command() {
if (this.versionCode === undefined)
throw new error_1.BleVersionCodeError("BleCommandFactory version code value missing");
if (this.dataType === undefined)
throw new error_1.BleDataTypeError("BleCommandFactory data type value missing");
if (this.commandCode === undefined)
throw new error_1.BleCommandCodeError("BleCommandFactory command code value missing");
if (this.data === undefined)
throw new error_1.BleDataError("BleCommandFactory data value missing");
if (this.additionalData === undefined)
throw new error_1.BleAdditionalDataError("BleCommandFactory additional data value missing");
this.setAdditionalDataSeparator(BleParameterIndex.ZERO);
const bVersionCode = Buffer.from([this.versionCode]);
const bDataType = Buffer.from([this.dataType]);
const bCommandCode = Buffer.from([this.commandCode]);
const bPackageFlag = this.packageFlag === undefined ? Buffer.from([-64]) : Buffer.from([this.packageFlag]);
const bAdditionalDataLength = Buffer.from([this.additionalData.length]);
const size = Buffer.allocUnsafe(2);
size.writeInt16LE(BleCommandFactory.HEADER.length +
size.length +
bVersionCode.length +
bDataType.length +
bCommandCode.length +
bPackageFlag.length +
this.additionalDataSeparatorByte.length +
bAdditionalDataLength.length +
this.additionalData.length +
this.data.length +
1 // Hash
);
const data = Buffer.concat([
BleCommandFactory.HEADER,
size,
bVersionCode,
bDataType,
bCommandCode,
bPackageFlag,
this.additionalDataSeparatorByte,
bAdditionalDataLength,
this.additionalData,
this.data
]);
const hash = BleCommandFactory.generateHash(data);
return Buffer.concat([data, Buffer.from([hash])]);
}
getSmartSafeCommand() {
if (this.versionCode === undefined)
throw new error_1.BleVersionCodeError("BleCommandFactory version code value missing");
if (this.dataType === undefined)
throw new error_1.BleDataTypeError("BleCommandFactory data type value missing");
if (this.commandCode === undefined)
throw new error_1.BleCommandCodeError("BleCommandFactory command code value missing");
if (this.data === undefined)
throw new error_1.BleDataError("BleCommandFactory data value missing");
const bVersionCode = Buffer.from([this.versionCode]);
const bDataType = Buffer.from([this.dataType]);
const bCommandCode = Buffer.from([this.commandCode]);
const bPackageFlag = this.packageFlag === undefined ? Buffer.from([-64]) : Buffer.from([this.packageFlag]);
const size = Buffer.allocUnsafe(2);
size.writeInt16LE(BleCommandFactory.HEADER.length +
size.length +
bVersionCode.length +
bDataType.length +
bCommandCode.length +
bPackageFlag.length +
this.data.length +
1 // Hash
);
const data = Buffer.concat([
BleCommandFactory.HEADER,
size,
bVersionCode,
bDataType,
bCommandCode,
bPackageFlag,
this.data
]);
const hash = BleCommandFactory.generateHash(data);
return Buffer.concat([data, Buffer.from([hash])]);
}
getSmartLockCommand() {
if (this.versionCode === undefined)
throw new error_1.BleVersionCodeError("BleCommandFactory version code value missing");
if (this.dataType === undefined)
throw new error_1.BleDataTypeError("BleCommandFactory data type value missing");
if (this.commandCode === undefined)
throw new error_1.BleCommandCodeError("BleCommandFactory command code value missing");
if (this.data === undefined)
throw new error_1.BleDataError("BleCommandFactory data value missing");
const bVersionCode = Buffer.from([this.versionCode]);
const bDataType = Buffer.from([this.dataType]);
const unknown = Buffer.alloc(1);
const partial = false;
const encrypted = true;
const commandCodeEncoded = Buffer.allocUnsafe(2);
commandCodeEncoded.writeInt16BE(((partial ? 1 : 0) << 15) + ((encrypted ? 1 : 0) << 14) + this.commandCode);
const size = Buffer.allocUnsafe(2);
size.writeInt16LE(BleCommandFactory.HEADER.length +
size.length +
bVersionCode.length +
unknown.length +
bDataType.length +
commandCodeEncoded.length +
this.data.length +
1 // Hash
);
const data = Buffer.concat([
BleCommandFactory.HEADER,
size,
bVersionCode,
unknown,
bDataType,
commandCodeEncoded,
this.data
]);
const hash = BleCommandFactory.generateHash(data);
return Buffer.concat([data, Buffer.from([hash])]);
}
}
exports.BleCommandFactory = BleCommandFactory;
//# sourceMappingURL=ble.js.map

1
build/p2p/ble.js.map Normal file

File diff suppressed because one or more lines are too long

49
build/p2p/error.d.ts vendored Normal file
View File

@ -0,0 +1,49 @@
import { BaseError, Jsonable } from "../error";
export declare class BleVersionCodeError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleCommandCodeError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleDataTypeError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleDataError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleAdditionalDataError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleAdditionalDataSeparatorError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleInvalidDataHeaderError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleInvalidChecksumError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}

69
build/p2p/error.js Normal file
View File

@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BleInvalidChecksumError = exports.BleInvalidDataHeaderError = exports.BleAdditionalDataSeparatorError = exports.BleAdditionalDataError = exports.BleDataError = exports.BleDataTypeError = exports.BleCommandCodeError = exports.BleVersionCodeError = void 0;
const error_1 = require("../error");
class BleVersionCodeError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleVersionCodeError.name;
}
}
exports.BleVersionCodeError = BleVersionCodeError;
class BleCommandCodeError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleCommandCodeError.name;
}
}
exports.BleCommandCodeError = BleCommandCodeError;
class BleDataTypeError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleDataTypeError.name;
}
}
exports.BleDataTypeError = BleDataTypeError;
class BleDataError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleDataError.name;
}
}
exports.BleDataError = BleDataError;
class BleAdditionalDataError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleAdditionalDataError.name;
}
}
exports.BleAdditionalDataError = BleAdditionalDataError;
class BleAdditionalDataSeparatorError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleAdditionalDataSeparatorError.name;
}
}
exports.BleAdditionalDataSeparatorError = BleAdditionalDataSeparatorError;
class BleInvalidDataHeaderError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleInvalidDataHeaderError.name;
}
}
exports.BleInvalidDataHeaderError = BleInvalidDataHeaderError;
class BleInvalidChecksumError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleInvalidChecksumError.name;
}
}
exports.BleInvalidChecksumError = BleInvalidChecksumError;
//# sourceMappingURL=error.js.map

1
build/p2p/error.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/p2p/error.ts"],"names":[],"mappings":";;;AAAA,oCAA+C;AAC/C,MAAa,mBAAoB,SAAQ,iBAAS;IAC9C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC;IACzC,CAAC;CACJ;AAND,kDAMC;AAED,MAAa,mBAAoB,SAAQ,iBAAS;IAC9C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC;IACzC,CAAC;CACJ;AAND,kDAMC;AAED,MAAa,gBAAiB,SAAQ,iBAAS;IAC3C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;IACtC,CAAC;CACJ;AAND,4CAMC;AAED,MAAa,YAAa,SAAQ,iBAAS;IACvC,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;IAClC,CAAC;CACJ;AAND,oCAMC;AAED,MAAa,sBAAuB,SAAQ,iBAAS;IACjD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC,IAAI,CAAC;IAC5C,CAAC;CACJ;AAND,wDAMC;AAED,MAAa,+BAAgC,SAAQ,iBAAS;IAC1D,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC,IAAI,CAAC;IACrD,CAAC;CACJ;AAND,0EAMC;AAED,MAAa,yBAA0B,SAAQ,iBAAS;IACpD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC;IAC/C,CAAC;CACJ;AAND,8DAMC;AAED,MAAa,uBAAwB,SAAQ,iBAAS;IAClD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC,IAAI,CAAC;IAC7C,CAAC;CACJ;AAND,0DAMC"}

8
build/p2p/index.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
export * from "./interfaces";
export * from "./models";
export * from "./session";
export * from "./types";
export * from "./talkback";
export * from "./ble";
export * from "./error";
export { isPrivateIp, getLocalIpAddress } from "./utils";

28
build/p2p/index.js Normal file
View File

@ -0,0 +1,28 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLocalIpAddress = exports.isPrivateIp = void 0;
__exportStar(require("./interfaces"), exports);
__exportStar(require("./models"), exports);
__exportStar(require("./session"), exports);
__exportStar(require("./types"), exports);
__exportStar(require("./talkback"), exports);
__exportStar(require("./ble"), exports);
__exportStar(require("./error"), exports);
var utils_1 = require("./utils");
Object.defineProperty(exports, "isPrivateIp", { enumerable: true, get: function () { return utils_1.isPrivateIp; } });
Object.defineProperty(exports, "getLocalIpAddress", { enumerable: true, get: function () { return utils_1.getLocalIpAddress; } });
//# sourceMappingURL=index.js.map

1
build/p2p/index.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/p2p/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,2CAAyB;AACzB,4CAA0B;AAC1B,0CAAwB;AACxB,6CAA2B;AAC3B,wCAAsB;AACtB,0CAAwB;AACxB,iCAAyD;AAAhD,oGAAA,WAAW,OAAA;AAAE,0GAAA,iBAAiB,OAAA"}

388
build/p2p/interfaces.d.ts vendored Normal file
View File

@ -0,0 +1,388 @@
import * as NodeRSA from "node-rsa";
import { Readable } from "stream";
import { SortedMap } from "sweet-collections";
import { AlarmMode, DeviceType, MicStatus, ParamType, TriggerType, VideoType } from "../http/types";
import { Address, CmdCameraInfoResponse, CommandResult, CustomData, StorageInfoBodyHB3 } from "./models";
import { TalkbackStream } from "./talkback";
import { AlarmEvent, AudioCodec, CommandType, DatabaseReturnCode, IndoorSoloSmartdropCommandType, P2PDataType, SmartSafeAlarm911Event, SmartSafeShakeAlarmEvent, P2PStorageType, TFCardStatus, VideoCodec, InternalP2PCommandType } from "./types";
export interface P2PClientProtocolEvents {
"alarm mode": (mode: AlarmMode) => void;
"camera info": (cameraInfo: CmdCameraInfoResponse) => void;
"connect": (address: Address) => void;
"close": () => void;
"command": (result: CommandResult) => void;
"download started": (channel: number, metadata: StreamMetadata, videoStream: Readable, audioStream: Readable) => void;
"download finished": (channel: number) => void;
"livestream started": (channel: number, metadata: StreamMetadata, videoStream: Readable, audioStream: Readable) => void;
"livestream stopped": (channel: number) => void;
"livestream error": (channel: number, error: Error) => void;
"wifi rssi": (channel: number, rssi: number) => void;
"rtsp url": (channel: number, rtspUrl: string) => void;
"parameter": (channel: number, param: number, value: string) => void;
"timeout": () => void;
"runtime state": (channel: number, batteryLevel: number, temperature: number) => void;
"charging state": (channel: number, chargeType: number, batteryLevel: number) => void;
"rtsp livestream started": (channel: number) => void;
"rtsp livestream stopped": (channel: number) => void;
"floodlight manual switch": (channel: number, enabled: boolean) => void;
"alarm delay": (alarmDelayEvent: AlarmEvent, alarmDelay: number) => void;
"alarm armed": () => void;
"alarm event": (alarmEvent: AlarmEvent) => void;
"talkback started": (channel: number, talkbackStream: TalkbackStream) => void;
"talkback stopped": (channel: number) => void;
"talkback error": (channel: number, error: Error) => void;
"secondary command": (result: CommandResult) => void;
"jammed": (channel: number) => void;
"low battery": (channel: number) => void;
"shake alarm": (channel: number, detail: SmartSafeShakeAlarmEvent) => void;
"911 alarm": (channel: number, detail: SmartSafeAlarm911Event) => void;
"wrong try-protect alarm": (channel: number) => void;
"sd info ex": (sdStatus: TFCardStatus, sdCapacity: number, sdCapacityAvailable: number) => void;
"image download": (file: string, image: Buffer) => void;
"tfcard status": (channel: number, status: TFCardStatus) => void;
"database query latest": (returnCode: DatabaseReturnCode, data: Array<DatabaseQueryLatestInfo>) => void;
"database query local": (returnCode: DatabaseReturnCode, data: Array<DatabaseQueryLocal>) => void;
"database count by date": (returnCode: DatabaseReturnCode, data: Array<DatabaseCountByDate>) => void;
"database delete": (returnCode: DatabaseReturnCode, failedIds: Array<unknown>) => void;
"sensor status": (channel: number, status: number) => void;
"garage door status": (channel: number, doorId: number, status: number) => void;
"storage info hb3": (channel: number, storageInfo: StorageInfoBodyHB3) => void;
"sequence error": (channel: number, command: number, sequence: number, serialnumber: string) => void;
}
export interface P2PQueueMessage {
p2pCommandType: InternalP2PCommandType;
p2pCommand: P2PCommand;
nestedCommandType?: CommandType;
nestedCommandType2?: number;
timestamp: number;
customData?: CustomData;
}
export interface P2PMessageState {
sequence: number;
commandType: CommandType;
nestedCommandType?: CommandType | IndoorSoloSmartdropCommandType | ParamType;
nestedCommandType2?: number;
channel: number;
data: Buffer;
retries: number;
acknowledged: boolean;
returnCode?: number;
retryTimeout?: NodeJS.Timeout;
timeout?: NodeJS.Timeout;
customData?: CustomData;
}
export interface P2PMessageParts {
[index: number]: Buffer;
}
export interface P2PMessage {
bytesToRead: number;
type: P2PDataType;
seqNo: number;
data: Buffer;
}
export interface P2PDataHeader {
commandId: number;
bytesToRead: number;
channel: number;
signCode: number;
type: number;
}
export interface P2PDataMessage extends P2PDataHeader {
seqNo: number;
dataType: P2PDataType;
data: Buffer;
}
export interface P2PDataMessageBuilder {
header: P2PDataHeader;
bytesRead: number;
messages: P2PMessageParts;
}
export interface P2PDataMessageState {
leftoverData: Buffer;
queuedData: SortedMap<number, P2PMessage>;
rsaKey: NodeRSA | null;
videoStream: Readable | null;
audioStream: Readable | null;
invalidStream: boolean;
p2pStreaming: boolean;
p2pStreamNotStarted: boolean;
p2pStreamChannel: number;
p2pStreamFirstAudioDataReceived: boolean;
p2pStreamFirstVideoDataReceived: boolean;
p2pStreamMetadata: StreamMetadata;
p2pStreamingTimeout?: NodeJS.Timeout;
rtspStream: {
[index: number]: boolean;
};
rtspStreaming: {
[index: number]: boolean;
};
waitForSeqNoTimeout?: NodeJS.Timeout;
waitForAudioData?: NodeJS.Timeout;
receivedFirstIFrame: boolean;
preFrameVideoData: Buffer;
p2pTalkback: boolean;
p2pTalkbackChannel: number;
}
export interface P2PDataMessageVideo {
streamType: number;
videoSeqNo: number;
videoFPS: number;
videoWidth: number;
videoHeight: number;
videoTimestamp: number;
videoDataLength: number;
aesKey: string;
}
export interface P2PDataMessageAudio {
audioType: number;
audioSeqNo: number;
audioTimestamp: number;
audioDataLength: number;
}
export interface StreamMetadata {
videoCodec: VideoCodec;
videoFPS: number;
videoWidth: number;
videoHeight: number;
audioCodec: AudioCodec;
}
export interface DeviceSerial {
[index: number]: {
sn: string;
adminUserId: string;
};
}
export interface P2PCommand {
commandType: CommandType;
value?: number | string;
valueSub?: number;
strValue?: string;
strValueSub?: string;
channel?: number;
}
export interface P2PVideoMessageState {
sequence: number;
channel: number;
data: Buffer;
retries: number;
timeout?: NodeJS.Timeout;
}
export interface P2PDatabaseQueryLatestInfoResponse {
device_sn: string;
payload: {
event_count: number;
crop_hb3_path: string;
crop_cloud_path: string;
};
}
export interface P2PDatabaseCountByDateResponse {
days: string;
count: number;
}
export interface P2PDatabaseQueryLocalHistoryRecordInfo {
record_id: number;
account: string;
station_sn: string;
device_sn: string;
device_type: DeviceType;
start_time: string;
end_time: string;
frame_num: number;
storage_type: P2PStorageType;
storage_cloud: boolean;
cipher_id: number;
vision: number;
video_type: VideoType;
has_lock: boolean;
automation_id: number;
trigger_type: TriggerType;
push_mode: number;
mic_status: MicStatus;
res_change: number;
res_best_width: number;
res_best_height: number;
self_learning: number;
int_reserve: number;
int_extra: number;
storage_path: string;
thumb_path: string;
write_status: number;
str_extra: string;
cloud_path: string;
folder_size: number;
storage_status: number;
storage_label: string;
time_zone: string;
mp4_cloud: string;
snapshot_cloud: string;
table_version: string;
update_time: string;
}
export interface P2PDatabaseQueryLocalRecordCropPictureInfo {
picture_id: number;
record_id: number;
station_sn: string;
device_sn: string;
detection_type: number;
person_id: number;
crop_path: string;
event_time: string;
str_reserve: string;
person_recog_flag: boolean;
crop_pic_quality: number;
pic_marking_flag: boolean;
group_id: number;
int_reserve: number;
crop_id: number;
start_time: string;
reserve2_int: number;
reserve2_date: string;
reserve2_string: string;
storage_type: P2PStorageType;
storage_status: number;
storage_label: string;
table_version: string;
update_time: string;
}
export interface P2PDatabaseQueryLocalResponse {
payload: Array<P2PDatabaseQueryLocalHistoryRecordInfo> | Array<P2PDatabaseQueryLocalRecordCropPictureInfo>;
table_name: string;
}
export interface P2PDatabaseDeleteResponse {
failed_delete: Array<unknown>;
}
export interface P2PDatabaseResponse {
data: Array<P2PDatabaseQueryLatestInfoResponse> | Array<P2PDatabaseCountByDateResponse> | Array<P2PDatabaseQueryLocalResponse> | P2PDatabaseDeleteResponse;
start_id?: number;
end_id?: number;
count?: number;
transaction: string;
table: string;
cmd: number;
mIntRet: DatabaseReturnCode;
version: string;
msg: string;
}
export interface DatabaseQueryLatestInfoBase {
device_sn: string;
event_count: number;
}
export interface DatabaseQueryLatestInfoCloud extends DatabaseQueryLatestInfoBase {
crop_cloud_path: string;
}
export interface DatabaseQueryLatestInfoLocal extends DatabaseQueryLatestInfoBase {
crop_local_path: string;
}
export type DatabaseQueryLatestInfo = DatabaseQueryLatestInfoCloud | DatabaseQueryLatestInfoLocal;
export interface DatabaseCountByDate {
day: Date;
count: number;
}
export interface HistoryRecordInfo {
device_type: DeviceType;
account: string;
start_time: Date;
end_time: Date;
frame_num: number;
storage_type: P2PStorageType;
storage_cloud: boolean;
cipher_id: number;
vision: number;
video_type: VideoType;
has_lock: boolean;
automation_id: number;
trigger_type: TriggerType;
push_mode: number;
mic_status: MicStatus;
res_change: number;
res_best_width: number;
res_best_height: number;
self_learning: number;
storage_path: string;
thumb_path: string;
write_status: number;
cloud_path: string;
folder_size: number;
storage_status: number;
storage_label: string;
time_zone: string;
mp4_cloud: string;
snapshot_cloud: string;
table_version: string;
}
export interface CropPictureInfo {
picture_id: number;
detection_type: number;
person_id: number;
crop_path: string;
event_time: Date | null;
person_recog_flag: boolean;
crop_pic_quality: number;
pic_marking_flag: boolean;
group_id: number;
crop_id: number;
start_time: Date;
storage_type: P2PStorageType;
storage_status: number;
storage_label: string;
table_version: string;
update_time: string;
}
export interface DatabaseQueryLocal {
record_id: number;
station_sn: string;
device_sn?: string;
history: HistoryRecordInfo;
picture: Array<CropPictureInfo>;
}
export interface RGBColor {
red: number;
green: number;
blue: number;
}
export interface InternalColoredLighting {
color: number;
}
export interface DynamicLighting {
name: string;
mode: number;
speed: number;
colors: Array<RGBColor>;
}
export interface InternalDynamicLighting {
name: string;
mode: number;
id: number;
speed: number;
colors: Array<number>;
}
export interface MotionZonePoint {
x: number;
y: number;
}
export interface MotionZonePoints {
points: Array<MotionZonePoint>;
}
export interface MotionZone {
polygens: Array<MotionZonePoints>;
}
export interface VideoStreamingRecordingQuality {
mode_0: {
quality: number;
};
mode_1: {
quality: number;
};
cur_mode: number;
}
export interface CrossTrackingGroupEntry {
value: Array<string>;
}
export interface CustomDataType {
[index: number]: {
channel: number;
customData: CustomData;
timestamp: number;
};
}

3
build/p2p/interfaces.js Normal file
View File

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=interfaces.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../../src/p2p/interfaces.ts"],"names":[],"mappings":""}

284
build/p2p/models.d.ts vendored Normal file
View File

@ -0,0 +1,284 @@
import { PropertyValue } from "../http";
import { CommandName, PropertyName } from "../http/types";
import { SmartSafeEventValueDetail } from "../push/models";
import { CommandType } from "./types";
export interface Address {
host: string;
port: number;
}
export interface CmdCameraInfoResponse {
params: Array<{
dev_type: number;
param_type: number;
param_value: string;
}>;
main_sw_version: string;
sec_sw_version: string;
db_bypass_str?: Array<{
channel: number;
param_type: number;
param_value: string;
}>;
}
export interface PropertyData {
name: PropertyName;
value: PropertyValue;
}
export interface CommandData {
name: CommandName;
value?: any;
}
export interface CustomData {
property?: PropertyData;
command?: CommandData;
onSuccess?: () => void;
onFailure?: () => void;
}
export interface CommandResult {
customData?: CustomData;
command_type: CommandType;
channel: number;
return_code: number;
}
export interface CmdNotifyPayload {
cmd: number;
payload: ESLStationP2PThroughData | ESLAdvancedLockStatusNotification | SmartSafeSettingsNotification | SmartSafeStatusNotification | ESLBleV12P2PThroughData | EntrySensorStatus | GarageDoorStatus | StorageInfoHB3 | SmartLockP2PSequenceData | string;
payloadLen?: number;
}
export interface ESLStationP2PThroughData {
channel?: number;
lock_cmd: number;
lock_payload: string;
seq_num?: number;
stationSn?: string;
}
export interface ESLAdvancedLockStatusNotification {
code: number;
slBattery: string;
slState: string;
trigger: number;
}
export interface ESLAdvancedLockStatusNotificationT8530 extends ESLAdvancedLockStatusNotification {
slOpenDirection: string;
}
export interface SmartSafeSettingsNotification {
data: string;
prj_id: number;
}
export interface SmartSafeStatusNotification {
event_type: number;
event_time: number;
event_value: number | SmartSafeEventValueDetail;
}
export interface SmartSafeNotificationResponse {
versionCode: number;
commandCode: number;
packageFlag: number;
dataType: number;
responseCode: number;
data: Buffer;
}
export interface LockAdvancedOnOffRequestBasePayload {
shortUserId: string;
slOperation: number;
userId: string;
userName: string;
}
export interface LockAdvancedOnOffRequestPayload extends LockAdvancedOnOffRequestBasePayload {
seq_num: number;
}
export interface AdvancedLockSetParamsType {
[index: string]: unknown;
autoLockTime: number;
isAutoLock: number;
isLockNotification: number;
isNotification: number;
isOneTouchLock: number;
isSchedule: number;
isScramblePasscode: number;
isUnLockNotification: number;
isWrongTryProtect: number;
lockDownTime: number;
lockSound: number;
paramType: number;
scheduleEnd: string;
scheduleStart: string;
wrongTryTime: number;
seq_num: number;
}
export interface AdvancedLockSetParamsTypeT8520 {
[index: string]: unknown;
autoLockTime: number;
isAutoLock: number;
isLockNotification: number;
isNotification: number;
isOneTouchLock: number;
isSchedule: number;
isScramblePasscode: number;
isUnLockNotification: number;
isWrongTryProtect: number;
lockDownTime: number;
lockOpenDirection: number;
lockVolume: number;
nightVisionEnhance: number;
openLeftAlarmEnable: number;
openLeftAlarmScheduleEnd: string;
openLeftAlarmScheduleStart: string;
openLeftAlarmScheduled: number;
openLeftAlarmTimer: number;
openLeftAlarmWays: number;
paramType: number;
scheduleEnd: string;
scheduleStart: string;
tamperAlarmEnable: number;
tamperAlarmScheduleEnd: string;
tamperAlarmScheduleStart: string;
tamperAlarmScheduled: number;
tamperAlarmWays: number;
wrongTryTime: number;
}
export interface LockP2PCommandType {
commandType: CommandType;
value: string;
channel: number;
aesKey: string;
}
export interface LockP2PCommandPayloadType {
key: string;
account_id: string;
cmd: CommandType;
mChannel: number;
mValue3: number;
payload: string;
}
export interface ESLBleV12P2PThroughData {
dev_sn: string;
lock_payload: string;
}
export interface LockV12P2PCommandPayloadType {
account_id: string;
cmd: CommandType;
mChannel: number;
mValue3: number;
payload: {
apiCommand: number;
lock_payload: string;
seq_num: number;
};
}
export interface LockV12P2PCommandType {
commandType: CommandType;
value: string;
}
export interface SmartSafeP2PCommandPayloadType {
account_id: string;
cmd: CommandType;
mChannel: number;
mValue3: number;
payload: {
data: string;
prj_id: CommandType;
seq_num: number;
};
}
export interface SmartSafeP2PCommandType {
commandType: CommandType;
value: string;
channel: number;
}
export interface CmdDatabaseImageResponse {
file: string;
content: string;
}
export interface EntrySensorStatus {
status: number;
}
export interface GarageDoorStatus {
type: number;
notify_tag: string;
door_id: number;
}
export interface StorageInfoHB3 {
cmd: number;
version: number;
mIntRet: number;
msg: string;
old_storage_label: string;
cur_storage_label: string;
body: StorageInfoBodyHB3;
}
export interface StorageInfoBodyHB3 {
body_version: number;
storage_days: number;
storage_events: number;
con_video_hours: number;
format_transaction: string;
format_errcode: number;
hdd_info: StorageInfoHddHB3;
move_disk_info: StorageInfoMoveDiskInfoHB3;
emmc_info: StorageInfoEmmcHB3;
}
export interface StorageInfoHddHB3 {
serial_number: string;
disk_path: string;
disk_size: number;
system_size: number;
disk_used: number;
video_used: number;
video_size: number;
cur_temperate: number;
parted_status: number;
work_status: number;
hdd_label: string;
health: number;
device_module: string;
hdd_type: number;
}
export interface StorageInfoMoveDiskInfoHB3 {
disk_path: string;
disk_size: number;
disk_used: number;
part_layout_arr: string[];
data: string[];
}
export interface StorageInfoEmmcHB3 {
disk_nominal: number;
disk_size: number;
system_size: number;
disk_used: number;
data_used_percent: number;
swap_size: number;
video_size: number;
video_used: number;
data_partition_size: number;
eol_percent: number;
work_status: number;
health: number;
}
export interface SmartLockP2PCommandPayloadType {
account_id: string;
cmd: CommandType;
mChannel: number;
mValue3: number;
payload: {
apiCommand: number;
lock_payload: string;
seq_num: number;
time: number;
};
}
export interface SmartLockP2PCommandType {
commandType: CommandType;
value: string;
}
export interface SmartLockP2PThroughData {
dev_sn: string;
lock_payload: string;
time: string;
}
export interface SmartLockP2PSequenceData {
lock_cmd: number;
seq_num: number;
dev_sn: string;
bus_type?: number;
}

3
build/p2p/models.js Normal file
View File

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=models.js.map

1
build/p2p/models.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/p2p/models.ts"],"names":[],"mappings":""}

186
build/p2p/session.d.ts vendored Normal file
View File

@ -0,0 +1,186 @@
import { TypedEmitter } from "tiny-typed-emitter";
import * as NodeRSA from "node-rsa";
import { Address, CustomData } from "./models";
import { CommandType, P2PDataType, P2PConnectionType } from "./types";
import { P2PClientProtocolEvents, P2PCommand } from "./interfaces";
import { StationListResponse } from "../http/models";
import { HTTPApi } from "../http/api";
export declare class P2PClientProtocol extends TypedEmitter<P2PClientProtocolEvents> {
private readonly MAX_RETRIES;
private readonly MAX_COMMAND_RESULT_WAIT;
private readonly MAX_GATEWAY_COMMAND_RESULT_WAIT;
private readonly MAX_CONNECTION_TIMEOUT;
private readonly MAX_AKNOWLEDGE_TIMEOUT;
private readonly MAX_LOOKUP_TIMEOUT;
private readonly LOCAL_LOOKUP_RETRY_TIMEOUT;
private readonly LOOKUP_RETRY_TIMEOUT;
private readonly LOOKUP2_TIMEOUT;
private readonly LOOKUP2_RETRY_TIMEOUT;
private readonly MAX_EXPECTED_SEQNO_WAIT;
private readonly HEARTBEAT_INTERVAL;
private readonly MAX_COMMAND_QUEUE_TIMEOUT;
private readonly AUDIO_CODEC_ANALYZE_TIMEOUT;
private readonly KEEPALIVE_INTERVAL;
private readonly ESD_DISCONNECT_TIMEOUT;
private readonly MAX_STREAM_DATA_WAIT;
private readonly RESEND_NOT_ACKNOWLEDGED_COMMAND;
private readonly UDP_RECVBUFFERSIZE_BYTES;
private readonly MAX_PAYLOAD_BYTES;
private readonly MAX_PACKET_BYTES;
private readonly MAX_VIDEO_PACKET_BYTES;
private readonly P2P_DATA_HEADER_BYTES;
private readonly MAX_SEQUENCE_NUMBER;
private readonly LOOP_RUNAWAY_LIMIT;
private readonly SEQUENCE_PROCESSING_BOUNDARY;
private socket;
private binded;
private connected;
private connecting;
private terminating;
private p2pTurnHandshaking;
private p2pTurnConfirmed;
private seqNumber;
private offsetDataSeqNumber;
private videoSeqNumber;
private lockSeqNumber;
private expectedSeqNo;
private currentMessageBuilder;
private currentMessageState;
private talkbackStream?;
private downloadTotalBytes;
private downloadReceivedBytes;
private cloudAddresses;
private messageStates;
private messageVideoStates;
private sendQueue;
private connectTimeout?;
private lookupTimeout?;
private localLookupRetryTimeout?;
private lookupRetryTimeout?;
private lookup2Timeout?;
private lookup2RetryTimeout?;
private heartbeatTimeout?;
private keepaliveTimeout?;
private esdDisconnectTimeout?;
private secondaryCommandTimeout?;
private connectTime;
private lastPong;
private lastPongData;
private connectionType;
private energySavingDevice;
private p2pSeqMapping;
private p2pDataSeqNumber;
private connectAddress;
private localIPAddress;
private preferredIPAddress;
private listeningPort;
private dskKey;
private dskExpiration;
private deviceSNs;
private api;
private rawStation;
private customDataStaging;
private lockPublicKey;
private lockAESKeys;
private channel;
private encryption;
private p2pKey?;
private enableEmbeddedPKCS1Support;
constructor(rawStation: StationListResponse, api: HTTPApi, ipAddress?: string, listeningPort?: number, publicKey?: string, enableEmbeddedPKCS1Support?: boolean);
private _incrementSequence;
private _isBetween;
private _wasSequenceNumberAlreadyProcessed;
private _initialize;
private initializeMessageBuilder;
private initializeMessageState;
private _clearTimeout;
private _clearMessageStateTimeouts;
private _clearMessageVideoStateTimeouts;
private _clearHeartbeatTimeout;
private _clearKeepaliveTimeout;
private _clearConnectTimeout;
private _clearLookupTimeout;
private _clearLocalLookupRetryTimeout;
private _clearLookupRetryTimeout;
private _clearLookup2RetryTimeout;
private _clearLookup2Timeout;
private _clearESDDisconnectTimeout;
private _clearSecondaryCommandTimeout;
private sendMessage;
private _disconnected;
private closeEnergySavingDevice;
private renewDSKKey;
private localLookup;
private cloudLookup;
private cloudLookup2;
private cloudLookupWithTurnServer;
private localLookupByAddress;
private cloudLookupByAddress;
private cloudLookupByAddress2;
private cloudLookupByAddressWithTurnServer;
isConnected(): boolean;
private _startConnectTimeout;
private _connect;
private lookup;
connect(host?: string): Promise<void>;
private sendCamCheck;
private sendCamCheck2;
sendPing(address: Address): Promise<void>;
sendCommandWithIntString(p2pcommand: P2PCommand, customData?: CustomData): void;
sendCommandWithInt(p2pcommand: P2PCommand, customData?: CustomData): void;
sendCommandWithStringPayload(p2pcommand: P2PCommand, customData?: CustomData): void;
sendCommandWithString(p2pcommand: P2PCommand, customData?: CustomData): void;
sendCommandPing(channel?: number): void;
sendCommandDevicePing(channel?: number): void;
sendCommandWithoutData(commandType: CommandType, channel?: number): void;
private sendQueuedMessage;
private sendCommand;
private resendNotAcknowledgedCommand;
private _sendCommand;
private handleMsg;
private parseDataMessage;
private handleData;
private isIFrame;
private waitForStreamData;
private handleDataBinaryAndVideo;
private handleDataControl;
private sendAck;
private getDataType;
close(): Promise<void>;
private getHeartbeatInterval;
private onClose;
private onError;
private scheduleHeartbeat;
private scheduleP2PKeepalive;
getDownloadRSAPrivateKey(): NodeRSA;
setDownloadRSAPrivateKeyPem(pem: string): void;
getRSAPrivateKey(): NodeRSA | null;
private initializeStream;
private endStream;
private endRTSPStream;
private emitStreamStartEvent;
private emitStreamStopEvent;
isStreaming(channel: number, datatype: P2PDataType): boolean;
isLiveStreaming(channel: number): boolean;
private isCurrentlyStreaming;
isRTSPLiveStreaming(channel: number): boolean;
isDownloading(channel: number): boolean;
getLockSequenceNumber(): number;
incLockSequenceNumber(): number;
setConnectionType(type: P2PConnectionType): void;
getConnectionType(): P2PConnectionType;
isEnergySavingDevice(): boolean;
private getDSKKeys;
updateRawStation(value: StationListResponse): void;
private initializeTalkbackStream;
private sendTalkbackAudioFrame;
private onTalkbackStreamClose;
private onTalkbackStreamError;
private _sendVideoData;
isTalkbackOngoing(channel: number): boolean;
startTalkback(channel?: number): void;
stopTalkback(channel?: number): void;
setLockAESKey(commandCode: number, aesKey: string): void;
getLockAESKey(commandCode: number): string | undefined;
isConnecting(): boolean;
}

2678
build/p2p/session.js Normal file

File diff suppressed because it is too large Load Diff

1
build/p2p/session.js.map Normal file

File diff suppressed because one or more lines are too long

8
build/p2p/talkback.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
import { Transform } from "stream";
export declare class TalkbackStream extends Transform {
private isStreaming;
constructor();
_transform(data: Buffer, _encoding: string, callback: (err?: Error | null) => void): void;
startTalkback(): void;
stopTalkback(): void;
}

23
build/p2p/talkback.js Normal file
View File

@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TalkbackStream = void 0;
const stream_1 = require("stream");
class TalkbackStream extends stream_1.Transform {
isStreaming = false;
constructor() {
super();
}
_transform(data, _encoding, callback) {
if (this.isStreaming)
this.push(data);
callback();
}
startTalkback() {
this.isStreaming = true;
}
stopTalkback() {
this.isStreaming = false;
}
}
exports.TalkbackStream = TalkbackStream;
//# sourceMappingURL=talkback.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"talkback.js","sourceRoot":"","sources":["../../src/p2p/talkback.ts"],"names":[],"mappings":";;;AAAA,mCAAmC;AAEnC,MAAa,cAAe,SAAQ,kBAAS;IAEjC,WAAW,GAAG,KAAK,CAAC;IAE5B;QACI,KAAK,EAAE,CAAC;IACZ,CAAC;IAED,UAAU,CAAC,IAAY,EAAE,SAAiB,EAAE,QAAsC;QAC9E,IAAG,IAAI,CAAC,WAAW;YACf,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,QAAQ,EAAE,CAAC;IACf,CAAC;IAEM,aAAa;QAChB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC5B,CAAC;IAEM,YAAY;QACf,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC7B,CAAC;CACJ;AArBD,wCAqBC"}

1164
build/p2p/types.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

1219
build/p2p/types.js Normal file

File diff suppressed because it is too large Load Diff

1
build/p2p/types.js.map Normal file

File diff suppressed because one or more lines are too long

72
build/p2p/utils.d.ts vendored Normal file
View File

@ -0,0 +1,72 @@
import { Socket } from "dgram";
import NodeRSA from "node-rsa";
import { P2PMessageParts, P2PMessageState, P2PQueueMessage, RGBColor } from "./interfaces";
import { CommandType, ESLCommand, LockV12P2PCommand, SmartSafeCommandCode, VideoCodec, EncryptionType, SmartLockP2PCommand, SmartLockFunctionType, SmartLockCommand } from "./types";
import { Address, LockP2PCommandType, SmartSafeNotificationResponse, SmartSafeP2PCommandType } from "./models";
import { DeviceType } from "../http/types";
export declare const MAGIC_WORD = "XZYH";
export declare const isPrivateIp: (ip: string) => boolean;
export declare const getLocalIpAddress: (init?: string) => string;
export declare const isP2PCommandEncrypted: (cmd: CommandType) => boolean;
export declare const getP2PCommandEncryptionKey: (serialNumber: string, p2pDid: string) => string;
export declare const encryptP2PData: (data: Buffer, key: Buffer) => Buffer;
export declare const decryptP2PData: (data: Buffer, key: Buffer) => Buffer;
export declare const paddingP2PData: (data: Buffer, blocksize?: number) => Buffer;
export declare const buildLookupWithKeyPayload: (socket: Socket, p2pDid: string, dskKey: string) => Buffer;
export declare const buildLookupWithKeyPayload2: (p2pDid: string, dskKey: string) => Buffer;
export declare const buildLookupWithKeyPayload3: (p2pDid: string, address: Address, data: Buffer) => Buffer;
export declare const buildCheckCamPayload: (p2pDid: string) => Buffer;
export declare const buildCheckCamPayload2: (p2pDid: string, data: Buffer) => Buffer;
export declare const buildIntCommandPayload: (encryptionType: EncryptionType, encryptionKey: Buffer | undefined, serialNumber: string, p2pDid: string, commandType: CommandType, value: number, strValue?: string, channel?: number) => Buffer;
export declare const buildStringTypeCommandPayload: (encryptionType: EncryptionType, encryptionKey: Buffer | undefined, serialNumber: string, p2pDid: string, commandType: CommandType, strValue: string, strValueSub: string, channel?: number) => Buffer;
export declare const buildIntStringCommandPayload: (encryptionType: EncryptionType, encryptionKey: Buffer | undefined, serialNumber: string, p2pDid: string, commandType: CommandType, value: number, valueSub?: number, strValue?: string, strValueSub?: string, channel?: number) => Buffer;
export declare const sendMessage: (socket: Socket, address: {
host: string;
port: number;
}, msgID: Buffer, payload?: Buffer) => Promise<number>;
export declare const hasHeader: (msg: Buffer, searchedType: Buffer) => boolean;
export declare const buildCommandHeader: (seqNumber: number, commandType: CommandType, p2pDataTypeHeader?: Buffer | null) => Buffer;
export declare const buildCommandWithStringTypePayload: (encryptionType: EncryptionType, encryptionKey: Buffer | undefined, serialNumber: string, p2pDid: string, commandType: CommandType, value: string, channel?: number) => Buffer;
export declare const sortP2PMessageParts: (messages: P2PMessageParts) => Buffer;
export declare const getRSAPrivateKey: (pem: string, enableEmbeddedPKCS1Support?: boolean) => NodeRSA;
export declare const getNewRSAPrivateKey: (enableEmbeddedPKCS1Support?: boolean) => NodeRSA;
export declare const decryptAESData: (hexkey: string, data: Buffer) => Buffer;
export declare const findStartCode: (data: Buffer) => boolean;
export declare const isIFrame: (data: Buffer) => boolean;
export declare const decryptLockAESData: (key: string, iv: string, data: Buffer) => Buffer;
export declare const encryptLockAESData: (key: string, iv: string, data: Buffer) => Buffer;
export declare const generateBasicLockAESKey: (adminID: string, stationSN: string) => string;
export declare const getCurrentTimeInSeconds: () => number;
export declare const generateLockSequence: (deviceType?: DeviceType, serialnumber?: string) => number;
export declare const encodeLockPayload: (data: string) => Buffer;
export declare const getLockVectorBytes: (data: string) => string;
export declare const decodeLockPayload: (data: Buffer) => string;
export declare const decodeBase64: (data: string) => Buffer;
export declare const eslTimestamp: (timestamp_in_sec?: number) => number[];
export declare const generateAdvancedLockAESKey: () => string;
export declare const getVideoCodec: (data: Buffer) => VideoCodec;
export declare const checkT8420: (serialNumber: string) => boolean;
export declare const buildVoidCommandPayload: (channel?: number) => Buffer;
export declare function isP2PQueueMessage(type: P2PQueueMessage | P2PMessageState): type is P2PQueueMessage;
export declare const encryptPayloadData: (data: string | Buffer, key: Buffer, iv: Buffer) => Buffer;
export declare const decryptPayloadData: (data: Buffer, key: Buffer, iv: Buffer) => Buffer;
export declare const eufyKDF: (key: Buffer) => Buffer;
export declare const getAdvancedLockKey: (key: string, publicKey: string) => string;
export declare const getLockV12Key: (key: string, publicKey: string) => string;
export declare const buildTalkbackAudioFrameHeader: (audioData: Buffer, channel?: number) => Buffer;
export declare const decodeP2PCloudIPs: (data: string) => Array<Address>;
export declare const decodeSmartSafeData: (deviceSN: string, data: Buffer) => SmartSafeNotificationResponse;
export declare const getSmartSafeP2PCommand: (deviceSN: string, user_id: string, command: CommandType, intCommand: SmartSafeCommandCode, channel: number, sequence: number, data: Buffer) => SmartSafeP2PCommandType;
export declare const getLockP2PCommand: (deviceSN: string, user_id: string, command: CommandType, channel: number, lockPublicKey: string, payload: any) => LockP2PCommandType;
export declare const getLockV12P2PCommand: (deviceSN: string, user_id: string, command: CommandType | ESLCommand, channel: number, lockPublicKey: string, sequence: number, data: Buffer) => LockV12P2PCommand;
export declare const DecimalToRGBColor: (color: number) => RGBColor;
export declare const RGBColorToDecimal: (color: RGBColor) => number;
export declare const getNullTerminatedString: (data: Buffer, encoding?: BufferEncoding) => string;
export declare const isUsbCharging: (value: number) => boolean;
export declare const isSolarCharging: (value: number) => boolean;
export declare const isPlugSolarCharging: (value: number) => boolean;
export declare const isCharging: (value: number) => boolean;
export declare const getSmartLockCurrentTimeInSeconds: () => number;
export declare const generateSmartLockAESKey: (adminUserId: string, time: number) => Buffer;
export declare const getSmartLockP2PCommand: (deviceSN: string, user_id: string, command: CommandType | SmartLockCommand, channel: number, sequence: number, data: Buffer, functionType?: SmartLockFunctionType) => SmartLockP2PCommand;
export declare const readNullTerminatedBuffer: (input: Buffer) => Buffer;

824
build/p2p/utils.js Normal file
View File

@ -0,0 +1,824 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLockP2PCommand = exports.getSmartSafeP2PCommand = exports.decodeSmartSafeData = exports.decodeP2PCloudIPs = exports.buildTalkbackAudioFrameHeader = exports.getLockV12Key = exports.getAdvancedLockKey = exports.eufyKDF = exports.decryptPayloadData = exports.encryptPayloadData = exports.buildVoidCommandPayload = exports.checkT8420 = exports.getVideoCodec = exports.generateAdvancedLockAESKey = exports.eslTimestamp = exports.decodeBase64 = exports.decodeLockPayload = exports.getLockVectorBytes = exports.encodeLockPayload = exports.generateLockSequence = exports.getCurrentTimeInSeconds = exports.generateBasicLockAESKey = exports.encryptLockAESData = exports.decryptLockAESData = exports.isIFrame = exports.findStartCode = exports.decryptAESData = exports.getNewRSAPrivateKey = exports.getRSAPrivateKey = exports.sortP2PMessageParts = exports.buildCommandWithStringTypePayload = exports.buildCommandHeader = exports.hasHeader = exports.sendMessage = exports.buildIntStringCommandPayload = exports.buildStringTypeCommandPayload = exports.buildIntCommandPayload = exports.buildCheckCamPayload2 = exports.buildCheckCamPayload = exports.buildLookupWithKeyPayload3 = exports.buildLookupWithKeyPayload2 = exports.buildLookupWithKeyPayload = exports.paddingP2PData = exports.decryptP2PData = exports.encryptP2PData = exports.getP2PCommandEncryptionKey = exports.isP2PCommandEncrypted = exports.getLocalIpAddress = exports.isPrivateIp = exports.MAGIC_WORD = void 0;
exports.readNullTerminatedBuffer = exports.getSmartLockP2PCommand = exports.generateSmartLockAESKey = exports.getSmartLockCurrentTimeInSeconds = exports.isCharging = exports.isPlugSolarCharging = exports.isSolarCharging = exports.isUsbCharging = exports.getNullTerminatedString = exports.RGBColorToDecimal = exports.DecimalToRGBColor = exports.getLockV12P2PCommand = void 0;
exports.isP2PQueueMessage = isP2PQueueMessage;
const node_rsa_1 = __importDefault(require("node-rsa"));
const CryptoJS = __importStar(require("crypto-js"));
const crypto_1 = require("crypto");
const os = __importStar(require("os"));
const types_1 = require("./types");
const device_1 = require("../http/device");
const ble_1 = require("./ble");
const logging_1 = require("../logging");
exports.MAGIC_WORD = "XZYH";
const isPrivateIp = (ip) => /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^f[cd][0-9a-f]{2}:/i.test(ip) ||
/^fe80:/i.test(ip) ||
/^::1$/.test(ip) ||
/^::$/.test(ip);
exports.isPrivateIp = isPrivateIp;
const stringWithLength = (input, chunkLength = 128) => {
const stringAsBuffer = Buffer.from(input);
const bufferSize = stringAsBuffer.byteLength < chunkLength ? chunkLength : Math.ceil(stringAsBuffer.byteLength / chunkLength) * chunkLength;
const result = Buffer.alloc(bufferSize);
stringAsBuffer.copy(result);
return result;
};
const getLocalIpAddress = (init = "") => {
const ifaces = os.networkInterfaces();
let localAddress = init;
for (const name in ifaces) {
const iface = ifaces[name].filter(function (details) {
return details.family === "IPv4" && details.internal === false;
});
if (iface.length > 0) {
localAddress = iface[0].address;
break;
}
}
return localAddress;
};
exports.getLocalIpAddress = getLocalIpAddress;
const p2pDidToBuffer = (p2pDid) => {
const p2pArray = p2pDid.split("-");
const buf1 = stringWithLength(p2pArray[0], 8);
const buf2 = Buffer.allocUnsafe(4);
buf2.writeUInt32BE(Number.parseInt(p2pArray[1]), 0);
const buf3 = stringWithLength(p2pArray[2], 8);
return Buffer.concat([buf1, buf2, buf3], 20);
};
const isP2PCommandEncrypted = function (cmd) {
return [1001, 1002, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1015, 1017, 1019, 1035, 1045, 1056, 1145, 1146, 1152, 1200, 1207, 1210, 1213, 1214, 1226, 1227, 1229, 1230, 1233, 1236, 1240, 1241, 1243, 1246, 1272, 1273, 1275, 1400, 1401, 1402, 1403, 1408, 1409, 1410, 1412, 1413, 1506, 1507, 1607, 1609, 1610, 1611, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1013, 1202, 1205, 1206, 1024, 1025, 1132, 1215, 1216, 1217, 1414, 1026, 1164, 1201, 1027, 1047, 1048, 1029, 1034, 1036, 1043, 1057, 1203, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1232, 1234, 1235, 1237, 1238, 1248, 1253, 1257, 1269, 1800, 1037, 1040, 1038, 1049, 1050, 1051, 1054, 1060, 1204, 1254, 1255, 1256, 1258, 1259, 1260, 1261, 1262, 1264, 1271, 1350, 1404, 1101, 1106, 1108, 1110, 1111, 1112, 1113, 1114, 1116, 1117, 1118, 1119, 1121, 1103, 1129, 1211, 1228, 1231, 1242, 1249, 1250, 1251, 1252, 1405, 1406, 1407, 1700].includes(cmd);
};
exports.isP2PCommandEncrypted = isP2PCommandEncrypted;
const getP2PCommandEncryptionKey = function (serialNumber, p2pDid) {
return `${serialNumber.slice(-7)}${p2pDid.substring(p2pDid.indexOf("-"), p2pDid.indexOf("-") + 9)}`;
};
exports.getP2PCommandEncryptionKey = getP2PCommandEncryptionKey;
const encryptP2PData = (data, key) => {
const cipher = (0, crypto_1.createCipheriv)("aes-128-ecb", key, null);
cipher.setAutoPadding(false);
return Buffer.concat([
cipher.update(data),
cipher.final()
]);
};
exports.encryptP2PData = encryptP2PData;
const decryptP2PData = (data, key) => {
const decipher = (0, crypto_1.createDecipheriv)("aes-128-ecb", key, null);
decipher.setAutoPadding(false);
return Buffer.concat([
decipher.update(data),
decipher.final()
]);
};
exports.decryptP2PData = decryptP2PData;
const paddingP2PData = (data, blocksize = 16) => {
const bufferSize = data.byteLength < blocksize ? blocksize : Math.ceil(data.byteLength / blocksize) * blocksize;
const result = Buffer.alloc(bufferSize);
data.copy(result);
return result;
};
exports.paddingP2PData = paddingP2PData;
const buildLookupWithKeyPayload = (socket, p2pDid, dskKey) => {
const p2pDidBuffer = p2pDidToBuffer(p2pDid);
const addressInfo = socket.address();
const port = addressInfo.port;
const portAsBuffer = Buffer.allocUnsafe(2);
portAsBuffer.writeUInt16LE(port, 0);
//const ip = socket.address().address;
const ip = (0, exports.getLocalIpAddress)(addressInfo.address);
const temp_buff = [];
ip.split(".").reverse().forEach(element => {
temp_buff.push(Number.parseInt(element));
});
const ipAsBuffer = Buffer.from(temp_buff);
const splitter = Buffer.from([0x00, 0x02]);
const magic = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00]);
const dskKeyAsBuffer = Buffer.from(dskKey);
const fourEmpty = Buffer.from([0x00, 0x00, 0x00, 0x00]);
return Buffer.concat([p2pDidBuffer, splitter, portAsBuffer, ipAsBuffer, magic, dskKeyAsBuffer, fourEmpty]);
};
exports.buildLookupWithKeyPayload = buildLookupWithKeyPayload;
const buildLookupWithKeyPayload2 = (p2pDid, dskKey) => {
const p2pDidBuffer = p2pDidToBuffer(p2pDid);
const dskKeyAsBuffer = Buffer.from(dskKey);
const fourEmpty = Buffer.from([0x00, 0x00, 0x00, 0x00]);
return Buffer.concat([p2pDidBuffer, dskKeyAsBuffer, fourEmpty]);
};
exports.buildLookupWithKeyPayload2 = buildLookupWithKeyPayload2;
const buildLookupWithKeyPayload3 = (p2pDid, address, data) => {
const p2pDidBuffer = p2pDidToBuffer(p2pDid);
const portAsBuffer = Buffer.allocUnsafe(2);
portAsBuffer.writeUInt16LE(address.port, 0);
const temp_buff = [];
address.host.split(".").reverse().forEach(element => {
temp_buff.push(Number.parseInt(element));
});
const ipAsBuffer = Buffer.from(temp_buff);
const splitter = Buffer.from([0x00, 0x02]);
const eightEmpty = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
return Buffer.concat([p2pDidBuffer, splitter, portAsBuffer, ipAsBuffer, eightEmpty, data]);
};
exports.buildLookupWithKeyPayload3 = buildLookupWithKeyPayload3;
const buildCheckCamPayload = (p2pDid) => {
const p2pDidBuffer = p2pDidToBuffer(p2pDid);
const magic = Buffer.from([0x00, 0x00, 0x00]);
return Buffer.concat([p2pDidBuffer, magic]);
};
exports.buildCheckCamPayload = buildCheckCamPayload;
const buildCheckCamPayload2 = (p2pDid, data) => {
const p2pDidBuffer = p2pDidToBuffer(p2pDid);
const magic = Buffer.from([0x00, 0x00, 0x00, 0x00]);
return Buffer.concat([data, p2pDidBuffer, magic]);
};
exports.buildCheckCamPayload2 = buildCheckCamPayload2;
const buildIntCommandPayload = (encryptionType, encryptionKey, serialNumber, p2pDid, commandType, value, strValue = "", channel = 255) => {
const emptyBuffer = Buffer.from([0x00, 0x00]);
const magicBuffer = Buffer.from([0x01, 0x00]);
const encrypted = (0, exports.isP2PCommandEncrypted)(commandType) && encryptionType !== types_1.EncryptionType.NONE && encryptionKey?.length === 16;
const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]);
const valueBuffer = Buffer.allocUnsafe(4);
valueBuffer.writeUInt32LE(value, 0);
const headerBuffer = Buffer.allocUnsafe(2);
const strValueBuffer = strValue.length === 0 ? Buffer.from([]) : stringWithLength(strValue);
const tmpDataBuffer = Buffer.concat([
valueBuffer,
strValueBuffer
]);
const dataBuffer = encrypted ? (0, exports.paddingP2PData)(tmpDataBuffer) : tmpDataBuffer;
headerBuffer.writeUInt16LE(dataBuffer.length, 0);
return Buffer.concat([
headerBuffer,
emptyBuffer,
magicBuffer,
channelBuffer,
emptyBuffer,
encrypted ? (0, exports.encryptP2PData)(dataBuffer, encryptionKey) : dataBuffer
]);
};
exports.buildIntCommandPayload = buildIntCommandPayload;
const buildStringTypeCommandPayload = (encryptionType, encryptionKey, serialNumber, p2pDid, commandType, strValue, strValueSub, channel = 255) => {
const emptyBuffer = Buffer.from([0x00, 0x00]);
const magicBuffer = Buffer.from([0x01, 0x00]);
const encrypted = (0, exports.isP2PCommandEncrypted)(commandType) && encryptionType !== types_1.EncryptionType.NONE && encryptionKey?.length === 16;
const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]);
const someBuffer = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00]);
const strValueBuffer = stringWithLength(strValue);
const strValueSubBuffer = stringWithLength(strValueSub);
const headerBuffer = Buffer.allocUnsafe(2);
const tmpDataBuffer = Buffer.concat([
someBuffer,
strValueBuffer,
strValueSubBuffer
]);
const dataBuffer = encrypted ? (0, exports.paddingP2PData)(tmpDataBuffer) : tmpDataBuffer;
headerBuffer.writeUInt16LE(dataBuffer.length, 0);
return Buffer.concat([
headerBuffer,
emptyBuffer,
magicBuffer,
channelBuffer,
emptyBuffer,
encrypted ? (0, exports.encryptP2PData)(dataBuffer, encryptionKey) : dataBuffer
]);
};
exports.buildStringTypeCommandPayload = buildStringTypeCommandPayload;
const buildIntStringCommandPayload = (encryptionType, encryptionKey, serialNumber, p2pDid, commandType, value, valueSub = 0, strValue = "", strValueSub = "", channel = 0) => {
const emptyBuffer = Buffer.from([0x00, 0x00]);
const magicBuffer = Buffer.from([0x01, 0x00]);
const encrypted = (0, exports.isP2PCommandEncrypted)(commandType) && encryptionType !== types_1.EncryptionType.NONE && encryptionKey?.length === 16;
const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]);
const someintBuffer = Buffer.allocUnsafe(4);
someintBuffer.writeUInt32LE(valueSub, 0);
const valueBuffer = Buffer.allocUnsafe(4);
valueBuffer.writeUInt32LE(value, 0);
const strValueBuffer = strValue.length === 0 ? Buffer.from([]) : stringWithLength(strValue);
const strValueSubBuffer = strValueSub.length === 0 ? Buffer.from([]) : stringWithLength(strValueSub);
const headerBuffer = Buffer.allocUnsafe(2);
const tmpDataBuffer = Buffer.concat([
someintBuffer,
valueBuffer,
strValueBuffer,
strValueSubBuffer
]);
const dataBuffer = encrypted ? (0, exports.paddingP2PData)(tmpDataBuffer) : tmpDataBuffer;
headerBuffer.writeUInt16LE(dataBuffer.length, 0);
return Buffer.concat([
headerBuffer,
emptyBuffer,
magicBuffer,
channelBuffer,
emptyBuffer,
encrypted ? (0, exports.encryptP2PData)(dataBuffer, encryptionKey) : dataBuffer
]);
};
exports.buildIntStringCommandPayload = buildIntStringCommandPayload;
const sendMessage = async (socket, address, msgID, payload) => {
if (!payload)
payload = Buffer.from([]);
const payloadLen = Buffer.allocUnsafe(2);
payloadLen.writeUInt16BE(payload.length, 0);
const message = Buffer.concat([msgID, payloadLen, payload], 4 + payload.length);
return new Promise((resolve, reject) => {
socket.send(message, address.port, address.host, (err, bytes) => {
return err ? reject(err) : resolve(bytes);
});
});
};
exports.sendMessage = sendMessage;
const hasHeader = (msg, searchedType) => {
const header = Buffer.allocUnsafe(2);
msg.copy(header, 0, 0, 2);
return Buffer.compare(header, searchedType) === 0;
};
exports.hasHeader = hasHeader;
const buildCommandHeader = (seqNumber, commandType, p2pDataTypeHeader = null) => {
let dataTypeBuffer = types_1.P2PDataTypeHeader.DATA;
if (p2pDataTypeHeader !== null &&
(Buffer.compare(p2pDataTypeHeader, types_1.P2PDataTypeHeader.DATA) === 0 ||
Buffer.compare(p2pDataTypeHeader, types_1.P2PDataTypeHeader.BINARY) === 0 ||
Buffer.compare(p2pDataTypeHeader, types_1.P2PDataTypeHeader.CONTROL) === 0 ||
Buffer.compare(p2pDataTypeHeader, types_1.P2PDataTypeHeader.VIDEO) === 0)) {
dataTypeBuffer = p2pDataTypeHeader;
}
const seqAsBuffer = Buffer.allocUnsafe(2);
seqAsBuffer.writeUInt16BE(seqNumber, 0);
const magicString = Buffer.from(exports.MAGIC_WORD);
const commandTypeBuffer = Buffer.allocUnsafe(2);
commandTypeBuffer.writeUInt16LE(commandType, 0);
return Buffer.concat([dataTypeBuffer, seqAsBuffer, magicString, commandTypeBuffer]);
};
exports.buildCommandHeader = buildCommandHeader;
const buildCommandWithStringTypePayload = (encryptionType, encryptionKey, serialNumber, p2pDid, commandType, value, channel = 0) => {
const headerBuffer = Buffer.allocUnsafe(2);
const emptyBuffer = Buffer.from([0x00, 0x00]);
const magicBuffer = Buffer.from([0x01, 0x00]);
const encrypted = (0, exports.isP2PCommandEncrypted)(commandType) && encryptionType !== types_1.EncryptionType.NONE && encryptionKey?.length === 16;
const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]);
const dataBuffer = encrypted ? (0, exports.paddingP2PData)(Buffer.from(value)) : Buffer.from(value);
headerBuffer.writeUInt16LE(dataBuffer.length, 0);
return Buffer.concat([
headerBuffer,
emptyBuffer,
magicBuffer,
channelBuffer,
emptyBuffer,
encrypted ? (0, exports.encryptP2PData)(dataBuffer, encryptionKey) : dataBuffer
]);
};
exports.buildCommandWithStringTypePayload = buildCommandWithStringTypePayload;
const sortP2PMessageParts = (messages) => {
let completeMessage = Buffer.from([]);
Object.keys(messages).map(Number)
.sort((a, b) => {
if (Math.abs(a - b) > 65000) {
if (a < b) {
return 1;
}
else if (b < a) {
return -1;
}
}
return a - b;
}) // assure the seqNumbers are in correct order
.forEach((key) => {
completeMessage = Buffer.concat([completeMessage, messages[key]]);
});
return completeMessage;
};
exports.sortP2PMessageParts = sortP2PMessageParts;
const getRSAPrivateKey = (pem, enableEmbeddedPKCS1Support = false) => {
const key = new node_rsa_1.default();
if (pem.indexOf("\n") !== -1) {
pem = pem.replaceAll("\n", "");
}
if (pem.startsWith("-----BEGIN RSA PRIVATE KEY-----")) {
pem = pem.replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", "");
}
key.importKey(pem, "pkcs8");
const options = {
encryptionScheme: "pkcs1"
};
if (enableEmbeddedPKCS1Support) {
options.environment = "browser";
}
key.setOptions(options);
return key;
};
exports.getRSAPrivateKey = getRSAPrivateKey;
const getNewRSAPrivateKey = (enableEmbeddedPKCS1Support = false) => {
const key = new node_rsa_1.default({ b: 1024 });
const options = {
encryptionScheme: "pkcs1"
};
if (enableEmbeddedPKCS1Support) {
options.environment = "browser";
}
key.setOptions(options);
return key;
};
exports.getNewRSAPrivateKey = getNewRSAPrivateKey;
const decryptAESData = (hexkey, data) => {
const key = CryptoJS.enc.Hex.parse(hexkey);
const cipherParams = CryptoJS.lib.CipherParams.create({
ciphertext: CryptoJS.enc.Hex.parse(data.toString("hex"))
});
const decrypted = CryptoJS.AES.decrypt(cipherParams, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.NoPadding
});
return Buffer.from(CryptoJS.enc.Hex.stringify(decrypted), "hex");
};
exports.decryptAESData = decryptAESData;
const findStartCode = (data) => {
if (data !== undefined && data.length > 0) {
if (data.length >= 4) {
const startcode = [...data.subarray(0, 4)];
if ((startcode[0] === 0 && startcode[1] === 0 && startcode[2] === 1) || (startcode[0] === 0 && startcode[1] === 0 && startcode[2] === 0 && startcode[3] === 1))
return true;
}
else if (data.length === 3) {
const startcode = [...data.subarray(0, 3)];
if ((startcode[0] === 0 && startcode[1] === 0 && startcode[2] === 1))
return true;
}
}
return false;
};
exports.findStartCode = findStartCode;
const isIFrame = (data) => {
const validValues = [64, 66, 68, 78, 101, 103];
if (data !== undefined && data.length > 0) {
if (data.length >= 5) {
const startcode = [...data.subarray(0, 5)];
if (validValues.includes(startcode[3]) || validValues.includes(startcode[4]))
return true;
}
}
return false;
};
exports.isIFrame = isIFrame;
const decryptLockAESData = (key, iv, data) => {
const ekey = CryptoJS.enc.Hex.parse(key);
const eiv = CryptoJS.enc.Hex.parse(iv);
const cipherParams = CryptoJS.lib.CipherParams.create({
ciphertext: CryptoJS.enc.Hex.parse(data.toString("hex"))
});
const decrypted = CryptoJS.AES.decrypt(cipherParams, ekey, {
iv: eiv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return Buffer.from(CryptoJS.enc.Hex.stringify(decrypted), "hex");
};
exports.decryptLockAESData = decryptLockAESData;
const encryptLockAESData = (key, iv, data) => {
const ekey = CryptoJS.enc.Hex.parse(key);
const eiv = CryptoJS.enc.Hex.parse(iv);
const encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Hex.parse(data.toString("hex")), ekey, {
iv: eiv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return Buffer.from(CryptoJS.enc.Hex.stringify(encrypted.ciphertext), "hex");
};
exports.encryptLockAESData = encryptLockAESData;
const generateBasicLockAESKey = (adminID, stationSN) => {
const encoder = new TextEncoder();
const encOwnerID = encoder.encode(adminID);
const encStationSerial = encoder.encode(stationSN);
const array = [104, -83, -72, 38, -107, 99, -110, 17, -95, -121, 54, 57, -46, -98, -111, 89];
for (let i = 0; i < 16; i++) {
array[i] = (array[i] + encStationSerial[((encStationSerial[i] * 3) + 5) % 16] + encOwnerID[((encOwnerID[i] * 3) + 5) % 40]);
}
return Buffer.from(array).toString("hex");
};
exports.generateBasicLockAESKey = generateBasicLockAESKey;
const getCurrentTimeInSeconds = function () {
return Math.trunc(new Date().getTime() / 1000);
};
exports.getCurrentTimeInSeconds = getCurrentTimeInSeconds;
const generateLockSequence = (deviceType, serialnumber) => {
if (deviceType !== undefined && serialnumber !== undefined)
if (device_1.Device.isLockWifi(deviceType, serialnumber) || device_1.Device.isLockWifiNoFinger(deviceType))
return Math.trunc(Math.random() * 1000);
return (0, exports.getCurrentTimeInSeconds)();
};
exports.generateLockSequence = generateLockSequence;
const encodeLockPayload = (data) => {
const encoder = new TextEncoder();
const encData = encoder.encode(data);
const length = encData.length;
const old_buffer = Buffer.from(encData);
if (length % 16 == 0) {
return old_buffer;
}
const new_length = (Math.trunc(length / 16) + 1) * 16;
const new_buffer = Buffer.alloc(new_length);
old_buffer.copy(new_buffer, 0);
return new_buffer;
};
exports.encodeLockPayload = encodeLockPayload;
const getLockVectorBytes = (data) => {
const encoder = new TextEncoder();
const encData = encoder.encode(data);
const old_buffer = Buffer.from(encData);
if (encData.length >= 16)
return old_buffer.toString("hex");
const new_buffer = Buffer.alloc(16);
old_buffer.copy(new_buffer, 0);
return new_buffer.toString("hex");
};
exports.getLockVectorBytes = getLockVectorBytes;
const decodeLockPayload = (data) => {
const decoder = new TextDecoder();
return decoder.decode(data);
};
exports.decodeLockPayload = decodeLockPayload;
const decodeBase64 = (data) => {
const base64RegExp = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/;
if (base64RegExp.test(data))
return Buffer.from(data, "base64");
return Buffer.from(data);
};
exports.decodeBase64 = decodeBase64;
const eslTimestamp = function (timestamp_in_sec = new Date().getTime() / 1000) {
const array = [];
for (let pos = 0; pos < 4; pos++) {
array[pos] = ((timestamp_in_sec >> (pos * 8)) & 255);
}
return array;
};
exports.eslTimestamp = eslTimestamp;
const generateAdvancedLockAESKey = () => {
const randomBytesArray = [...(0, crypto_1.randomBytes)(16)];
let result = "";
for (let pos = 0; pos < randomBytesArray.length; pos++) {
result += "0123456789ABCDEF".charAt((randomBytesArray[pos] >> 4) & 15);
result += "0123456789ABCDEF".charAt(randomBytesArray[pos] & 15);
}
return result;
};
exports.generateAdvancedLockAESKey = generateAdvancedLockAESKey;
const getVideoCodec = (data) => {
if (data !== undefined && data.length > 0) {
if (data.length >= 5) {
const h265Values = [38, 64, 66, 68, 78];
const startcode = [...data.subarray(0, 5)];
if (h265Values.includes(startcode[3]) || h265Values.includes(startcode[4])) {
return types_1.VideoCodec.H265;
}
else if (startcode[3] === 103 || startcode[4] === 103) {
return types_1.VideoCodec.H264;
}
}
return types_1.VideoCodec.H264;
}
return types_1.VideoCodec.UNKNOWN; // Maybe return h264 as Eufy does?
};
exports.getVideoCodec = getVideoCodec;
const checkT8420 = (serialNumber) => {
if (!(serialNumber !== undefined && serialNumber !== null && serialNumber.length > 0 && serialNumber.startsWith("T8420")) || serialNumber.length <= 7 || serialNumber[6] != "6") {
return false;
}
return true;
};
exports.checkT8420 = checkT8420;
const buildVoidCommandPayload = (channel = 255) => {
const headerBuffer = Buffer.from([0x00, 0x00]);
const emptyBuffer = Buffer.from([0x00, 0x00]);
const magicBuffer = Buffer.from([0x01, 0x00]);
const channelBuffer = Buffer.from([channel, 0x00]);
return Buffer.concat([
headerBuffer,
emptyBuffer,
magicBuffer,
channelBuffer,
emptyBuffer
]);
};
exports.buildVoidCommandPayload = buildVoidCommandPayload;
function isP2PQueueMessage(type) {
return type.p2pCommand !== undefined;
}
const encryptPayloadData = (data, key, iv) => {
const cipher = (0, crypto_1.createCipheriv)("aes-128-cbc", key, iv);
return Buffer.concat([
cipher.update(data),
cipher.final()
]);
};
exports.encryptPayloadData = encryptPayloadData;
const decryptPayloadData = (data, key, iv) => {
const cipher = (0, crypto_1.createDecipheriv)("aes-128-cbc", key, iv);
return Buffer.concat([
cipher.update(data),
cipher.final()
]);
};
exports.decryptPayloadData = decryptPayloadData;
const eufyKDF = (key) => {
const hash_length = 32;
const digest_length = 48;
const staticBuffer = Buffer.from("ECIES");
const steps = Math.ceil(digest_length / hash_length);
const buffer = Buffer.alloc(hash_length * steps);
let tmpBuffer = staticBuffer;
for (let step = 0; step < steps; ++step) {
tmpBuffer = (0, crypto_1.createHmac)("sha256", key).update(tmpBuffer).digest();
const digest = (0, crypto_1.createHmac)("sha256", key).update(Buffer.concat([tmpBuffer, staticBuffer])).digest();
digest.copy(buffer, hash_length * step);
}
return buffer.subarray(0, digest_length);
};
exports.eufyKDF = eufyKDF;
const getAdvancedLockKey = (key, publicKey) => {
const ecdh = (0, crypto_1.createECDH)("prime256v1");
ecdh.generateKeys();
const secret = ecdh.computeSecret(Buffer.concat([Buffer.from("04", "hex"), Buffer.from(publicKey, "hex")]));
const randomValue = (0, crypto_1.randomBytes)(16);
const derivedKey = (0, exports.eufyKDF)(secret);
const encryptedData = (0, exports.encryptPayloadData)(key, derivedKey.subarray(0, 16), randomValue);
const hmac = (0, crypto_1.createHmac)("sha256", derivedKey.subarray(16));
hmac.update(randomValue);
hmac.update(encryptedData);
const hmacDigest = hmac.digest();
return Buffer.concat([Buffer.from(ecdh.getPublicKey("hex", "compressed"), "hex"), randomValue, encryptedData, hmacDigest]).toString("hex");
};
exports.getAdvancedLockKey = getAdvancedLockKey;
const getLockV12Key = (key, publicKey) => {
const ecdh = (0, crypto_1.createECDH)("prime256v1");
ecdh.generateKeys();
const secret = ecdh.computeSecret(Buffer.concat([Buffer.from("04", "hex"), Buffer.from(publicKey, "hex")]));
const randomValue = (0, crypto_1.randomBytes)(16);
const derivedKey = (0, exports.eufyKDF)(secret);
const encryptedData = (0, exports.encryptPayloadData)(Buffer.from(key, "hex"), derivedKey.subarray(0, 16), randomValue);
const hmac = (0, crypto_1.createHmac)("sha256", derivedKey.subarray(16));
hmac.update(randomValue);
hmac.update(encryptedData);
const hmacDigest = hmac.digest();
return Buffer.concat([Buffer.from(ecdh.getPublicKey("hex", "compressed"), "hex"), randomValue, encryptedData, hmacDigest]).toString("hex");
};
exports.getLockV12Key = getLockV12Key;
const buildTalkbackAudioFrameHeader = (audioData, channel = 0) => {
const audioDataLength = Buffer.allocUnsafe(4);
audioDataLength.writeUInt32LE(audioData.length);
const unknown1 = Buffer.alloc(1);
const audioType = Buffer.alloc(1);
const audioSeq = Buffer.alloc(2);
const audioTimestamp = Buffer.alloc(8);
const audioDataHeader = Buffer.concat([audioDataLength, unknown1, audioType, audioSeq, audioTimestamp]);
const bytesToRead = Buffer.allocUnsafe(4);
bytesToRead.writeUInt32LE(audioData.length + audioDataHeader.length);
const magicBuffer = Buffer.from([0x01, 0x00]);
const channelBuffer = Buffer.from([channel, 0x00]);
const emptyBuffer = Buffer.from([0x00, 0x00]);
return Buffer.concat([
bytesToRead,
magicBuffer,
channelBuffer,
emptyBuffer,
audioDataHeader
]);
};
exports.buildTalkbackAudioFrameHeader = buildTalkbackAudioFrameHeader;
const decodeP2PCloudIPs = (data) => {
const lookupTable = Buffer.from("4959433db5bf6da347534f6165e371e9677f02030badb3892b2f35c16b8b959711e5a70deff1050783fb9d3bc5c713171d1f2529d3df", "hex");
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [encoded, name = "name not included"] = data.split(":");
const output = Buffer.alloc(encoded.length / 2);
for (let i = 0; i <= data.length / 2; i++) {
let z = 0x39; // 57 // '9'
for (let j = 0; j < i; j++) {
z = z ^ output[j];
}
const x = (data.charCodeAt(i * 2 + 1) - "A".charCodeAt(0));
const y = (data.charCodeAt(i * 2) - "A".charCodeAt(0)) * 0x10;
output[i] = z ^ lookupTable[i % lookupTable.length] ^ x + y;
}
const result = [];
output.toString("utf8").split(",").forEach((ip) => {
if (ip !== "") {
result.push({ host: ip, port: 32100 });
}
});
return result;
};
exports.decodeP2PCloudIPs = decodeP2PCloudIPs;
const decodeSmartSafeData = function (deviceSN, data) {
const response = ble_1.BleCommandFactory.parseSmartSafe(data);
return {
versionCode: response.getVersionCode(),
dataType: response.getDataType(),
commandCode: response.getCommandCode(),
packageFlag: response.getPackageFlag(),
responseCode: response.getResponseCode(),
data: (0, exports.decryptPayloadData)(response.getData(), Buffer.from(deviceSN), Buffer.from(device_1.SmartSafe.IV, "hex"))
};
};
exports.decodeSmartSafeData = decodeSmartSafeData;
const getSmartSafeP2PCommand = function (deviceSN, user_id, command, intCommand, channel, sequence, data) {
const encPayload = (0, exports.encryptPayloadData)(data, Buffer.from(deviceSN), Buffer.from(device_1.SmartSafe.IV, "hex"));
const bleCommand = new ble_1.BleCommandFactory()
.setVersionCode(device_1.SmartSafe.VERSION_CODE)
.setCommandCode(intCommand)
.setDataType(-1)
.setData(encPayload)
.getSmartSafeCommand();
logging_1.rootP2PLogger.debug(`Generate smart safe command`, { deviceSN: deviceSN, userId: user_id, command: command, intCommand: intCommand, channel: channel, sequence: sequence, data: data.toString("hex") });
return {
commandType: types_1.CommandType.CMD_SET_PAYLOAD,
value: JSON.stringify({
account_id: user_id,
cmd: command,
mChannel: channel,
mValue3: 0,
payload: {
data: bleCommand.toString("hex"),
prj_id: command,
seq_num: sequence,
}
}),
channel: channel
};
};
exports.getSmartSafeP2PCommand = getSmartSafeP2PCommand;
const getLockP2PCommand = function (deviceSN, user_id, command, channel, lockPublicKey, payload) {
const key = (0, exports.generateAdvancedLockAESKey)();
const ecdhKey = (0, exports.getAdvancedLockKey)(key, lockPublicKey);
const iv = (0, exports.getLockVectorBytes)(deviceSN);
const encPayload = (0, exports.encryptLockAESData)(key, iv, Buffer.from(JSON.stringify(payload)));
logging_1.rootP2PLogger.debug(`Generate lock command`, { deviceSN: deviceSN, userId: user_id, command: command, channel: channel, data: JSON.stringify(payload) });
return {
commandType: types_1.CommandType.CMD_SET_PAYLOAD,
value: JSON.stringify({
key: ecdhKey,
account_id: user_id,
cmd: command,
mChannel: channel,
mValue3: 0,
payload: encPayload.toString("base64")
}).replace(/=/g, "\\u003d"),
channel: channel,
aesKey: key
};
};
exports.getLockP2PCommand = getLockP2PCommand;
const getLockV12P2PCommand = function (deviceSN, user_id, command, channel, lockPublicKey, sequence, data) {
const key = (0, exports.generateAdvancedLockAESKey)();
const encryptedAesKey = (0, exports.getLockV12Key)(key, lockPublicKey);
const iv = (0, exports.getLockVectorBytes)(deviceSN);
const encPayload = (0, exports.encryptPayloadData)(data, Buffer.from(key, "hex"), Buffer.from(iv, "hex"));
logging_1.rootP2PLogger.debug(`Generate smart lock v12 command`, { deviceSN: deviceSN, userId: user_id, command: command, channel: channel, sequence: sequence, data: data.toString("hex") });
const bleCommand = new ble_1.BleCommandFactory()
.setVersionCode(device_1.Lock.VERSION_CODE_LOCKV12)
.setCommandCode(Number.parseInt(types_1.ESLBleCommand[types_1.ESLCommand[command]])) //TODO: Change internal command identification?
.setDataType(-1)
.setData(encPayload)
.setAdditionalData(Buffer.from(encryptedAesKey, "hex"));
return {
aesKey: key,
bleCommand: bleCommand.getCommandCode(),
payload: {
commandType: types_1.CommandType.CMD_SET_PAYLOAD,
value: JSON.stringify({
account_id: user_id,
cmd: types_1.CommandType.CMD_SET_PAYLOAD_LOCKV12,
mChannel: channel,
mValue3: 0,
payload: {
apiCommand: command,
lock_payload: bleCommand.getLockV12Command().toString("hex"),
seq_num: sequence,
}
})
}
};
};
exports.getLockV12P2PCommand = getLockV12P2PCommand;
const DecimalToRGBColor = function (color) {
return {
red: (color >> 16) & 0xff,
green: (color >> 8) & 0xff,
blue: color & 0xff,
};
};
exports.DecimalToRGBColor = DecimalToRGBColor;
const RGBColorToDecimal = function (color) {
return (color.red << 16) + (color.green << 8) + (color.blue);
};
exports.RGBColorToDecimal = RGBColorToDecimal;
const getNullTerminatedString = function (data, encoding) {
const index = data.indexOf(0);
return data.toString(encoding, 0, index === -1 ? data.length : index);
};
exports.getNullTerminatedString = getNullTerminatedString;
const isUsbCharging = function (value) {
return (value & 1) == 1;
};
exports.isUsbCharging = isUsbCharging;
const isSolarCharging = function (value) {
return ((value >> 2) & 1) == 1;
};
exports.isSolarCharging = isSolarCharging;
const isPlugSolarCharging = function (value) {
return ((value >> 3) & 1) == 1;
};
exports.isPlugSolarCharging = isPlugSolarCharging;
const isCharging = function (value) {
return (0, exports.isUsbCharging)(value) || (0, exports.isSolarCharging)(value) || (0, exports.isPlugSolarCharging)(value);
};
exports.isCharging = isCharging;
const getSmartLockCurrentTimeInSeconds = function () {
return Math.trunc(new Date().getTime() / 1000) | Math.trunc(Math.random() * 100);
};
exports.getSmartLockCurrentTimeInSeconds = getSmartLockCurrentTimeInSeconds;
const generateSmartLockAESKey = (adminUserId, time) => {
const buffer = Buffer.allocUnsafe(4);
buffer.writeUint32BE(time);
return Buffer.concat([Buffer.from(adminUserId.substring(adminUserId.length - 12)), buffer]);
};
exports.generateSmartLockAESKey = generateSmartLockAESKey;
const getSmartLockP2PCommand = function (deviceSN, user_id, command, channel, sequence, data, functionType = types_1.SmartLockFunctionType.TYPE_2) {
const time = (0, exports.getSmartLockCurrentTimeInSeconds)();
const key = (0, exports.generateSmartLockAESKey)(user_id, time);
const iv = (0, exports.getLockVectorBytes)(deviceSN);
const encPayload = (0, exports.encryptPayloadData)(data, key, Buffer.from(iv, "hex"));
logging_1.rootP2PLogger.debug(`Generate smart lock command`, { deviceSN: deviceSN, userId: user_id, command: command, channel: channel, sequence: sequence, data: data.toString("hex"), functionType: functionType });
let commandCode = 0;
if (functionType === types_1.SmartLockFunctionType.TYPE_1) {
commandCode = Number.parseInt(types_1.SmartLockBleCommandFunctionType1[types_1.SmartLockCommand[command]]);
}
else if (functionType === types_1.SmartLockFunctionType.TYPE_2) {
commandCode = Number.parseInt(types_1.SmartLockBleCommandFunctionType2[types_1.SmartLockCommand[command]]);
}
const bleCommand = new ble_1.BleCommandFactory()
.setVersionCode(device_1.Lock.VERSION_CODE_SMART_LOCK)
.setCommandCode(commandCode)
.setDataType(functionType)
.setData(encPayload);
return {
bleCommand: bleCommand.getCommandCode(),
payload: {
commandType: types_1.CommandType.CMD_SET_PAYLOAD,
value: JSON.stringify({
account_id: user_id,
cmd: types_1.CommandType.CMD_TRANSFER_PAYLOAD,
mChannel: channel,
mValue3: 0,
payload: {
apiCommand: command,
lock_payload: bleCommand.getSmartLockCommand().toString("hex"),
seq_num: sequence,
time: time,
}
})
}
};
};
exports.getSmartLockP2PCommand = getSmartLockP2PCommand;
const readNullTerminatedBuffer = (input) => {
const index = input.indexOf(new Uint8Array([0]));
if (index === -1) {
const result = Buffer.alloc(input.length);
input.copy(result);
return result;
}
const result = Buffer.alloc(input.subarray(0, index).length);
input.subarray(0, index).copy(result);
return result;
};
exports.readNullTerminatedBuffer = readNullTerminatedBuffer;
//# sourceMappingURL=utils.js.map

1
build/p2p/utils.js.map Normal file

File diff suppressed because one or more lines are too long

49
build/push/client.d.ts vendored Normal file
View File

@ -0,0 +1,49 @@
import { TypedEmitter } from "tiny-typed-emitter";
import { PushClientEvents } from "./interfaces";
export declare class PushClient extends TypedEmitter<PushClientEvents> {
private readonly HOST;
private readonly PORT;
private readonly MCS_VERSION;
private readonly HEARTBEAT_INTERVAL;
private loggedIn;
private streamId;
private lastStreamIdReported;
private currentDelay;
private client?;
private heartbeatTimeout?;
private reconnectTimeout?;
private persistentIds;
private static proto;
private pushClientParser;
private auth;
private constructor();
static init(auth: {
androidId: string;
securityToken: string;
}): Promise<PushClient>;
private initialize;
getPersistentIds(): Array<string>;
setPersistentIds(ids: Array<string>): void;
connect(): void;
private buildLoginRequest;
private buildHeartbeatPingRequest;
private buildHeartbeatAckRequest;
private onSocketData;
private onSocketConnect;
private onSocketClose;
private onSocketError;
private handleParsedMessage;
private handleHeartbeatPing;
private handleHeartbeatAck;
private convertPayloadMessage;
private getStreamId;
private newStreamIdAvailable;
private scheduleHeartbeat;
private sendHeartbeat;
isConnected(): boolean;
private getHeartbeatInterval;
private getCurrentDelay;
private resetCurrentDelay;
private scheduleReconnect;
close(): void;
}

323
build/push/client.js Normal file
View File

@ -0,0 +1,323 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PushClient = void 0;
const long_1 = __importDefault(require("long"));
const path = __importStar(require("path"));
const protobufjs_1 = require("protobufjs");
const tls = __importStar(require("tls"));
const tiny_typed_emitter_1 = require("tiny-typed-emitter");
const models_1 = require("./models");
const parser_1 = require("./parser");
const utils_1 = require("../utils");
const error_1 = require("./error");
const error_2 = require("../error");
const utils_2 = require("../p2p/utils");
const logging_1 = require("../logging");
class PushClient extends tiny_typed_emitter_1.TypedEmitter {
HOST = "mtalk.google.com";
PORT = 5228;
MCS_VERSION = 41;
HEARTBEAT_INTERVAL = 5 * 60 * 1000;
loggedIn = false;
streamId = 0;
lastStreamIdReported = -1;
currentDelay = 0;
client;
heartbeatTimeout;
reconnectTimeout;
persistentIds = [];
static proto = null;
pushClientParser;
auth;
constructor(pushClientParser, auth) {
super();
this.pushClientParser = pushClientParser;
this.auth = auth;
}
static async init(auth) {
this.proto = await (0, protobufjs_1.load)(path.join(__dirname, "./proto/mcs.proto"));
const pushClientParser = await parser_1.PushClientParser.init();
return new PushClient(pushClientParser, auth);
}
initialize() {
this.loggedIn = false;
this.streamId = 0;
this.lastStreamIdReported = -1;
if (this.client) {
this.client.removeAllListeners();
this.client.destroy();
this.client = undefined;
}
this.pushClientParser.resetState();
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
this.reconnectTimeout = undefined;
}
}
getPersistentIds() {
return this.persistentIds;
}
setPersistentIds(ids) {
this.persistentIds = ids;
}
connect() {
this.initialize();
this.pushClientParser.on("message", (message) => this.handleParsedMessage(message));
this.client = tls.connect(this.PORT, this.HOST, {
rejectUnauthorized: false,
});
this.client.setKeepAlive(true);
// For debugging purposes
//this.client.enableTrace();
this.client.on("connect", () => this.onSocketConnect());
this.client.on("close", () => this.onSocketClose());
this.client.on("error", (error) => this.onSocketError(error));
this.client.on("data", (newData) => this.onSocketData(newData));
this.client.write(this.buildLoginRequest());
}
buildLoginRequest() {
const androidId = this.auth.androidId;
const securityToken = this.auth.securityToken;
const LoginRequestType = PushClient.proto.lookupType("mcs_proto.LoginRequest");
const hexAndroidId = long_1.default.fromString(androidId).toString(16);
const loginRequest = {
adaptiveHeartbeat: false,
authService: 2,
authToken: securityToken,
id: "chrome-63.0.3234.0",
domain: "mcs.android.com",
deviceId: `android-${hexAndroidId}`,
networkType: 1,
resource: androidId,
user: androidId,
useRmq2: true,
setting: [{ name: "new_vc", value: "1" }],
clientEvent: [],
receivedPersistentId: this.persistentIds,
};
const errorMessage = LoginRequestType.verify(loginRequest);
if (errorMessage) {
throw new error_1.BuildLoginRequestError(errorMessage, { context: { loginRequest: loginRequest } });
}
const buffer = LoginRequestType.encodeDelimited(loginRequest).finish();
return Buffer.concat([Buffer.from([this.MCS_VERSION, models_1.MessageTag.LoginRequest]), buffer]);
}
buildHeartbeatPingRequest(stream_id) {
const heartbeatPingRequest = {};
if (stream_id) {
heartbeatPingRequest.last_stream_id_received = stream_id;
}
logging_1.rootPushLogger.debug(`Push client - heartbeatPingRequest`, { streamId: stream_id, request: JSON.stringify(heartbeatPingRequest) });
const HeartbeatPingRequestType = PushClient.proto.lookupType("mcs_proto.HeartbeatPing");
const errorMessage = HeartbeatPingRequestType.verify(heartbeatPingRequest);
if (errorMessage) {
throw new error_1.BuildHeartbeatPingRequestError(errorMessage, { context: { heartbeatPingRequest: heartbeatPingRequest } });
}
const buffer = HeartbeatPingRequestType.encodeDelimited(heartbeatPingRequest).finish();
return Buffer.concat([Buffer.from([models_1.MessageTag.HeartbeatPing]), buffer]);
}
buildHeartbeatAckRequest(stream_id, status) {
const heartbeatAckRequest = {};
if (stream_id && !status) {
heartbeatAckRequest.last_stream_id_received = stream_id;
}
else if (!stream_id && status) {
heartbeatAckRequest.status = status;
}
else {
heartbeatAckRequest.last_stream_id_received = stream_id;
heartbeatAckRequest.status = status;
}
logging_1.rootPushLogger.debug(`Push client - heartbeatAckRequest`, { streamId: stream_id, status: status, request: JSON.stringify(heartbeatAckRequest) });
const HeartbeatAckRequestType = PushClient.proto.lookupType("mcs_proto.HeartbeatAck");
const errorMessage = HeartbeatAckRequestType.verify(heartbeatAckRequest);
if (errorMessage) {
throw new error_1.BuildHeartbeatAckRequestError(errorMessage, { context: { heartbeatAckRequest: heartbeatAckRequest } });
}
const buffer = HeartbeatAckRequestType.encodeDelimited(heartbeatAckRequest).finish();
return Buffer.concat([Buffer.from([models_1.MessageTag.HeartbeatAck]), buffer]);
}
onSocketData(newData) {
this.pushClientParser.handleData(newData);
}
onSocketConnect() {
//
}
onSocketClose() {
this.loggedIn = false;
if (this.heartbeatTimeout) {
clearTimeout(this.heartbeatTimeout);
this.heartbeatTimeout = undefined;
}
this.emit("close");
this.scheduleReconnect();
}
onSocketError(err) {
const error = (0, error_2.ensureError)(err);
logging_1.rootPushLogger.error(`Push client - Socket Error`, { error: (0, utils_1.getError)(error) });
}
handleParsedMessage(message) {
this.resetCurrentDelay();
switch (message.tag) {
case models_1.MessageTag.DataMessageStanza:
logging_1.rootPushLogger.debug(`Push client - DataMessageStanza`, { message: JSON.stringify(message) });
if (message.object && message.object.persistentId)
this.persistentIds.push(message.object.persistentId);
this.emit("message", this.convertPayloadMessage(message));
break;
case models_1.MessageTag.HeartbeatPing:
this.handleHeartbeatPing(message);
break;
case models_1.MessageTag.HeartbeatAck:
this.handleHeartbeatAck(message);
break;
case models_1.MessageTag.Close:
logging_1.rootPushLogger.debug(`Push client - Close: Server requested close`, { message: JSON.stringify(message) });
break;
case models_1.MessageTag.LoginResponse:
logging_1.rootPushLogger.debug("Push client - Login response: GCM -> logged in -> waiting for push messages...", { message: JSON.stringify(message) });
this.loggedIn = true;
this.persistentIds = [];
this.emit("connect");
this.heartbeatTimeout = setTimeout(() => {
this.scheduleHeartbeat(this);
}, this.getHeartbeatInterval());
break;
case models_1.MessageTag.LoginRequest:
logging_1.rootPushLogger.debug(`Push client - Login request`, { message: JSON.stringify(message) });
break;
case models_1.MessageTag.IqStanza:
logging_1.rootPushLogger.debug(`Push client - IqStanza: Not implemented`, { message: JSON.stringify(message) });
break;
default:
logging_1.rootPushLogger.debug(`Push client - Unknown message`, { message: JSON.stringify(message) });
return;
}
this.streamId++;
}
handleHeartbeatPing(message) {
logging_1.rootPushLogger.debug(`Push client - Heartbeat ping`, { message: JSON.stringify(message) });
let streamId = undefined;
let status = undefined;
if (this.newStreamIdAvailable()) {
streamId = this.getStreamId();
}
if (message.object && message.object.status) {
status = message.object.status;
}
if (this.client)
this.client.write(this.buildHeartbeatAckRequest(streamId, status));
}
handleHeartbeatAck(message) {
logging_1.rootPushLogger.debug(`Push client - Heartbeat acknowledge`, { message: JSON.stringify(message) });
}
convertPayloadMessage(message) {
const { appData, ...otherData } = message.object;
const messageData = {};
appData.forEach((kv) => {
if (kv.key === "payload") {
const payload = (0, utils_1.parseJSON)((0, utils_2.getNullTerminatedString)(Buffer.from(kv.value, "base64"), "utf8"), logging_1.rootPushLogger);
messageData[kv.key] = payload;
}
else {
messageData[kv.key] = kv.value;
}
});
return {
...otherData,
payload: messageData,
};
}
getStreamId() {
this.lastStreamIdReported = this.streamId;
return this.streamId;
}
newStreamIdAvailable() {
return this.lastStreamIdReported != this.streamId;
}
scheduleHeartbeat(client) {
if (client.sendHeartbeat()) {
this.heartbeatTimeout = setTimeout(() => {
this.scheduleHeartbeat(client);
}, client.getHeartbeatInterval());
}
else {
logging_1.rootPushLogger.debug("Push client - Heartbeat disabled!");
}
}
sendHeartbeat() {
let streamId = undefined;
if (this.newStreamIdAvailable()) {
streamId = this.getStreamId();
}
if (this.client && this.isConnected()) {
logging_1.rootPushLogger.debug(`Push client - Sending heartbeat...`, { streamId: streamId });
this.client.write(this.buildHeartbeatPingRequest(streamId));
return true;
}
else {
logging_1.rootPushLogger.debug("Push client - No more connected, reconnect...");
this.scheduleReconnect();
}
return false;
}
isConnected() {
return this.loggedIn;
}
getHeartbeatInterval() {
return this.HEARTBEAT_INTERVAL;
}
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() {
const delay = this.getCurrentDelay();
logging_1.rootPushLogger.debug("Push client - Schedule reconnect...", { delay: delay });
if (!this.reconnectTimeout)
this.reconnectTimeout = setTimeout(() => {
this.connect();
}, delay);
}
close() {
const wasConnected = this.isConnected();
this.initialize();
if (wasConnected)
this.emit("close");
}
}
exports.PushClient = PushClient;
//# sourceMappingURL=client.js.map

1
build/push/client.js.map Normal file

File diff suppressed because one or more lines are too long

73
build/push/error.d.ts vendored Normal file
View File

@ -0,0 +1,73 @@
import { BaseError, Jsonable } from "../error";
export declare class UnknownExpiryFormaError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class FidRegistrationFailedError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class RenewFidTokenFailedError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class ExecuteCheckInError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class RegisterGcmError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BuildLoginRequestError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BuildHeartbeatPingRequestError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BuildHeartbeatAckRequestError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class FidGenerationError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class MCSProtocolVersionError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class MCSProtocolProcessingStateError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class MCSProtocolMessageTagError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}

101
build/push/error.js Normal file
View File

@ -0,0 +1,101 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MCSProtocolMessageTagError = exports.MCSProtocolProcessingStateError = exports.MCSProtocolVersionError = exports.FidGenerationError = exports.BuildHeartbeatAckRequestError = exports.BuildHeartbeatPingRequestError = exports.BuildLoginRequestError = exports.RegisterGcmError = exports.ExecuteCheckInError = exports.RenewFidTokenFailedError = exports.FidRegistrationFailedError = exports.UnknownExpiryFormaError = void 0;
const error_1 = require("../error");
class UnknownExpiryFormaError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = UnknownExpiryFormaError.name;
}
}
exports.UnknownExpiryFormaError = UnknownExpiryFormaError;
class FidRegistrationFailedError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = FidRegistrationFailedError.name;
}
}
exports.FidRegistrationFailedError = FidRegistrationFailedError;
class RenewFidTokenFailedError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = RenewFidTokenFailedError.name;
}
}
exports.RenewFidTokenFailedError = RenewFidTokenFailedError;
class ExecuteCheckInError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = ExecuteCheckInError.name;
}
}
exports.ExecuteCheckInError = ExecuteCheckInError;
class RegisterGcmError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = RegisterGcmError.name;
}
}
exports.RegisterGcmError = RegisterGcmError;
class BuildLoginRequestError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BuildLoginRequestError.name;
}
}
exports.BuildLoginRequestError = BuildLoginRequestError;
class BuildHeartbeatPingRequestError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BuildHeartbeatPingRequestError.name;
}
}
exports.BuildHeartbeatPingRequestError = BuildHeartbeatPingRequestError;
class BuildHeartbeatAckRequestError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BuildHeartbeatAckRequestError.name;
}
}
exports.BuildHeartbeatAckRequestError = BuildHeartbeatAckRequestError;
class FidGenerationError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = FidGenerationError.name;
}
}
exports.FidGenerationError = FidGenerationError;
class MCSProtocolVersionError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = MCSProtocolVersionError.name;
}
}
exports.MCSProtocolVersionError = MCSProtocolVersionError;
class MCSProtocolProcessingStateError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = MCSProtocolProcessingStateError.name;
}
}
exports.MCSProtocolProcessingStateError = MCSProtocolProcessingStateError;
class MCSProtocolMessageTagError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = MCSProtocolMessageTagError.name;
}
}
exports.MCSProtocolMessageTagError = MCSProtocolMessageTagError;
//# sourceMappingURL=error.js.map

1
build/push/error.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/push/error.ts"],"names":[],"mappings":";;;AAAA,oCAA+C;AAE/C,MAAa,uBAAwB,SAAQ,iBAAS;IAClD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC,IAAI,CAAC;IAC7C,CAAC;CACJ;AAND,0DAMC;AAED,MAAa,0BAA2B,SAAQ,iBAAS;IACrD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC,IAAI,CAAC;IAChD,CAAC;CACJ;AAND,gEAMC;AAED,MAAa,wBAAyB,SAAQ,iBAAS;IACnD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC,IAAI,CAAC;IAC9C,CAAC;CACJ;AAND,4DAMC;AAED,MAAa,mBAAoB,SAAQ,iBAAS;IAC9C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC;IACzC,CAAC;CACJ;AAND,kDAMC;AAED,MAAa,gBAAiB,SAAQ,iBAAS;IAC3C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;IACtC,CAAC;CACJ;AAND,4CAMC;AAED,MAAa,sBAAuB,SAAQ,iBAAS;IACjD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC,IAAI,CAAC;IAC5C,CAAC;CACJ;AAND,wDAMC;AAED,MAAa,8BAA+B,SAAQ,iBAAS;IACzD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC,IAAI,CAAC;IACpD,CAAC;CACJ;AAND,wEAMC;AAED,MAAa,6BAA8B,SAAQ,iBAAS;IACxD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC,IAAI,CAAC;IACnD,CAAC;CACJ;AAND,sEAMC;AAED,MAAa,kBAAmB,SAAQ,iBAAS;IAC7C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC;IACxC,CAAC;CACJ;AAND,gDAMC;AAED,MAAa,uBAAwB,SAAQ,iBAAS;IAClD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC,IAAI,CAAC;IAC7C,CAAC;CACJ;AAND,0DAMC;AAED,MAAa,+BAAgC,SAAQ,iBAAS;IAC1D,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC,IAAI,CAAC;IACrD,CAAC;CACJ;AAND,0EAMC;AAED,MAAa,0BAA2B,SAAQ,iBAAS;IACrD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC,IAAI,CAAC;IAChD,CAAC;CACJ;AAND,gEAMC"}

6
build/push/index.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
export * from "./models";
export * from "./interfaces";
export * from "./service";
export * from "./types";
export * from "./error";
export { sleep, convertTimestampMs } from "./utils";

26
build/push/index.js Normal file
View File

@ -0,0 +1,26 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertTimestampMs = exports.sleep = void 0;
__exportStar(require("./models"), exports);
__exportStar(require("./interfaces"), exports);
__exportStar(require("./service"), exports);
__exportStar(require("./types"), exports);
__exportStar(require("./error"), exports);
var utils_1 = require("./utils");
Object.defineProperty(exports, "sleep", { enumerable: true, get: function () { return utils_1.sleep; } });
Object.defineProperty(exports, "convertTimestampMs", { enumerable: true, get: function () { return utils_1.convertTimestampMs; } });
//# sourceMappingURL=index.js.map

Some files were not shown because too many files have changed in this diff Show More