---
name: "useStructuredDevicesActions"
mode: "api"
versionRequirements:
  - { name: "@ray-js/panel-sdk", version: "1.16.0" }
title: "useStructuredDevicesActions"
---

## useStructuredDevicesActions

> [VERSION] @ray-js/panel-sdk >= 1.16.0

> 💡 Before use, both of the following must be met:
> 1. Mount SdmDevicesProvider and configure the associated device mapping
> 2. Each device has configured the dp-kit interceptor (createDpKit) during initialization
> Notes:
> The actions returned by this hook wrap the underlying publishDps; calling actions does not trigger an immediate rerender of the component.
> Only when the command is sent successfully and the device reports a new DP state will components that use the corresponding useStructuredDevicesProps and whose selectors match be rerendered.

### Description

Get a collection of structured DP action methods for associated devices; must be used with the dp-kit interceptor

### Parameters

None


### Return Value

Type: `DevicesActions`

A collection of structured action methods; the key is the device identifier and the value is that device’s structured actions.
Usage is the same as single-device useStructuredActions

**`interface` DevicesActions**

```typescript
interface DevicesActions {
  [key: string]: {
    set: (value: object, options?: SendDpOption) => Promise<boolean>;
  };
}
```

### Referenced Types

##### `interface` DevicesActions

```typescript
interface DevicesActions {
  [key: string]: {
    set: (value: object, options?: SendDpOption) => Promise<boolean>;
  };
}
```

##### `type` IgnoreDpChangeInterceptorOptions

Configuration option to ignore the DP data change interceptor

Used to configure the debounce mechanism for DP reporting events on the device panel, preventing immediate responses after panel operations from affecting user experience or business logic

| Property | Type | Description |
| --- | --- | --- |
| `whiteDpCodes` | `string[]` | DP whitelist; reports will not be ignored |
| `timeout` | `number` | Debounce timeout check, in milliseconds, default 5000 - The maximum time between sending a DP from the panel and receiving the DP reply; dpDataChange is triggered only if this is exceeded. - Used to debounce DP reporting events |
| `customRule` | `(dpState: DpState, lastSendTimestamp: number) => boolean` | Custom ignore rules > Highest priority; when configured, whiteDpCodes and timeout become ineffective |

##### `type` DevPropInterceptorOptions

| Property | Type | Description |
| --- | --- | --- |
| `blackDpCodes` | `string[]` | DP blacklist; will not be synchronized to the cloud |
| `defaultState` | `DpState` | Default device state on first entry; supports async initialization |
| `throttle` | `number` | Send throttling, in milliseconds, defaults to 0 If set to 0, throttling is disabled. |

##### `type` CustomRawDpMap

