跳到主要内容

Introduction

Once you are done with the basic customizations, you may wish to add more features or modify the behaviors, customize UI control panels, and so on to meet your product and app needs.

This section talks about understanding how you can customize a device control panel screen or how you can customize parameter control. You can even extend the existing behavior of notifications.

Pre-Requisite

Assumption is that you already have the app development setup ready. Follow the instructions for setting up the development environment. All the references below would be based on the cloned GitHub repository for the sample ESP RainMaker Home app source code.

Assumption is that you are already aware of how hybrid apps work and are familiar with React Native & Expo app development process.

API Configuration

Custom API Endpoint

Customize the ESP RainMaker API endpoint and authentication settings in rainmaker.config.ts:

export const SDKConfig = {
baseUrl: "https://your-custom-api.com", // Custom API endpoint
version: "v1",
authUrl: "https://your-custom-auth.com", // Custom OAuth endpoint
clientId: "your-client-id", // OAuth client ID
redirectUrl: "yourapp://com.yourcompany.yourapp/success", // OAuth redirect URL
customStorageAdapter: asyncStorageAdapter,
localDiscoveryAdapter: EspLocalDiscoveryAdapter,
localControlAdapter: ESPLocalControlAdapter,
provisionAdapter: provisionAdapter,
notificationAdapter: ESPNotificationAdapter,
oauthAdapter: espOauthAdapter,
appUtilityAdapter: ESPAppUtilityAdapter,
};

Environment-Specific Configuration

You can create environment-specific configurations:

// Development configuration
const developmentConfig = {
baseUrl: "https://api.staging.rainmaker.espressif.com",
};

// Production configuration
const productionConfig = {
baseUrl: "https://api.rainmaker.espressif.com",
};

// Use appropriate configuration based on environment
export const SDKConfig = __DEV__ ? developmentConfig : productionConfig;

Custom Device Control Panel Screen

Go to your source code and create custom device control panels in app/(device)/device_panels/ by creating new panel components.

Existing device panels:

  • Light.tsx - Light device control panel
  • Switch.tsx - Switch device control panel
  • Temperature.tsx - Temperature sensor panel
  • Fallback.tsx - Default fallback panel

Steps to Create a Custom Device Panel

  1. Create a new TypeScript file in app/(device)/device_panels/
  2. Import necessary components and hooks
  3. Implement custom UI and control logic
  4. Register the panel in the device configuration

Example - Custom Light Panel Structure:

// 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} />
{/* Add your custom controls here */}
</View>
);
};

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

export default observer(CustomLightPanel);

Custom Parameter Controls

Add new parameter control types in components/ParamControls/ to support custom device parameters.

Existing parameter controls:

  • PowerButton.tsx - Power on/off control
  • BrightnessSlider.tsx - Brightness control
  • HueSlider.tsx - Color hue control
  • SaturationSlider.tsx - Color saturation control
  • ColorTemperatureSlider.tsx - Color temperature control
  • SpeedSlider.tsx - Fan speed control
  • TemperatureSlider.tsx - Temperature control
  • ToggleSwitch.tsx - Toggle switch control
  • Slider.tsx - Generic slider control
  • DropdownSelector.tsx - Dropdown selector
  • TextInput.tsx - Text input control

Steps to Create a Custom Parameter Control

  1. Create a new component in components/ParamControls/
  2. Implement the parameter control interface
  3. Handle parameter value changes
  4. Export the control from components/ParamControls/index.ts

Example - Custom Slider Control:

// 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,
},
});

Custom Adapters

ESP RainMaker App SDK has a provision to extend the functionality with custom behavior via adapters. The SDK provides interfaces to implement adapters to suit your functional needs.

Custom Storage Adapter

The storage adapter handles all key-value storage operations. Located in 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;

To create a custom storage adapter:

  1. Implement the ESPRMStorageAdapterInterface
  2. Provide implementations for setItem, getItem, removeItem, and clear
  3. Register your adapter in rainmaker.config.ts

Custom Notifications Adapter

The notification adapter handles push notification functionality. Located in 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();
}

// Listen for incoming notifications and handle them
const notificationListener = DeviceEventEmitter.addListener(
"ESPNotificationModule",
(data: Record<string, any>) => {
callback(data); // Invoke the callback with the received data
}
);

// Save listener reference for removal
ESPNotificationAdapter.currentListener = notificationListener;

// Return a cleanup function to remove the notification listener
return () => {
ESPNotificationAdapter.removeNotificationListener();
};
} catch (error) {
return () => {}; // Return a no-op cleanup function in case of an error
}
},

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;
}
},
};

To create a custom notification adapter:

  1. Implement the notification adapter interface
  2. Provide implementations for addNotificationListener, removeNotificationListener, and getNotificationPlatform
  3. Register your adapter in rainmaker.config.ts

Adapter Registration

After creating custom adapters, register them in 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, // Your custom adapter
notificationAdapter: customNotificationAdapter, // Your custom adapter
// ... other adapters
};

⚠️ IMPORTANT NOTICE: The public deployment details and configurations provided in this repository are intended for development and educational purposes only and should NOT be used for commercial purposes.

On this page