Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix switch accessory & add support for Smart IR (wnykq) #115

Merged
merged 3 commits into from
Nov 24, 2022

Conversation

bimusiek
Copy link

@bimusiek
Copy link
Author

bimusiek commented Nov 22, 2022

The error in JSON.parse comes from this response:

[11/22/2022, 10:00:50 PM] [TuyaPlatform] [TuyaOpenAPI] Request:
method = get
endpoint = https://openapi.tuyaeu.com
path = /v1.0/devices/bfc4ee178b05afd31dpaai/specifications
query = undefined
headers = {
  "t": "1669150850482",
  "client_id": "k3akuj97e4kxyckwg3yg",
  "nonce": "95f647f0-5a3e-4d8e-93f2-3b8f8f72b364",
  "Signature-Headers": "client_id",
  "sign": "BF8275C52E787797875F5D10B1CA9427512B549DDF4C2A71612435A2C3DB4368",
  "sign_method": "HMAC-SHA256",
  "access_token": "",
  "lang": "en",
  "dev_lang": "javascript",
  "dev_channel": "homebridge",
  "devVersion": "1.6.0-beta.38"
}
body = null
[11/22/2022, 10:00:50 PM] [TuyaPlatform] [TuyaOpenAPI] Response:
path = /v1.0/devices/bfc4ee178b05afd31dpaai/specifications
data = {
  "result": {
    "category": "infrared_light",
    "functions": [
      {
        "code": "BlueLight",
        "type": "STRING",
        "values": "BlueLight"
      },
      {
        "code": "Brightness+",
        "type": "STRING",
        "values": "Brightness+"
      },
      {
        "code": "Brightness-",
        "type": "STRING",
        "values": "Brightness-"
      },
      {
        "code": "ColdLight",
        "type": "STRING",
        "values": "ColdLight"
      },
      {
        "code": "GreenLight",
        "type": "STRING",
        "values": "GreenLight"
      },
      {
        "code": "PowerOff",
        "type": "STRING",
        "values": "PowerOff"
      },
      {
        "code": "PowerOn",
        "type": "STRING",
        "values": "PowerOn"
      },
      {
        "code": "RedLight",
        "type": "STRING",
        "values": "RedLight"
      },
      {
        "code": "WarmLight",
        "type": "STRING",
        "values": "WarmLight"
      }
    ],
    "status": []
  },
  "success": true,
  "t": 1669150850764,
  "tid": "bed90a666aa811ed854422b2ae449af7"
}

This opens up the way to support Infrared devices I guess? I will try to make it work soon as I have one light that I would love to be able to control.

How do you feel about adding config option to configure infra devices as this seems like a really custom-tailored list of commands. Or maybe I dont know the inner workings of Tuya platform.
Should I implement this infra light as standard Light and "fake" percentage of brightness? Or make it work as "buttons" so simple switches for each command?

@0x5e
Copy link
Owner

0x5e commented Nov 23, 2022

Thanks for the PR, unfortunately the IR device returns wrong specification format, completely different with others, I have contact the cloud development peoples, due to the history reason they refuse to fix. I prefer to let the plugin convert to the same format before we use. I will confirm how to convert these days.

I prefer add config to override per-device or per-product info, instead of just create a device in the config, so we can keep the device list data source is only from one place (from API). The user can add the IR subdevice in the tuya app, then the IR subdevice can both be used in app and plugin.

If it should be implemented as the switch accessory or specific accessory depends on the specific IR data the command sent. In your case the brightness command is "Brightness+" "Brightness-" much like an "action", not "Brightness 60%" "Brightness 70%" as a "state".
The "action" should use Switch Accessory, because if use the Light Accessory with brightness slider, when slider goes to the top but the real device is not bright enough, then there's no way to bright the real device :)
The air-condition mostly send the IR "state" data like "27°C" then the HeaterCooler Accessory may be more suitable for them.

Can we open this PR for a while and let me check the spec convertion things? Thanks for your contribution!

@bimusiek
Copy link
Author

So just to clarify things, Smart IR reports temp and humidity with proper schema. It behaves like thermometer so I think its fine to make it be discovered as one.

Other ir devices could be parsed as each action is a switch but I could prepare separate PR for that.

if (schemas[code]) {
continue;
}
const type = rawType.charAt(0).toUpperCase() + rawType.slice(1).toLowerCase();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My IR device spec is like this:

