Last Updated on : 2026-03-06 03:20:26download
The P2P capabilities of the robot vacuum are implemented based on the IP camera’s P2P and file transfer functionalities. In addition to the basic Tuya SDK, the following two libraries are required for direct use.
SDK:
@thingsmart/thingp2pfiletranssdk: P2P file transfer core library.@thingsmart/ipcsdk: IPC functionality library.Platform: HarmonyOS (ArkTS)
// IPC SDK manager
import { ThingIPCSdk } from '@thingsmart/ipcsdk'
// P2P file transfer core
import {
ThingP2pFileTransManager, // File transfer manager (static class)
ThingP2pFileTransInterface, // File transfer interface
ThingP2pFileTransListener // File transfer listener
} from '@thingsmart/thingp2pfiletranssdk'
Functional description
Gets a P2P management instance to manage the lifecycle of P2P connections. This is a static method in the singleton pattern.
Function signature
static getP2P(): IThingP2P
Return value
| Type | Description |
|---|---|
| IThingP2P | The P2P management instance, including methods for initialization, connection, and disconnection. |
Example
const p2pManager = ThingIPCSdk.getP2P()
Functional description
Initializes the P2P SDK. This is a necessary step before using any of the SDK’s functionalities. The initialization process configures the SDK runtime environment and registers essential services and components.
Function signature
initP2P(userId: string): number
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| userId | string | Yes | The user ID used to identify the current user. |
Return value
| Type | Description |
|---|---|
| number | Return result: 0 indicates success, and other values indicate failure. |
Example
const result = ThingIPCSdk.getP2P().initP2P('user_12345')
if (result === 0) {
L.i('P2PDemo', 'SDK initialization was successful')
} else {
L.e('P2PDemo', `SDK initialization failed: ${result}`)
}
Functional description
Connects to the specified device and establishes a P2P session. Upon successful connection, a sessionId (handle) is returned via the callback for subsequent file transfer operations.
Function signature
connectWithDevId(remoteId: string, lanMode: number, timeout: number, callback: IThingP2PCallback): string
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| remoteId | string | Yes | The device ID (an identifier for a remote device). |
| lanMode | number | Yes | The connection mode. Valid values:
|
| timeout | number | Yes | The timeout duration in milliseconds. Recommended value: no less than 10,000 ms. |
| callback | IThingP2PCallback | Yes | The P2P connection callback. |
IThingP2PCallback definition
interface IThingP2PCallback {
onResult(handle: number): void
}
| Callback | Parameter | Description |
|---|---|---|
| onResult | handle: number | The connection result callback. The handle value represents the sessionId:
|
Return value
| Type | Description |
|---|---|
| string | The trace ID (traceId) of the connection request. |
Session handle values
| Value | Description |
|---|---|
| > 0 | Connection was successful. The value is the sessionId, which must be set on the file transfer instance. |
| 0 | Initial state. |
| -1 | Connection failed. |
| -2 | The connection is closed. |
| -3 | The connection timed out. |
initP2P must be called before establishing a connection.handle parameter in the onResult callback (when the value is > 0) is the sessionId, which must be set on the file transfer instance.0) is suitable for remote connections, whereas LAN mode (1) is for fast connections within the same network.onResult will be called multiple times to notify of session state changes.Example
// Define callback
const callback: IThingP2PCallback = {
onResult: (handle: number) => {
L.i('P2PDemo', `P2P connection result: handle=${handle}`)
if (handle > 0) {
// Connection was successful. The handle is the sessionId, which needs to be set on the file transfer instance.
p2pFileTransfer.session = handle
L.i('P2PDemo', `Connection successful, sessionId set: ${handle}`)
} else if (handle === 0) {
L.i('P2PDemo', 'Connection initializing...')
} else {
// handle < 0 indicates connection failure or disconnection
L.e('P2PDemo', `Connection failed or disconnected: ${handle}`)
}
}
}
// Initiate a connection
ThingIPCSdk.getP2P().connectWithDevId(
'device_abc123', // Device ID
0, // Internet mode
15000, // 15-second timeout
callback // Callback interface
)
Complete example (combined with file transfer)
class P2PManager {
private p2pFileTransfer: ThingP2pFileTransInterface | null = null
private sessionId: number = -1
async connectDevice(deviceId: string) {
// 1. Create a file transfer listener
const listener: ThingP2pFileTransListener = {
onSessionStatusChanged: (sessionId, sessionStatus) => {
L.i('P2PDemo', `Session status: ${sessionStatus}`)
return 0
},
// ... Other callbacks
}
// 2. Create a file transfer instance
this.p2pFileTransfer = ThingP2pFileTransManager.createP2pFileTransfer(
deviceId,
listener
)
// 3. Define the connection callback
const callback: IThingP2PCallback = {
onResult: (handle: number) => {
if (handle > 0) {
// 🔥 Save sessionId and set it to the file transfer instance
this.sessionId = handle
if (this.p2pFileTransfer) {
this.p2pFileTransfer.session = handle
L.i('P2PDemo', `✅ sessionId set: ${handle}`)
}
} else if (handle < 0) {
L.e('P2PDemo', `Connection failed: ${handle}`)
this.sessionId = -1
}
}
}
// 4. Initiate a connection
ThingIPCSdk.getP2P().connectWithDevId(
deviceId,
0, // Internet mode
15000, // Timeout period
callback
)
}
}
Functional description
Disconnects the P2P connection with a specified device and releases associated resources.
Function signature
disConnect(handle: number, reason: number, forced: boolean): number
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| handle | number | Yes | The session handle (sessionId), obtained from the connectWithDevId callback. |
| reason | number | Yes | Disconnection reason code: 0 indicates normal disconnection. Other values indicate unexpected disconnection. |
| forced | boolean | Yes | Specifies whether to forcibly disconnect. Valid values:
|
Return value
| Type | Description |
|---|---|
| number | Return result: 0 indicates success, and other values indicate failure. |
handle parameter must be a valid sessionId (> 0).Example
// Assume the sessionId obtained from the connection callback
const sessionId = 12345
// Method 1: Normal disconnection (graceful)
const result = ThingIPCSdk.getP2P().disConnect(
sessionId, // Session handle
0, // Normal disconnection
false // Graceful disconnection
)
if (result === 0) {
L.i('P2PDemo', 'Device disconnected successfully')
} else {
L.e('P2PDemo', `Device disconnection failed: ${result}`)
}
// Method 2: Forced disconnection
const forceResult = ThingIPCSdk.getP2P().disConnect(
sessionId, // Session handle
1, // Unexpected disconnection
true // Forced disconnection
)
Functional description
Deinitializes the P2P SDK and releases all resources. This is typically called when the application exits.
Function signature
deInitP2P(): number
Return value
| Type | Description |
|---|---|
| number | Return result: 0 indicates success, and other values indicate failure. |
initP2P needs to be called again before the application can be used.Example
// Disconnect all connections first
const disconnectResult = ThingIPCSdk.getP2P().disConnect(sessionId, 0, false)
if (disconnectResult !== 0) {
L.e('P2PDemo', `Disconnection failed: ${disconnectResult}`)
}
// Deinitialize the SDK
const result = ThingIPCSdk.getP2P().deInitP2P()
if (result === 0) {
L.i('P2PDemo', 'SDK deinitialization was successful')
} else {
L.e('P2PDemo', `SDK deinitialization failed: ${result}`)
}
Functional description
Creates a P2P file transfer instance. An independent file transfer instance must be created for each device, used for operations such as querying file indexes, uploading, and downloading files.
Function signature
static createP2pFileTransfer(
deviceId: string,
listener: ThingP2pFileTransListener
): ThingP2pFileTransInterface
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| deviceId | string | Yes | The device ID. It must match the device ID used when connecting. |
| listener | ThingP2pFileTransListener | Yes | The file transfer listener used to receive various callback events. |
Return value
| Type | Description |
|---|---|
| ThingP2pFileTransInterface | The file transfer instance. It provides methods for querying, uploading, and downloading. |
sessionId obtained from the successful connection state callback to the session property of the instance.destroyP2pFileTransfer() method must be called.Example
// 1. Create a listener
const listener: ThingP2pFileTransListener = {
onSessionStatusChanged: (sessionId, status) => {
L.i('P2PDemo', `session status: ${status}`)
return 0
},
onFileFinished: (event, filename, index, errCode) => {
L.i('P2PDemo', `file completed: ${filename}`)
return 0
},
// ... other callbacks
}
// 2. Create a file transfer instance
const p2pFileTransfer = ThingP2pFileTransManager.createP2pFileTransfer(
'device_abc123',
listener
)
// 3. Set the sessionId after connecting to the device (Important!)
ThingIPCSdk.getP2P().connectWithDevId(
{ deviceId: 'device_abc123' },
(event) => {
if (event.status > 0) {
// Key step: Set sessionId
p2pFileTransfer.session = event.status
L.i('P2PDemo', `sessionId already set: ${event.status}`)
}
},
() => L.i('P2PDemo', 'Connection was successful'),
(code, msg) => L.e('P2PDemo', `Connection failed: ${msg}`)
)
Functional description
Gets the version number of the P2P file transfer SDK.
Function signature
static getSDKVersion(): string
Return value
| Type | Description |
|---|---|
| string | The SDK version number, in the format "1.0.0". |
It is used for debugging and compatibility checks.
Example
const version = ThingP2pFileTransManager.getSDKVersion()
L.i('P2PDemo', `SDK version: ${version}`)
Functional description
The session ID property, which must be set after a successful connection. This is the core identifier for P2P file transfer.
Property type
session: number
Description
| Property | Type | Description |
|---|---|---|
| session | number | The session ID, obtained from the status callback of connectWithDevId. |
sessionId is derived from event.status in the onStatusChange callback of connectWithDevId (when status is > 0).Example
// Set in connection status callback
ThingIPCSdk.getP2P().connectWithDevId(
{ deviceId: 'device_abc123' },
(event) => {
if (event.status > 0) {
// Set sessionId to file transfer instance
p2pFileTransfer.session = event.status
L.i('P2PDemo', `session already set: ${event.status}`)
}
},
() => {},
(code, msg) => {}
)
Functional description
Queries the file index list for a specified album. The returned file index contains information such as file name, type, and time, which can be used for subsequent download operations.
Function signature
queryAlbumFile(
albumName: string,
): number
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| albumName | string | Yes | The album name, such as "Camera" and "Maps". |
Return value
| Type | Description |
|---|---|
| number | Return result: 0 indicates success, and other values indicate failure. |
sessionId must be set before querying.onP2pResponse callback (event = 12).callback parameter might not be invoked and is present only for compatibility.P2PAlbumFileIndexs, containing count and items fields.Example
// Method 1: Using a listener to receive data (Recommended)
const listener: ThingP2pFileTransListener = {
onP2pResponse: (event, errCode, data) => {
if (event === 12) { // Query file index event
if (errCode === 0 && data) {
const result: P2PAlbumFileIndexs = JSON.parse(data)
L.i('P2PDemo', `Query was successful: count=${result.count}, items=${result.items.length}`)
// Process the file list
result.items.forEach(file => {
L.i('P2PDemo', `File: ${file.filename}, type: ${file.type}`)
})
}
}
return 0
},
// ... Other callbacks
}
// Call the query method
const result = p2pFileTransfer.queryFileIndexs('Camera', (indexes) => {
// Note: This callback might not be invoked
L.i('P2PDemo', `Query callback: ${indexes.length}`)
})
if (result !== 0) {
L.e('P2PDemo', `Query call failed: ${result}`)
}
Functional description
Starts downloading the specified list of files to a local directory. Supports bulk downloading, with download progress notified via listener callbacks.
Function signature
startDownloadFiles(
albumName: string,
savePath: string,
fileIndexes: string
): number
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| albumName | string | Yes | The album name, which must be the same as used in the query. |
| savePath | string | Yes | The save path. It must be an absolute path and the directory must exist. |
| fileIndexes | string | Yes | JSON string of the file index array, generated via JSON.stringify(FileIndex[]). |
Return value
| Type | Description |
|---|---|
| number | Return result: 0 indicates success, and other values indicate failure. |
fs.mkdirSync() to ensure the directory exists.onP2pResponse callback (after a successful query).onFileProgress callback.onFileFinished callback.Example
// Receive query results and automatically download them in onP2pResponse
onP2pResponse: (event, errCode, data) => {
if (event === 12 && errCode === 0 && data) {
const result: P2PAlbumFileIndexs = JSON.parse(data)
// Prepare the save path
const savePath = '/data/storage/el2/base/haps/entry/files/downloads'
if (!fs.accessSync(savePath)) {
fs.mkdirSync(savePath, true)
}
// Call the download in the query success callback
const fileIndexesJson = JSON.stringify(result.items)
const downloadResult = p2pFileTransfer.startDownloadFiles(
'ipc_sweeper_robot',
savePath,
fileIndexesJson
)
if (downloadResult === 0) {
L.i('P2PDemo', `Started downloading ${result.items.length} files`)
} else {
L.e('P2PDemo', `Download failed: ${downloadResult}`)
}
}
return 0
}
Functional description
Downloads files in a streaming manner, suitable for data that needs real-time processing, such as maps. Data is returned packet by packet through the listener’s onStreamRecved callback.
Function signature
startDownloadStream(
albumName: string,
fileIndexes: string
): number
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| albumName | string | Yes | The album name. |
| fileIndexes | string | Yes | The JSON string of the file index array. |
Return value
| Type | Description |
|---|---|
| number | Return result: 0 indicates success, and other values indicate failure. |
onStreamRecved callback.Example
const fileIndexesJson = JSON.stringify([
{ idx: 0, channel: 0, type: 2, filename: 'map.dat', /* ... */ }
])
const result = p2pFileTransfer.startDownloadStream('Maps', fileIndexesJson)
if (result === 0) {
L.i('P2PDemo', 'Streaming download has started')
}
Functional description
Destroys the file transfer instance and releases related resources. This method should be called before disconnecting the device.
Function signature
destroy(): void
Example
// Destroy the file transfer instance
p2pFileTransfer.destroy()
// Then disconnect the device
ThingIPCSdk.getP2P().disconnect({ deviceId: 'device_abc123' }, () => {}, () => {})
Functional description
A callback for session status changes. It is triggered when the device connection status changes, used to monitor the connection status.
Function signature
onSessionStatusChanged(sessionId: number, sessionStatus: number): number
Parameters
| Parameter | Type | Description |
|---|---|---|
| sessionId | number | The session ID. |
| sessionStatus | number | The session status. Valid values:
|
Return value
| Type | Description |
|---|---|
| number | Returns 0 or the sessionId by default. |
Status value description
| Status value | Description |
|---|---|
| > 0 | Connection successful. The value is the sessionId. |
| 0 | Initial state. |
| < 0 | Connection disconnected or failed. |
Example
onSessionStatusChanged: (sessionId, sessionStatus) => {
if (sessionStatus > 0) {
L.i('P2PDemo', `Connected,sessionId: ${sessionStatus}`)
} else if (sessionStatus < 0) {
L.e('P2PDemo', 'Disconnected')
}
return 0
}
Functional description
A callback for file transfer completion. It is triggered when a single file upload or download finishes.
Function signature
onFileFinished(
event: number,
filename: string,
index: number,
errCode: number
): number
Parameters
| Parameter | Type | Description |
|---|---|---|
| event | number | The event type. Valid values:
|
| filename | string | The file name. |
| index | number | The file index. |
| errCode | number | The error code. 0 indicates success, and other values indicate failure. |
Return value
| Type | Description |
|---|---|
| number | Returns 0 by default. |
Example
onFileFinished: (event, filename, index, errCode) => {
if (event === 0) {
L.i('P2PDemo', `File download completed: ${filename}, Result: ${errCode === 0 ? 'Success' : 'Failure'}`)
} else if (event === 2) {
L.i('P2PDemo', `File upload completed: ${filename}`)
}
return 0
}
Functional description
A Callback for overall transfer progress. It is used to display the overall transfer progress.
Function signature
onProgress(event: number, progress: number): number
Parameters
| Parameter | Type | Description |
|---|---|---|
| event | number | The event type. Valid values:
|
| progress | number | The progress percentage, ranging from 0 to 100. |
Return value
| Type | Description |
|---|---|
| number | Returns 0 by default. |
Example
onProgress: (event, progress) => {
L.i('P2PDemo', `${event === 0 ? 'Download' : 'Upload'}Progress: ${progress}%`)
return 0
}
Functional description
A callback for the progress of a single file transfer. It provides more granular progress information.
Function signature
onFileProgress(
event: number,
progress: number,
filename: string
): number
Parameters
| Parameter | Type | Description |
|---|---|---|
| event | number | The event type. Valid values:
|
| progress | number | The progress percentage, ranging from 0 to 100. |
| filename | string | The file name. |
Return value
| Type | Description |
|---|---|
| number | Returns 0 by default. |
Example
onFileProgress: (event, progress, filename) => {
L.i('P2PDemo', `${filename} ${event === 0 ? 'Download' : 'Upload'}Progress: ${progress}%`)
return 0
}
Functional description
P2P response callback. It is used to receive response data for commands such as queries. This is the key callback for receiving file index query results.
Function signature
onP2pResponse(event: number, errCode: number, data: string): number
Parameters
| Parameter | Type | Description |
|---|---|---|
| event | number | The event type. 12: Query file index. |
| errCode | number | The error code. 0 indicates success, and other values indicate failure. |
| data | string | The response data in a JSON string. |
Return value
| Type | Description |
|---|---|
| number | Returns 0 by default. |
Description of event types
| Event value | Description |
|---|---|
| 12 | The response for querying the file index. |
Response data format (when event = 12)
interface P2PAlbumFileIndexs {
count: number // Total number of files
items: FileIndex[] // Array of file indices
}
data needs to be parsed via JSON.parse().Example
onP2pResponse: (event, errCode, data) => {
L.i('P2PDemo', `P2P response: event=${event}, errCode=${errCode}`)
// Handle the response to the file index query
if (event === 12) {
if (errCode === 0 && data) {
try {
const result: P2PAlbumFileIndexs = JSON.parse(data)
L.i('P2PDemo', `Query was successful: count=${result.count}, items=${result.items.length}`)
// 🔥 Call the download method here
const savePath = '/data/storage/el2/base/haps/entry/files'
const fileIndexesJson = JSON.stringify(result.items)
p2pFileTransfer.startDownloadFiles('Camera', savePath, fileIndexesJson)
} catch (err) {
L.e('P2PDemo', `Parsing failed: ${err}`)
}
} else {
L.e('P2PDemo', `Query failed: ${errCode}`)
}
}
return 0
}
Functional description
A callback for streaming data reception. It is used for real-time data transmission such as maps. Data is returned packet by packet.
Function signature
onStreamRecved(
event: number,
sessionId: number,
totalfiles: number,
fileIndex: number,
fileLength: number,
pack: ArrayBuffer,
packageLength: number,
packageType: number
): number
Parameters
| Parameter | Type | Description |
|---|---|---|
| event | number | Event types |
| sessionId | number | The session ID. |
| totalfiles | number | Total number of files. |
| fileIndex | number | The current file index. |
| fileLength | number | The total file length. |
| pack | ArrayBuffer | The payload. |
| packageLength | number | The packet length. |
| packageType | number | The packet type. 1: The new file starts. |
Return value
| Type | Description |
|---|---|
| number | Returns 0 by default. |
Data packet types
| Type value | Description |
|---|---|
| 1 | New file start (first data packet). |
| Others | Subsequent data packets. |
Example
onStreamRecved: (event, sessionId, totalfiles, fileIndex, fileLength, pack, packageLength, packageType) => {
if (packageType === 1) {
L.i('P2PDemo', `Start receiving new files: file ${fileIndex}/${totalfiles}`)
}
L.d('P2PDemo', `Received data packet: length=${packageLength}, total length=${fileLength}`)
// Process data packet...
// For example: save to local, real-time rendering
return 0
}
Is this page helpful?
YesFeedbackIs this page helpful?
YesFeedback