Custom DP protocol converter for transforming between raw DP strings and structured objects.
Suitable for composite DPs of type raw/string (e.g., a light's colour_data "00ff003e8"),
splitting a single string into multiple semantic fields (e.g., { hue, saturation, value }).

| Property | Type | Description |
| --- | --- | --- |
| `parser` | `(dpValue: string) => any` | Parse the raw DP string reported by the device into a structured object |
| `formatter` | `(parsedDpValue: any) => string` | Serialize the structured object into a DP string to be sent to the device |

##### `type` SendDpOption

DP send options. Can be used as the global default configuration for createDpKit, and can also be overridden in a single publishDps/action call.
The global `sendDpOption` suits product-level defaults;
options passed for a single send are suitable for temporarily overriding throttling, debouncing, protocol parsing, or optimistic update strategies.
Note: requires the dp-kit interceptor.

| Property | Type | Since | Description |
| --- | --- | --- | --- |
| `immediate` | `boolean` | - | Whether to trigger a state update immediately; requires the dp-kit interceptor |
| `ignoreDpDataResponse` | `boolean \| IgnoreDpChangeInterceptorOptions` | `1.11.0` | Whether to ignore DP reports; default false |
| `synchronizeDevProperty` | `boolean \| DevPropInterceptorOptions` | `1.11.0` | Whether to sync dpData with cloud device properties; default false |
| `ordered` | `boolean` | - | Whether to send multiple DPs in the order of the object’s keys; requires the dp-kit interceptor; default false |
| `checkRepeat` | `boolean` | - | Whether to check for duplicate values and skip sending; requires the dp-kit interceptor; default false Compared with the current `dpState`; duplicates are detected and not sent |
| `delay` | `number` | - | Delayed send; requires the dp-kit interceptor; default 0, in ms |
| `throttle` | `number` | - | Send throttling (conflicts with debounce); requires the dp-kit interceptor; default 0, in ms |
| `debounce` | `number` | - | Send debounce (conflicts with throttle); requires the dp-kit interceptor; default 0, in ms |
| `protocols` | `Record<string, CustomRawDpMap>` | - | A per-call DP protocol converter; requires the dp-kit interceptor. The key is the dpCode and the value is a `{ parser, formatter }` object: - parser(dpValue: string) => any — parses the raw DP string into a structured object - formatter(parsedValue: any) => string — serializes the structured object into a DP string Affects only this invocation and does not override the global protocols configuration in createDpKit |

##### `type` DpState

Datapoint status object, where the key is the datapoint code and the value is the datapoint value.

```typescript
export type DpState = Record<string, DpValue>;
```

##### `interface` DpSchema

| Property | Type | Description |
| --- | --- | --- |
| `attr` | `number` | DP attribute flag bit, used to mark additional capabilities of the DP |
| `canTrigger` | `boolean` | Whether it can be used as an automation trigger condition |
| `code` | `string` | DP code, e.g., switch |
| `defaultRecommend` | `boolean` | Whether it is the default recommended DP |
| `editPermission` | `boolean` | Whether it has edit permission |
| `executable` | `boolean` | Whether it can be issued (sent downstream) |
| `extContent` | `string` | DP extension content, typically a JSON string |
| `iconname` | `string` | DP icon name |
| `id` | `string \| number` | DP ID |
| `mode` | `"rw" \| "ro" \| "wr"` | DP mode type rw: writable and reportable (read/write) ro: report-only (read-only) wr: write-only |
| `name` | `string` | DP name, typically used in voice scenarios |
| `property` | `Object` | DP attributes |
| `type` | `"raw" \| "obj"` | DP data type categories: raw for raw byte stream, obj for structured object |

##### `type` DpValue

Datapoint value type, which can be boolean, number, or string.

```typescript
export type DpValue = boolean | number | string;
```

##### `type` DpSchema.property

| Property | Type | Description |
| --- | --- | --- |
| `type` | `"string" \| "bool" \| "value" \| "enum" \| "bitmap" \| "raw"` | DP type |
| `range` | `string[] \| string[]` | Enum value range; present only when type = enum |
| `label` | `string[] \| string[]` | Fault label list; present only when type = bitmap |
| `maxlen` | `number` | Maximum length for fault bitmap; present only when type = bitmap |
| `unit` | `string` | Unit (type = value only) |
| `min` | `number` | Minimum value (type = value only) |
| `max` | `number` | Maximum value (type = value only) |
| `scale` | `number` | Precision (type = value only) |
| `step` | `number` | Step (type = value only) |


### Examples

#### End-to-end flow: configure dp-kit + read + send (using lighting colour_data as an example)

```tsx
// ---- 1. devices/protocols/index.ts: Instantiate parser and map it to the DP code ----
import { protocols as sdkProtocols } from '@ray-js/panel-sdk';
import { lampSchemaMap } from '../schema';

export const protocols = {
  [lampSchemaMap.colour_data.code]: new sdkProtocols.ColourTransformer(),
  // ColourTransformer.parser() returns { hue, saturation, value } → read via useStructuredDevicesProps
  // ColourTransformer.formatter() accepts { hue, saturation, value } → write via useStructuredDevicesActions
};

// ---- 2. devices/index.ts: Create dpKit and inject into SmartDevicesManager ----
import { createDpKit, SmartDevicesManager } from '@ray-js/panel-sdk';
import { protocols } from '@/devices/protocols';

export const dpKit = createDpKit({ protocols });
export const deviceManager = new SmartDevicesManager();

// Inject dp-kit interceptors during batchAdd
deviceManager.batchAdd([
  { key: 'lamp1', deviceId: 'xxx_device_id_1', interceptors: dpKit.interceptors },
  { key: 'lamp2', deviceId: 'xxx_device_id_2', interceptors: dpKit.interceptors },
]);

// ---- 3. Page component: dispatch structured data via useStructuredDevicesActions ----
import { View, Text } from '@ray-js/ray';
import { useStructuredDevicesProps, useStructuredDevicesActions } from '@ray-js/panel-sdk';

export default function ColourControl() {
  // Recommended: select only the required state to avoid unnecessary re-renders due to unrelated changes
  const colourData = useStructuredDevicesProps(props => props.lamp1?.colour_data);
  const actions = useStructuredDevicesActions();

  const setHue = (hue: number) => {
    actions.lamp1?.colour_data.set({ ...colourData, hue });
  };

  return (
    <View onClick={() => setHue(120)}>
      <Text>Current hue: {colourData?.hue}</Text>
      <Text>Click to set hue to 120</Text>
    </View>
  );
}
```