path = /v1.0/devices/6c66dfa384bdc2bbb2yqql/specifications
data = {
  "result": {
    "category": "infrared_ac",
    "functions": [
      {
        "code": "F",
        "type": "ENUM",
        "values": "{\"min\":0,\"max\":3,\"scale\":0,\"step\":1,\"type\":\"Integer\"}"
      },
      {
        "code": "M",
        "type": "ENUM",
        "values": "{\"min\":0,\"max\":4,\"scale\":0,\"step\":1,\"type\":\"Integer\"}"
      },
      {
        "code": "PowerOff",
        "type": "STRING",
        "values": "PowerOff"
      },
      {
        "code": "PowerOn",
        "type": "STRING",
        "values": "PowerOn"
      },
      {
        "code": "T",
        "type": "ENUM",
        "values": "{\"min\":16,\"max\":30,\"scale\":0,\"step\":1,\"type\":\"Integer\"}"
      }
    ],
    "status": [
      {
        "code": "wind",
        "type": "ENUM",
        "values": "{\"min\":0,\"max\":3,\"scale\":0,\"step\":1,\"type\":\"Integer\"}"
      },
      {
        "code": "mode",
        "type": "ENUM",
        "values": "{\"min\":0,\"max\":4,\"scale\":0,\"step\":1,\"type\":\"Integer\"}"
      },
      {
        "code": "power",
        "type": "BOOLEAN",
        "values": "{}"
      },
      {
        "code": "temp",
        "type": "ENUM",
        "values": "{\"min\":16,\"max\":30,\"scale\":0,\"step\":1,\"type\":\"Integer\"}"
      }
    ]
  },
  "success": true,
  "t": 1667552909972,
  "tid": "3fde5b005c2011ed9f2b629ef151a136"
}

The ENUM actually is Integer, the STRING is like a Enum type with 1 range, BOOLEAN is same as Boolean. They have to be some dirty code to convert this :(

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explaining, I will revert this code for now and we can discuss it further what is the best approach here

@@ -256,10 +256,10 @@ export class TuyaPlatform implements DynamicPlatformPlugin {
this.log.info(`Got home_id=${home_id}, name=${name}`);
if (this.options.homeWhitelist) {
if (this.options.homeWhitelist.includes(home_id)) {
this.log.info(`Found home_id=${home_id} in whitelist; including devices from this home.`);
homeIDList.push(home_id);
this.log.info(`Found home_id=${home_id} in whitelist; including devices from this home.`);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've noticed this and I don't know why npm run lint not return warnings for me and github actions, but ./node_modules/.bin/eslint src/**/**.ts --max-warnings=0 works. Do you know why?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my case, using eslint directly also works:

❯ ./node_modules/.bin/eslint src/**/**.ts --max-warnings=0
❯ echo $?
0

Do you have some additional global config specified? Or some prettier rules if you are using VSCode?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldnt it be

eslint src/**/*.ts --max-warnings=0

? with one asterisk before .ts

Besides this, no clue why it wouldnt return errors in actions.

src/accessory/AccessoryFactory.ts Show resolved Hide resolved
@@ -107,7 +110,11 @@ export default class TuyaDeviceManager extends EventEmitter {
}
let property: TuyaDeviceSchemaProperty;
try {
property = JSON.parse(values);
if (type === TuyaDeviceSchemaType.String) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

STRING value is a string, but String value is a json object string like {\"maxlen\":255} defines the max length.

@0x5e
Copy link
Owner

0x5e commented Nov 23, 2022

Sorry I forget to submit the review, It was left as pending state and you can't see. Now it is visible.

@0x5e
Copy link
Owner

0x5e commented Nov 23, 2022

Here's some informations:

IR additional API, if IoT Core not satisfied your requirements:
https://developer.tuya.com/en/docs/cloud/ir-control-hub-open-service?id=Kb3oe2mk8ya72

A Tuya plugin focused on IR devices:
https://github.com/prasad-edlabadka/homebridge-tuya-ir

Thanks again, I was intend to do this after December, but I'm a little bit busy and don't have enough time to develop and test recently.

@bimusiek
Copy link
Author

Hey @0x5e please re-check 👍

@0x5e 0x5e merged commit 49420f7 into 0x5e:develop Nov 24, 2022
@0x5e
Copy link
Owner

0x5e commented Nov 24, 2022

Thanks again! @bimusiek

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants