diff --git a/components/tuya/actions/list-devices/list-devices.mjs b/components/tuya/actions/list-devices/list-devices.mjs
new file mode 100644
index 0000000000000..308586dadfc24
--- /dev/null
+++ b/components/tuya/actions/list-devices/list-devices.mjs
@@ -0,0 +1,43 @@
+import tuya from "../../tuya.app.mjs";
+
+export default {
+  key: "tuya-list-devices",
+  name: "List Devices",
+  description: "Get a list of devices associated with a home. [See the documentation](https://developer.tuya.com/en/docs/cloud/d7ee73aadb?id=Kawfjer0wkt2a)",
+  version: "0.0.1",
+  type: "action",
+  props: {
+    tuya,
+    userId: {
+      propDefinition: [
+        tuya,
+        "userId",
+      ],
+    },
+    homeId: {
+      propDefinition: [
+        tuya,
+        "homeId",
+        (c) => ({
+          userId: c.userId,
+        }),
+      ],
+      optional: true,
+    },
+  },
+  async run({ $ }) {
+    const response = this.homeId
+      ? await this.tuya.listHomeDevices({
+        homeId: this.homeId,
+      })
+      : await this.tuya.listUserDevices({
+        userId: this.userId,
+      });
+    if (response?.result?.length) {
+      $.export("$summary", `Found ${response.result.length} device${response.result.length === 1
+        ? ""
+        : "s"}`);
+    }
+    return response;
+  },
+};
diff --git a/components/tuya/actions/list-homes/list-homes.mjs b/components/tuya/actions/list-homes/list-homes.mjs
new file mode 100644
index 0000000000000..8d6c4eec44bad
--- /dev/null
+++ b/components/tuya/actions/list-homes/list-homes.mjs
@@ -0,0 +1,29 @@
+import tuya from "../../tuya.app.mjs";
+
+export default {
+  key: "tuya-list-homes",
+  name: "List Homes",
+  description: "Based on the user ID, query the list of homes where the specified user belongs. [See the documentation](https://developer.tuya.com/en/docs/cloud/f5dd40ed14?id=Kawfjh9hpov1n)",
+  version: "0.0.1",
+  type: "action",
+  props: {
+    tuya,
+    userId: {
+      propDefinition: [
+        tuya,
+        "userId",
+      ],
+    },
+  },
+  async run({ $ }) {
+    const response = await this.tuya.listHomes({
+      userId: this.userId,
+    });
+    if (response?.result?.length) {
+      $.export("$summary", `Found ${response.result.length} home${response.result.length === 1
+        ? ""
+        : "s"}`);
+    }
+    return response;
+  },
+};
diff --git a/components/tuya/actions/send-instructions-to-device/send-instructions-to-device.mjs b/components/tuya/actions/send-instructions-to-device/send-instructions-to-device.mjs
new file mode 100644
index 0000000000000..0f34200843212
--- /dev/null
+++ b/components/tuya/actions/send-instructions-to-device/send-instructions-to-device.mjs
@@ -0,0 +1,69 @@
+import tuya from "../../tuya.app.mjs";
+
+export default {
+  key: "tuya-send-instructions-to-device",
+  name: "Send Instructions to Device",
+  description: "Send an instruction to the specified device. [See the documentation](https://developer.tuya.com/en/docs/cloud/device-control?id=K95zu01ksols7#title-35-Send%20instructions%20to%20the%20device)",
+  version: "0.0.1",
+  type: "action",
+  props: {
+    tuya,
+    userId: {
+      propDefinition: [
+        tuya,
+        "userId",
+      ],
+    },
+    homeId: {
+      propDefinition: [
+        tuya,
+        "homeId",
+        (c) => ({
+          userId: c.userId,
+        }),
+      ],
+      optional: true,
+    },
+    deviceId: {
+      propDefinition: [
+        tuya,
+        "deviceId",
+        (c) => ({
+          userId: c.userId,
+          homeId: c.homeId,
+        }),
+      ],
+    },
+    instructionCode: {
+      propDefinition: [
+        tuya,
+        "instructionCode",
+        (c) => ({
+          deviceId: c.deviceId,
+        }),
+      ],
+    },
+    value: {
+      type: "string",
+      label: "Value",
+      description: "The value to set",
+    },
+  },
+  async run({ $ }) {
+    const response = await this.tuya.sendInstructionsToDevice({
+      deviceId: this.deviceId,
+      data: {
+        commands: [
+          {
+            code: this.instructionCode,
+            value: this.value,
+          },
+        ],
+      },
+    });
+    if (response.success) {
+      $.export("$summary", "Successfully sent instructions to device");
+    }
+    return response;
+  },
+};
diff --git a/components/tuya/package.json b/components/tuya/package.json
index 6de3afdd66cc7..8674e909b2b55 100644
--- a/components/tuya/package.json
+++ b/components/tuya/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@pipedream/tuya",
-  "version": "0.0.1",
+  "version": "0.1.0",
   "description": "Pipedream Tuya Components",
   "main": "tuya.app.mjs",
   "keywords": [
@@ -11,5 +11,9 @@
   "author": "Pipedream <support@pipedream.com> (https://pipedream.com/)",
   "publishConfig": {
     "access": "public"
+  },
+  "dependencies": {
+    "@pipedream/platform": "^3.0.3",
+    "@tuya/tuya-connector-nodejs": "^2.1.2"
   }
-}
\ No newline at end of file
+}
diff --git a/components/tuya/sources/new-device-parameter-updated/new-device-parameter-updated.mjs b/components/tuya/sources/new-device-parameter-updated/new-device-parameter-updated.mjs
new file mode 100644
index 0000000000000..a230beaa3af84
--- /dev/null
+++ b/components/tuya/sources/new-device-parameter-updated/new-device-parameter-updated.mjs
@@ -0,0 +1,88 @@
+import tuya from "../../tuya.app.mjs";
+import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
+import sampleEmit from "./test-event.mjs";
+
+export default {
+  key: "tuya-new-device-parameter-updated",
+  name: "New Device Parameter Updated",
+  description: "Emit new event when the specified device parameter is updated. [See the documentation](https://developer.tuya.com/en/docs/cloud/device-management?id=K9g6rfntdz78a#title-10-Get%20a%20list%20of%20devices%20under%20a%20specified%20user)",
+  version: "0.0.1",
+  type: "source",
+  dedupe: "unique",
+  props: {
+    tuya,
+    db: "$.service.db",
+    timer: {
+      type: "$.interface.timer",
+      default: {
+        intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
+      },
+    },
+    userId: {
+      propDefinition: [
+        tuya,
+        "userId",
+      ],
+    },
+    deviceParameter: {
+      type: "string",
+      label: "Device Parameter",
+      description: "The device parameter to watch for updates. E.g. `switch_1`",
+    },
+    homeId: {
+      propDefinition: [
+        tuya,
+        "homeId",
+        (c) => ({
+          userId: c.userId,
+        }),
+      ],
+      optional: true,
+    },
+  },
+  methods: {
+    _getPreviousValues() {
+      return this.db.get("previousValues") || {};
+    },
+    _setPreviousValues(previousValues) {
+      this.db.set("previousValues", previousValues);
+    },
+    getCurrentValue(device) {
+      const { status } = device;
+      const relevantStatus = status.find(({ code }) => code === this.deviceParameter);
+      return relevantStatus?.value;
+    },
+    generateMeta(item) {
+      const ts = Date.now();
+      return {
+        id: `${item.id}${ts}`,
+        summary: `Device Updated with ID: ${item.id}`,
+        ts,
+      };
+    },
+  },
+  async run() {
+    const previousValues = this._getPreviousValues();
+    const newValues = {};
+
+    const { result: devices } = this.homeId
+      ? await this.tuya.listHomeDevices({
+        homeId: this.homeId,
+      })
+      : await this.tuya.listUserDevices({
+        userId: this.userId,
+      });
+
+    for (const device of devices) {
+      const currentValue = this.getCurrentValue(device);
+      if (previousValues[device.id] !== currentValue) {
+        const meta = this.generateMeta(device);
+        this.$emit(device, meta);
+      }
+      newValues[device.id] = currentValue;
+    }
+
+    this._setPreviousValues(newValues);
+  },
+  sampleEmit,
+};
diff --git a/components/tuya/sources/new-device-parameter-updated/test-event.mjs b/components/tuya/sources/new-device-parameter-updated/test-event.mjs
new file mode 100644
index 0000000000000..31d394ee1c983
--- /dev/null
+++ b/components/tuya/sources/new-device-parameter-updated/test-event.mjs
@@ -0,0 +1,77 @@
+export default {
+    "active_time": 1748632139,
+    "biz_type": 18,
+    "category": "cz",
+    "create_time": 1748632139,
+    "icon": "smart/icon/bay1599677305883cNM4/03aaf2fd77d712895eb7b8408a374ebe.png",
+    "id": "vdevo174863213925233",
+    "ip": "47.225.143.157",
+    "lat": "",
+    "local_key": ".'0k9<h@|2j7!OK9",
+    "lon": "",
+    "model": "TS-441",
+    "name": "Tramontina  Plug-vdevo",
+    "online": true,
+    "owner_id": "250587566",
+    "product_id": "mjzxchzvqmxps3lf",
+    "product_name": "Plugue Tramontina",
+    "status": [
+      {
+        "code": "switch_1",
+        "value": false
+      },
+      {
+        "code": "countdown_1",
+        "value": 0
+      },
+      {
+        "code": "add_ele",
+        "value": 0
+      },
+      {
+        "code": "cur_current",
+        "value": 0
+      },
+      {
+        "code": "cur_power",
+        "value": 0
+      },
+      {
+        "code": "cur_voltage",
+        "value": 0
+      },
+      {
+        "code": "relay_status",
+        "value": "power_off"
+      },
+      {
+        "code": "overcharge_switch",
+        "value": false
+      },
+      {
+        "code": "light_mode",
+        "value": "relay"
+      },
+      {
+        "code": "child_lock",
+        "value": false
+      },
+      {
+        "code": "cycle_time",
+        "value": ""
+      },
+      {
+        "code": "random_time",
+        "value": ""
+      },
+      {
+        "code": "switch_inching",
+        "value": ""
+      }
+    ],
+    "sub": false,
+    "time_zone": "",
+    "uid": "az1748632127862aWriL",
+    "update_time": 1748632139,
+    "uuid": "vdevo174863213925233"
+  }
\ No newline at end of file
diff --git a/components/tuya/tuya.app.mjs b/components/tuya/tuya.app.mjs
index 7cf9ecd689e92..c51da7b9190ca 100644
--- a/components/tuya/tuya.app.mjs
+++ b/components/tuya/tuya.app.mjs
@@ -1,11 +1,122 @@
+import { TuyaContext } from "@tuya/tuya-connector-nodejs";
+import { ConfigurationError } from "@pipedream/platform";
+
 export default {
   type: "app",
   app: "tuya",
-  propDefinitions: {},
+  propDefinitions: {
+    userId: {
+      type: "string",
+      label: "User ID",
+      description: "The unique identifier of a user. E.g. `az1748632127862aWriL`",
+    },
+    homeId: {
+      type: "string",
+      label: "Home ID",
+      description: "The identifier of a home",
+      async options({ userId }) {
+        const { result } = await this.listHomes({
+          userId,
+        });
+        return result?.map(({
+          home_id: value, name: label,
+        }) => ({
+          label,
+          value,
+        })) || [];
+      },
+    },
+    deviceId: {
+      type: "string",
+      label: "Device ID",
+      description: "The identifier of a device",
+      async options({
+        userId, homeId,
+      }) {
+        const { result } = homeId
+          ? await this.listHomeDevices({
+            homeId,
+          })
+          : await this.listUserDevices({
+            userId,
+          });
+        return result?.map(({
+          id: value, name: label,
+        }) => ({
+          label,
+          value,
+        })) || [];
+      },
+    },
+    instructionCode: {
+      type: "string",
+      label: "Instruction Code",
+      description: "The code of the command to use. E.g. `switch_1`",
+      async options({ deviceId }) {
+        const { result } = await this.listDeviceFunctions({
+          deviceId,
+        });
+        return result?.functions?.map(({
+          code: value, name: label,
+        }) => ({
+          label,
+          value,
+        })) || [];
+      },
+    },
+  },
   methods: {
-    // this.$auth contains connected account data
-    authKeys() {
-      console.log(Object.keys(this.$auth));
+    _getClient() {
+      return new TuyaContext({
+        baseUrl: this.$auth.base_url,
+        accessKey: this.$auth.client_id,
+        secretKey: this.$auth.client_secret,
+      });
+    },
+    async _makeRequest({
+      method = "GET",
+      path,
+      data = {},
+    }) {
+      const response = await this._getClient().request({
+        method,
+        path,
+        body: data,
+      });
+      if (!response.success) {
+        console.log(response);
+        throw new ConfigurationError(`${response.msg}`);
+      }
+      return response;
+    },
+    listHomes({ userId }) {
+      return this._makeRequest({
+        path: `/v1.0/users/${userId}/homes`,
+      });
+    },
+    listUserDevices({ userId }) {
+      return this._makeRequest({
+        path: `/v1.0/users/${userId}/devices`,
+      });
+    },
+    listHomeDevices({ homeId }) {
+      return this._makeRequest({
+        path: `/v1.0/homes/${homeId}/devices`,
+      });
+    },
+    listDeviceFunctions({ deviceId }) {
+      return this._makeRequest({
+        path: `/v1.0/devices/${deviceId}/functions`,
+      });
+    },
+    sendInstructionsToDevice({
+      deviceId, data,
+    }) {
+      return this._makeRequest({
+        method: "POST",
+        path: `/v1.0/devices/${deviceId}/commands`,
+        data,
+      });
     },
   },
-};
\ No newline at end of file
+};
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 795127a8cf399..5b11895ca85bc 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -13491,7 +13491,14 @@ importers:
 
   components/tutor_lms: {}
 
-  components/tuya: {}
+  components/tuya:
+    dependencies:
+      '@pipedream/platform':
+        specifier: ^3.0.3
+        version: 3.0.3
+      '@tuya/tuya-connector-nodejs':
+        specifier: ^2.1.2
+        version: 2.1.2
 
   components/twelve_data: {}
 
@@ -19800,6 +19807,9 @@ packages:
   '@tsconfig/node14@1.0.3':
     resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
 
+  '@tuya/tuya-connector-nodejs@2.1.2':
+    resolution: {integrity: sha512-8tM7QlOF1QQrT3iQgcHp4JDNRUdOyi06h8F5ZL7antQZYP67TRQ2/puisoo2uhdXo+n+GT0B605pWaDqr9nPrA==}
+
   '@types/acorn@4.0.6':
     resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==}
 
@@ -36373,6 +36383,13 @@ snapshots:
 
   '@tsconfig/node14@1.0.3': {}
 
+  '@tuya/tuya-connector-nodejs@2.1.2':
+    dependencies:
+      axios: 0.21.4
+      qs: 6.13.1
+    transitivePeerDependencies:
+      - debug
+
   '@types/acorn@4.0.6':
     dependencies:
       '@types/estree': 1.0.6