跳到主要内容

简介

完成基础自定义后,可能需要添加更多功能、修改默认行为、自定义 UI 控制面板等,以满足产品和应用需求。

本节介绍如何自定义设备控制面板界面或参数控制,甚至可以扩展现有的通知功能。

前提条件

假设你已经准备好应用开发环境。请按照说明设置开发环境。以下所有参考内容均基于克隆自 GitHub 的 ESP RainMaker Home 示例应用源码仓库。

假设你已经了解混合应用的工作原理,并熟悉 React Native 和 Expo 应用开发流程。

API 配置

自定义 API 端点

rainmaker.config.ts 中自定义 ESP RainMaker API 端点和认证设置:

export const SDKConfig = {
baseUrl: "https://your-custom-api.com", // 自定义 API 端点
version: "v1",
authUrl: "https://your-custom-auth.com", // 自定义 OAuth 端点
clientId: "your-client-id", // OAuth 客户端 ID
redirectUrl: "yourapp://com.yourcompany.yourapp/success", // OAuth 重定向 URL
customStorageAdapter: asyncStorageAdapter,
localDiscoveryAdapter: EspLocalDiscoveryAdapter,
localControlAdapter: ESPLocalControlAdapter,
provisionAdapter: provisionAdapter,
notificationAdapter: ESPNotificationAdapter,
oauthAdapter: espOauthAdapter,
appUtilityAdapter: ESPAppUtilityAdapter,
};

环境特定配置

可以为不同环境创建配置:

// 开发环境配置
const developmentConfig = {
baseUrl: "https://api.staging.rainmaker.espressif.com",
};

// 生产环境配置
const productionConfig = {
baseUrl: "https://api.rainmaker.espressif.com",
};

// 根据环境使用相应的配置
export const SDKConfig = __DEV__ ? developmentConfig : productionConfig;

自定义设备控制面板

打开源代码,在 app/(device)/device_panels/ 目录下创建新的面板组件来自定义设备控制面板。

现有设备面板:

  • Light.tsx - 灯光设备控制面板
  • Switch.tsx - 开关设备控制面板
  • Temperature.tsx - 温度传感器面板
  • Fallback.tsx - 默认回退面板

创建自定义设备面板

  1. app/(device)/device_panels/ 目录下创建新的 TypeScript 文件
  2. 导入必要的组件和 hooks
  3. 实现自定义 UI 和控制逻辑
  4. 在设备配置中注册面板

示例 - 自定义灯光面板结构:

// app/(device)/device_panels/CustomLight.tsx
import React from "react";
import { View, Text, StyleSheet } from "react-native";
import { observer } from "mobx-react-lite";
import { useToast } from "@/hooks/useToast";
import { useTranslation } from "react-i18next";
import {
PowerButton,
BrightnessSlider,
HueSlider,
SaturationSlider,
} from "@/components/ParamControls";
import { ControlPanelProps } from "@/types/global";

const CustomLightPanel: React.FC<ControlPanelProps> = ({ device, node }) => {
const { t } = useTranslation();
const toast = useToast();

return (
<View style={styles.container}>
<PowerButton device={device} node={node} />
<BrightnessSlider device={device} node={node} />
<HueSlider device={device} node={node} />
<SaturationSlider device={device} node={node} />
{/* 在此处添加自定义控件 */}
</View>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
});

export default observer(CustomLightPanel);

自定义参数控件

components/ParamControls/ 目录下添加新的参数控件类型,以支持自定义设备参数。

现有参数控件:

  • PowerButton.tsx - 电源开/关控件
  • BrightnessSlider.tsx - 亮度控件
  • HueSlider.tsx - 色相控件
  • SaturationSlider.tsx - 饱和度控件
  • ColorTemperatureSlider.tsx - 色温控件
  • SpeedSlider.tsx - 风扇速度控件
  • TemperatureSlider.tsx - 温度控件
  • ToggleSwitch.tsx - 切换开关控件
  • Slider.tsx - 通用滑块控件
  • DropdownSelector.tsx - 下拉选择器
  • TextInput.tsx - 文本输入控件

创建自定义参数控件

  1. components/ParamControls/ 目录下创建新组件
  2. 实现参数控件接口
  3. 处理参数值变化
  4. components/ParamControls/index.ts 导出控件

示例 - 自定义滑块控件:

// components/ParamControls/CustomSlider.tsx
import React, { useState } from "react";
import { View, Text, StyleSheet } from "react-native";
import { Slider } from "@miblanchard/react-native-slider";
import { tokens } from "@/theme/tokens";

interface CustomSliderProps {
value: number;
min: number;
max: number;
step: number;
onValueChange: (value: number) => void;
label: string;
}

