Skip to content

Commit

Permalink
feat(new-plugin): eliza samsung smarthings plugin (#2678)
Browse files Browse the repository at this point in the history
* fix(plugin-depin): sentientAI description (#2668)

* client-eliza-home

client-eliza-home

* basic import fixes

---------

Co-authored-by: alex <152680487+bodhi-crypo@users.noreply.github.com>
Co-authored-by: Sayo <hi@sayo.wtf>
  • Loading branch information
3 people authored Jan 23, 2025
1 parent 34ebf70 commit c9c7434
Show file tree
Hide file tree
Showing 25 changed files with 1,442 additions and 51 deletions.
18 changes: 18 additions & 0 deletions packages/client-eliza-home/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@elizaos/client-eliza-home",
"version": "0.1.0",
"main": "dist/index.js",
"type": "module",
"types": "dist/index.d.ts",
"dependencies": {
"@elizaos/core": "workspace:*"
},
"devDependencies": {
"tsup": "8.3.5"
},
"scripts": {
"build": "tsup --format esm --dts",
"dev": "tsup --format esm --dts --watch",
"lint": "eslint . --fix"
}
}
109 changes: 109 additions & 0 deletions packages/client-eliza-home/src/actions/control_device.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import {
Action,
ActionExample,
Content,
HandlerCallback,
IAgentRuntime,
Memory,
State,
} from "@elizaos/core";
import { SmartHomeManager } from "../smart_home.ts";
import { smartThingsApi } from "../services/smart_things_api.ts";
import { deviceStateProvider } from "../providers/device_state.ts";

export const controlDeviceAction = {
name: "CONTROL_DEVICE",
similes: ["DEVICE_CONTROL", "SMART_HOME_CONTROL", "HOME_CONTROL"],
description: "Controls smart home devices with specific commands",
validate: async (runtime: IAgentRuntime, message: Memory) => {
const keywords = [
"turn on",
"turn off",
"switch",
"toggle",
"set",
"change",
"adjust",
"dim",
"brighten",
"lock",
"unlock",
];
return keywords.some(keyword =>
message.content.text.toLowerCase().includes(keyword)
);
},
handler: async (
runtime: IAgentRuntime,
message: Memory,
state: State,
options: any,
callback: HandlerCallback
) => {
const smartHomeManager = new SmartHomeManager(runtime);
const result = await smartHomeManager.handleCommand(message.content.text, message.userId);

const response: Content = {
text: `Command executed: ${result.message || "Success"}`,
action: "DEVICE_CONTROL_RESPONSE",
source: "home-assistant"
};

await callback(response);
return response;
},
examples: [
[
{
user: "{{user1}}",
content: {
text: "Turn on the living room lights",
},
},
{
user: "{{user2}}",
content: {
text: "I'll turn on the living room lights for you",
action: "CONTROL_DEVICE",
},
},
],
] as ActionExample[][],
} as Action;

export async function controlDevice(deviceId: string, command: string, args: any = {}) {
try {
// Map internal commands to SmartThings commands
const smartThingsCommand = mapCommand(command, args);

await smartThingsApi.devices.executeCommand(deviceId, smartThingsCommand);

// Update local device state
await deviceStateProvider.updateDeviceState(deviceId, command, args);

} catch (error) {
console.error(`Failed to control device ${deviceId}:`, error);
throw error;
}
}

function mapCommand(command: string, args: any) {
// Map our internal commands to SmartThings command format
switch (command) {
case 'turnOn':
return { capability: 'switch', command: 'on' };
case 'turnOff':
return { capability: 'switch', command: 'off' };
case 'setLevel':
return {
capability: 'switchLevel',
command: 'setLevel',
arguments: [args.level]
};
// ... map other commands
default:
throw new Error(`Unknown command: ${command}`);
}
}

export default controlDeviceAction;
113 changes: 113 additions & 0 deletions packages/client-eliza-home/src/actions/discover_devices.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import {
Action,
ActionExample,
Content,
HandlerCallback,
IAgentRuntime,
Memory,
State,
} from "@elizaos/core";
import { EntityManager } from "../entities.ts";
import { CAPABILITIES } from '../capabilities';
import { smartThingsApi } from "../services/smart_things_api.ts";

export const discoverDevicesAction = {
name: "DISCOVER_DEVICES",
similes: ["SCAN_DEVICES", "FIND_DEVICES", "LIST_DEVICES"],
description: "Discovers and lists all available smart home devices",
validate: async (runtime: IAgentRuntime, message: Memory) => {
const keywords = [
"discover",
"find",
"scan",
"list",
"show",
"what",
"devices",
"lights",
"switches",
];
return keywords.some(keyword =>
message.content.text.toLowerCase().includes(keyword)
);
},
handler: async (
runtime: IAgentRuntime,
message: Memory,
state: State,
options: any,
callback: HandlerCallback
) => {
const entityManager = new EntityManager(runtime);
await entityManager.discoverEntities();

const entities = entityManager.getAllEntities();
const deviceList = entities
.map(entity => `- ${entity.name} (${entity.entityId}): ${entity.state}`)
.join('\n');

const response: Content = {
text: `Here are all the available devices:\n\n${deviceList}`,
action: "DEVICE_LIST_RESPONSE",
source: "home-assistant"
};

await callback(response);
return response;
},
examples: [
[
{
user: "{{user1}}",
content: {
text: "What devices do you see?",
},
},
{
user: "{{user2}}",
content: {
text: "Let me check what devices are available...",
action: "DISCOVER_DEVICES",
},
},
],
] as ActionExample[][],
} as Action;

export default discoverDevicesAction;

export async function discoverDevices() {
// Implementation to discover SmartThings devices
try {
const devices = await smartThingsApi.devices.list();

return devices.map(device => ({
id: device.deviceId,
name: device.label || device.name,
capabilities: device.capabilities.map(cap => ({
id: cap.id,
version: cap.version
})),
room: device.roomId,
status: parseDeviceStatus(device.status)
}));
} catch (error) {
console.error('Failed to discover devices:', error);
throw error;
}
}

function parseDeviceStatus(status: any) {
// Convert SmartThings status format to our internal format
const deviceStatus: any = {};

if (status.switch) {
deviceStatus.switch = status.switch.value;
}
if (status.level) {
deviceStatus.level = status.level.value;
}
// ... parse other status values

return deviceStatus;
}
109 changes: 109 additions & 0 deletions packages/client-eliza-home/src/capabilities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { IAgentRuntime } from "@elizaos/core";

// Define SmartThings capability interfaces
export interface SmartThingsCapability {
id: string;
version: number;
}

export const CAPABILITIES = {
// Basic capabilities
SWITCH: { id: 'switch', version: 1 },
POWER_METER: { id: 'powerMeter', version: 1 },
ENERGY_METER: { id: 'energyMeter', version: 1 },

// Climate capabilities
THERMOSTAT: { id: 'thermostat', version: 1 },
TEMPERATURE_MEASUREMENT: { id: 'temperatureMeasurement', version: 1 },
HUMIDITY_MEASUREMENT: { id: 'humidityMeasurement', version: 1 },

// Lighting capabilities
SWITCH_LEVEL: { id: 'switchLevel', version: 1 },
COLOR_CONTROL: { id: 'colorControl', version: 1 },
COLOR_TEMPERATURE: { id: 'colorTemperature', version: 1 },

// Security capabilities
LOCK: { id: 'lock', version: 1 },
MOTION_SENSOR: { id: 'motionSensor', version: 1 },
CONTACT_SENSOR: { id: 'contactSensor', version: 1 },
PRESENCE_SENSOR: { id: 'presenceSensor', version: 1 },

// Media capabilities
MEDIA_PLAYBACK: { id: 'mediaPlayback', version: 1 },
VOLUME: { id: 'volume', version: 1 },

// Window/Door capabilities
WINDOW_SHADE: { id: 'windowShade', version: 1 },
GARAGE_DOOR: { id: 'garageDoor', version: 1 },

// Fan capabilities
FAN_SPEED: { id: 'fanSpeed', version: 1 },

// Battery capabilities
BATTERY: { id: 'battery', version: 1 },
} as const;

export type CapabilityType = keyof typeof CAPABILITIES;

export interface Capability {
interface: string;
version: string;
type: string;
properties: {
supported: Array<{
name: string;
}>;
proactivelyReported: boolean;
retrievable: boolean;
};
}

export class CapabilityManager {
private runtime: IAgentRuntime;
private capabilities: Map<string, Capability>;

constructor(runtime: IAgentRuntime) {
this.runtime = runtime;
this.capabilities = new Map();
this.initializeCapabilities();
}

private initializeCapabilities() {
// Add standard capabilities
this.addCapability({
interface: "Alexa.PowerController",
version: "3",
type: "AlexaInterface",
properties: {
supported: [{ name: "powerState" }],
proactivelyReported: true,
retrievable: true,
},
});

this.addCapability({
interface: "Alexa.BrightnessController",
version: "3",
type: "AlexaInterface",
properties: {
supported: [{ name: "brightness" }],
proactivelyReported: true,
retrievable: true,
},
});

// Add more capabilities as needed
}

addCapability(capability: Capability) {
this.capabilities.set(capability.interface, capability);
}

getCapability(interfaceName: string): Capability | undefined {
return this.capabilities.get(interfaceName);
}

getAllCapabilities(): Capability[] {
return Array.from(this.capabilities.values());
}
}
Loading

0 comments on commit c9c7434

Please sign in to comment.