export const CustomSlider: React.FC<CustomSliderProps> = ({
value,
min,
max,
step,
onValueChange,
label,
}) => {
const [localValue, setLocalValue] = useState(value);

const handleValueChange = (values: number[]) => {
setLocalValue(values[0]);
};

const handleSlidingComplete = (values: number[]) => {
onValueChange(values[0]);
};

return (
<View style={styles.container}>
<Text style={styles.label}>{label}</Text>
<Slider
value={localValue}
minimumValue={min}
maximumValue={max}
step={step}
onValueChange={handleValueChange}
onSlidingComplete={handleSlidingComplete}
minimumTrackTintColor={tokens.colors.primary}
maximumTrackTintColor={tokens.colors.lightGray}
/>
<Text style={styles.value}>{Math.round(localValue)}</Text>
</View>
);
};

const styles = StyleSheet.create({
container: {
padding: 16,
},
label: {
fontSize: 16,
marginBottom: 8,
},
value: {
textAlign: "center",
fontSize: 14,
marginTop: 8,
},
});

自定义适配器

ESP RainMaker App SDK 支持通过适配器扩展自定义功能。SDK 提供了接口,可以实现适配器以满足功能需求。

自定义存储适配器

存储适配器处理所有键值存储操作,位于 adaptors/implementations/ESPAsyncStorage.ts 中:

import AsyncStorage from "@react-native-async-storage/async-storage";
import { ESPRMStorageAdapterInterface } from "@espressif/rainmaker-base-sdk";

export const asyncStorageAdapter: ESPRMStorageAdapterInterface = {
setItem: async (name: string, value: string) => {
try {
await AsyncStorage.setItem(name, value);
} catch (error) {
throw error;
}
},

getItem: async (name: string): Promise<string | null> => {
try {
const response = await AsyncStorage.getItem(name);
return response;
} catch (error) {
throw error;
}
},

removeItem: async (name: string) => {
try {
await AsyncStorage.removeItem(name);
} catch (error) {
throw error;
}
},

clear: async () => {
try {
await AsyncStorage.clear();
} catch (error) {
throw error;
}
},
};

export default asyncStorageAdapter;

创建自定义存储适配器:

  1. 实现 ESPRMStorageAdapterInterface 接口
  2. setItemgetItemremoveItemclear 提供具体实现
  3. rainmaker.config.ts 中注册适配器

自定义通知适配器

通知适配器用于处理推送通知功能,位于 adaptors/implementations/ESPNotificationAdapter.ts 中:

import { DeviceEventEmitter, EmitterSubscription } from "react-native";
import ESPNotificationModule from "../interfaces/ESPNotificationInterface";

export const ESPNotificationAdapter = {
currentListener: null as EmitterSubscription | null,

addNotificationListener: async (
callback: (data: Record<string, any>) => void
): Promise<() => void> => {
try {
if (ESPNotificationAdapter.currentListener) {
ESPNotificationAdapter.removeNotificationListener();
}

// 监听并处理传入的通知
const notificationListener = DeviceEventEmitter.addListener(
"ESPNotificationModule",
(data: Record<string, any>) => {
callback(data); // 使用接收到的数据调用回调
}
);

// 保存监听器引用以便移除
ESPNotificationAdapter.currentListener = notificationListener;

// 返回清理函数以移除通知监听器
return () => {
ESPNotificationAdapter.removeNotificationListener();
};
} catch (error) {
return () => {}; // 发生错误时返回空操作清理函数
}
},

removeNotificationListener: (): void => {
try {
if (ESPNotificationAdapter.currentListener) {
ESPNotificationAdapter.currentListener.remove();
ESPNotificationAdapter.currentListener = null;
}
} catch (error) {
throw error;
}
},

getNotificationPlatform: async (): Promise<string> => {
try {
const platform = await ESPNotificationModule.getNotificationPlatform();
return platform;
} catch (error) {
console.error("Error getting notification platform:", error);
throw error;
}
},
};

创建自定义通知适配器:

  1. 实现通知适配器接口
  2. addNotificationListenerremoveNotificationListenergetNotificationPlatform 提供具体实现
  3. rainmaker.config.ts 中注册适配器

适配器注册

创建自定义适配器后,在 rainmaker.config.ts 中进行注册:

import { customStorageAdapter } from "@/adaptors/implementations/CustomStorage";
import { customNotificationAdapter } from "@/adaptors/implementations/CustomNotifications";

export const SDKConfig = {
baseUrl: "https://api.rainmaker.espressif.com",
version: "v1",
authUrl: "https://3pauth.rainmaker.espressif.com",
clientId: "1h7ujqjs8140n17v0ahb4n51m2",
redirectUrl: "rainmaker://com.espressif.novahome/success",
customStorageAdapter: customStorageAdapter, // 自定义适配器
notificationAdapter: customNotificationAdapter, // 自定义适配器
// ... 其他适配器
};

⚠️ 重要声明:本仓库中提供的公共部署详情和配置仅用于开发和教育目的不得用于商业用途

On this page