dkerr64 / homebridge-yolink

Apache License 2.0
12 stars 2 forks source link

Add Support for IR Blaster #83

Closed bhamid79 closed 9 months ago

bhamid79 commented 10 months ago

Thank you for this amazingly stable plugin. So I got the IR Blaster and was excited to give it a try with some solar dumb lights in the yard. Worked great BUT plugin has no support for the IR remote. Totally understand how trying to read the custom remotes in the Yolink app might be annoying hassle to program.

So my workaround was to get the Flexfob and use that as in between. Unfortunately the Flexfob integration works opposite of what I hoped. The fob shows up as a programable remote to create automations in homekit - which makes total sense. But I was actually ho Thank you for this amazingly stable plugin. So I got the IR Blaster and was excited to give it a try with some solar dumb lights in the yard. Worked great BUT plugin has no support for the IR remote. Totally understand how trying to read the custom remotes in the Yolink app might be annoying hassle to program.

So my workaround was to get the Flexfob and use that as in between. Unfortunately the Flexfob integration works opposite of what I hoped. The fob shows up as a programable remote to create automations in homekit - which makes total sense. But I was actually hoping to have the fob duplicated digitally in homekit, so have homekit buttons that simulate a fob button press.

Is there anyway to simulate fob button press? or a simpler approach, a button to activate/deactivate a Yolink scene thats been setup in the app?

dkerr64 commented 10 months ago

Can you look in the Homebridge log please and see what messages are printed out when you start the plugin with the IR blaster. I am hoping that some messages will show up that will identify the device and messages. In the meantime I will look at the documentation (here) and think about how best to support.

Homebridge/HomeKit does not have concept of a IR Blaster accessory type. But it does have Television so if the IR Blaster is being used to control a TV then we could set it up as this.

Alternatively just set up a series of buttons, like we do for the Flexfob.

I'm open to ideas on how this could be done. I would need to buy one too, in order to develop this.

bhamid79 commented 10 months ago

Log display (censored some of the token IDs not sure if that makes a difference):

[11/17/2023, 8:43:39 PM] [YoLink] Login to YoLink API with credentials from config [11/17/2023, 8:43:39 PM] Homebridge v1.7.0 (HAP v0.11.1) (YoLink) is running on port ******. [11/17/2023, 8:43:40 PM] [YoLink] Starting interval timer to refresh accessToken every 6480 seconds [11/17/2023, 8:43:40 PM] [YoLink] YoLink device type: 'InfraredRemoter' is not supported (Smart IR Remote (d88b4c010005eb92)) (initialize) Please report all bugs at https://github.com/dkerr64/homebridge-yolink/issues {"deviceId":"d8********b92","deviceUDID":"453***********************43ee41e5","name":"Smart IR Remote","token":"5E************************5FA076D","type":"InfraredRemoter","parentDeviceId":null,"modelName":"YS4803-UC","config":{"refreshAfter":14500,"enableExperimental":false,"temperature":false,"powerFailureSensorAs":"Outlet"},"data":{},"deviceMsgName":"Smart IR Remote (d8***********b92)","lastReportAtTime":0,"hasBattery":false,"updateTime":1700271820,"reportAtTime":"1970-01-01T00:00:00.000Z","semaphore":{"_nextSemaphoreId":0,"_maxSemaphores":1,"name":"anonymous 4","_loggedName":"“anonymous 4”","_currentSemaphores":{},"_waitingCallers":[]},"timeout":45,"targetState":""} [11/17/2023, 8:43:40 PM] [YoLink] Not registering device YoLink Hub () as config 'hide=true' [11/17/2023, 8:43:40 PM] [YoLink] Create MQTT client to connect to YoLink message service [11/17/2023, 8:43:40 PM] [YoLink] MQTT subscribed: yl-home/5546daf*********************8eb2/+/report

The way the app works is once the remote button is coded to the IR Remote, user is able to bind it to a graphic button. The button can then be added to a grid layout. Grid layout is stored under a custom device. In the end all the buttons are ON/OFF grouped under a custom grid layout. I am no programmer, I barely know some python to help with my day job. But what I would imagine is the plugin would read all the "devices" in the IR Remote, pulls in all the buttons as on/off switches into Homekit, then group all the switches under a group with the "device" name.

If you want to msg me I'm totally down to order an IR Blaster to your address. Small thank you for troubleshooting this. I think having access to an IR Remote in Yolink's LoRa ecosystem opens up a lot of potential.

dkerr64 commented 10 months ago

@bhamid79 can you please update the plugin to 1.3.6 that I just published. This adds a framework on which I can build to add support for IR Blaster. You will need to set...

"enableExperimental": true,

into the config file, you can do this in the plugin settings user interface, expand the "Optional global configuration" section and select the "Enable support for devices under development" option.

This creates a framework, but does not yet add any accessories to Homebridge. The purpose is to capture any messages from the IR blaster into log. Specifically, on initialization it should do a InfraredRemoter.getState from the device which should return a list of which "keys" on the blaster have been "learned"

bhamid79 commented 10 months ago

Updated. Here is the initial log:

[11/18/2023, 7:20:27 PM] [YoLink] Starting interval timer to refresh accessToken every 6480 seconds
[11/18/2023, 7:20:27 PM] [YoLink] YoLink device type: 'InfraredRemoter' is under development (Smart IR Remote (d88b4c010005eb92)) (initialize)
Please report all bugs at https://github.com/dkerr64/homebridge-yolink/issues
{
  "deviceId": "d88b4c010005eb92",
  "deviceUDID": "4537733419084cb79758c59143ee42e5",
  "name": "Smart IR Remote",
  "token": "5E76DE89BE363FC1C36BD62D55FA077D",
  "type": "InfraredRemoter",
  "parentDeviceId": null,
  "modelName": "YS4803-UC",
  "config": {
    "refreshAfter": 14500,
    "enableExperimental": true,
    "temperature": false,
    "powerFailureSensorAs": "Outlet"
  },
  "data": {},
  "deviceMsgName": "Smart IR Remote (d88b4c010005eb92)",
  "lastReportAtTime": 0,
  "hasBattery": true,
  "updateTime": 1700353227,
  "reportAtTime": "1970-01-01T00:00:00.000Z",
  "semaphore": {
    "_nextSemaphoreId": 0,
    "_maxSemaphores": 1,
    "name": "anonymous 4",
    "_loggedName": "“anonymous 4”",
    "_currentSemaphores": {},
    "_waitingCallers": []
  },
  "timeout": 45,
  "targetState": "",
  "batteryService": {
    "_events": {},
    "_eventsCount": 3,
    "iid": 9,
    "name": null,
    "characteristics": [
      {
        "_events": {},
        "_eventsCount": 2,
        "iid": 10,
        "value": "Smart IR Remote",
        "status": null,
        "statusCode": 0,
        "subscriptions": 0,
        "displayName": "Name",
        "UUID": "00000023-0000-1000-8000-0026BB765291",
        "props": {
          "format": "string",
          "perms": [
            "pr"
          ],
          "maxLen": 64
        }
      },
      {
        "_events": {},
        "_eventsCount": 2,
        "iid": 11,
        "value": 0,
        "status": null,
        "statusCode": 0,
        "subscriptions": 0,
        "displayName": "Status Low Battery",
        "UUID": "00000079-0000-1000-8000-0026BB765291",
        "props": {
          "format": "uint8",
          "perms": [
            "ev",
            "pr"
          ],
          "minValue": 0,
          "maxValue": 1,
          "minStep": 1,
          "validValues": [
            0,
            1
          ]
        }
      },
      {
        "_events": {},
        "_eventsCount": 2,
        "iid": 12,
        "value": 2,
        "status": null,
        "statusCode": 0,
        "subscriptions": 0,
        "displayName": "Charging State",
        "UUID": "0000008F-0000-1000-8000-0026BB765291",
        "props": {
          "format": "uint8",
          "perms": [
            "ev",
            "pr"
          ],
          "minValue": 0,
          "maxValue": 2,
          "minStep": 1,
          "validValues": [
            0,
            1,
            2
          ]
        }
      },
      {
        "_events": {},
        "_eventsCount": 2,
        "iid": 13,
        "value": 100,
        "status": null,
        "statusCode": 0,
        "subscriptions": 0,
        "displayName": "Battery Level",
        "UUID": "00000068-0000-1000-8000-0026BB765291",
        "props": {
          "format": "uint8",
          "perms": [
            "ev",
            "pr"
          ],
          "unit": "percentage",
          "minValue": 0,
          "maxValue": 100,
          "minStep": 1
        }
      }
    ],
    "optionalCharacteristics": [
      {
        "_events": {},
        "_eventsCount": 0,
        "iid": null,
        "value": 0,
        "status": null,
        "statusCode": 0,
        "subscriptions": 0,
        "displayName": "Battery Level",
        "UUID": "00000068-0000-1000-8000-0026BB765291",
        "props": {
          "format": "uint8",
          "perms": [
            "ev",
            "pr"
          ],
          "unit": "percentage",
          "minValue": 0,
          "maxValue": 100,
          "minStep": 1
        }
      },
      {
        "_events": {},
        "_eventsCount": 0,
        "iid": null,
        "value": 0,
        "status": null,
        "statusCode": 0,
        "subscriptions": 0,
        "displayName": "Charging State",
        "UUID": "0000008F-0000-1000-8000-0026BB765291",
        "props": {
          "format": "uint8",
          "perms": [
            "ev",
            "pr"
          ],
          "minValue": 0,
          "maxValue": 2,
          "minStep": 1,
          "validValues": [
            0,
            1,
            2
          ]
        }
      },
      {
        "_events": {},
        "_eventsCount": 0,
        "iid": null,
        "value": "",
        "status": null,
        "statusCode": 0,
        "subscriptions": 0,
        "displayName": "Name",
        "UUID": "00000023-0000-1000-8000-0026BB765291",
        "props": {
          "format": "string",
          "perms": [
            "pr"
          ],
          "maxLen": 64
        }
      }
    ],
    "isHiddenService": false,
    "isPrimaryService": false,
    "linkedServices": [],
    "displayName": "Battery",
    "UUID": "00000096-0000-1000-8000-0026BB765291",
    "subtype": "battery"
  }
}
[11/18/2023, 7:20:27 PM] [YoLink] Not registering device YoLink Hub (d88b4c160301ac39) as config 'hide=true'
[11/18/2023, 7:20:27 PM] [YoLink] Create MQTT client to connect to YoLink message service

Log shows RING Plugin starting up, then:

[YoLink] YoLink device type: 'InfraredRemoter' is under development (Smart IR Remote (d88b4c010005eb92)) (handleGet)
Please report all bugs at https://github.com/dkerr64/homebridge-yolink/issues
{
  "battery": 4,
  "keys": [
    true,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false,
    false
  ],
  "version": "030a",
  "time": "2023-10-18T16:20:54.000Z",
  "tz": 0,
  "loraInfo": {
    "netId": "010203",
    "signal": -23,
    "gatewayId": "d88b4c160301ac39",
    "gateways": 1
  }
}

Thats the last log from the Yolink Plugin. Currently I have only one DIY device named "Light" and it has one "Power On" button.

dkerr64 commented 10 months ago

Thank you, those are exactly the log details I need.

dkerr64 commented 10 months ago

@bhamid79 can you please try version 1.3.7 that I just published. Again I would like to capture the logs. I am developing this blind as I do not have a IR blaster to test with, but with this version I hope that it will...

Create an accessory with a battery service and switch service(s). In Homebridge these will appear as separate tiles in the accessory page. In Apple Home app I am hopping that they appear as a single accessory and when you open it you will see battery level and a "switch" for each IR blaster key. The switch should be named with a number (0..63) to indicate which IR blaster key it is.

In the "keys" array [0..63] of boolean values a "true" indicates that the button/key has been learned. I create a "switch" for each one that is true. I'd like you to test with just the one that you have now, and then program another key so that there is more than one.

If you turn on one of the switches in Homebridge or Apple Home then the IR blaster should send that signal. The switch should then immediately turn off again (as the IR blaster is stateless).

I have left some logging in the code as "warn" level, which means it will show in the log as yellow/amber in color -- to help draw eye to them.

Let me know how this works out.

Thanks

dkerr64 commented 10 months ago

Oh... and please try triggering the switches in Homebridge and/or Apple Home app, and capturing the logs when you do that.

Thanks

bhamid79 commented 10 months ago

Great thanks David. Here are the logs. Now I get this during initialization: [11/19/2023, 6:07:48 PM] [YoLink] Initialize infrared remoter, find number of learned buttons... followed by:

[11/19/2023, 6:07:50 PM] [YoLink] Initialize infrared remoter with 0 button
[11/19/2023, 6:07:50 PM] [YoLink] Add switch for learned button index: 0

Just as you explained, I now have a switch on Homekit with one ON/OFF and a battery level in the settings. I also have 2 devices in Homebridge Accessories, an IR remote with battery level and IR remote ON/OFF key 0.

When I click on the switch in Homekit (or in Homebridge) the IR Remote works! It sends the IR signal to the dummy floodlight and it turns on. However the switch in Homekit and Homebridge stays ON and I get this log error:

[11/19/2023, 6:09:11 PM] [YoLink] YoLinkAPI.setDeviceState for Smart IR Remote (d88b4c010005eb92): {"key":0}
[11/19/2023, 6:09:13 PM] [YoLink] Error in SwitchDevice handleGet
Please report all bugs at https://github.com/dkerr64/homebridge-yolink/issues
TypeError: Cannot read properties of undefined (reading 'warn')
    at YoLinkPlatformAccessory.handleSet (/homebridge/node_modules/homebridge-yolink/src/infraredRemoter.ts:123:16)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)

When I manually turn the switch OFF same error appears. Same error repeats when the plugin refreshes status, showing:

[11/19/2023, 6:09:13 PM] [YoLink] Error in SwitchDevice handleGet
Please report all bugs at https://github.com/dkerr64/homebridge-yolink/issues
TypeError: Cannot read properties of undefined (reading 'warn')
    at YoLinkPlatformAccessory.handleSet (/homebridge/node_modules/homebridge-yolink/src/infraredRemoter.ts:123:16)

I'll add another button and update here in a bit.

dkerr64 commented 10 months ago

ok, so that is a bug in my code. will fix now.

dkerr64 commented 10 months ago

Just pushed a fix to that coding error on my part. I'm encouraged by what you report, sounds like we're on the right track.

bhamid79 commented 9 months ago

Works great now.

[11/20/2023, 3:18:36 PM] [YoLink] YoLinkAPI.setDeviceState for Smart IR Remote (d88b4c010005eb92): {"key":0}
[11/20/2023, 3:18:38 PM] [YoLink] Send infrared key number 0 returned:
{
  "key": 0,
  "success": true
}

Switch resets to OFF state.

dkerr64 commented 9 months ago

Excellent. And it works with more than one key "learned" ? I will clean up the code tonight to remove the experimental and hide the unnecessary log messages.

bhamid79 commented 9 months ago

So added 2 more buttons to the first device and made a new device with 2 buttons. All the buttons show up in Homekit under the IR Remote device and all are named "IR Remote Device". All the buttons do what they were programmed to do in Yolink app.

[11/20/2023, 3:30:30 PM] [YoLink] Add switch for learned button index: 0
[11/20/2023, 3:30:30 PM] [YoLink] Add switch for learned button index: 1
[11/20/2023, 3:30:30 PM] [YoLink] Add switch for learned button index: 2
[11/20/2023, 3:30:30 PM] [YoLink] Add switch for learned button index: 3
[11/20/2023, 3:30:30 PM] [YoLink] Add switch for learned button index: 4

When I do press a lot of the buttons in a row, Homebridge does lag and I get this message: [11/20/2023, 3:31:50 PM] [homebridge-yolink] This plugin slows down Homebridge. The read handler for the characteristic 'On' didn't respond at all!. Please check that you properly call the callback! See https://homebridge.io/w/JtMGR for more info. Not sure if its helpful but maybe something that can be optimized? of maybe users shouldnt press a lot of the buttons together hahaha

So issue now is, plugin need to read the different "devices". Button index 0, 1, 2 are under the first device "Floodlight" and 3,4 are under "DIY" device. Those should be added to Homekit as their own Device instead of under IR Remote. Right? I send screenshots from the yolink app setup if that's helpful.

dkerr64 commented 9 months ago

I have published version 1.4.0 which should polish off the support. I'll comment on some of your observations separately...

dkerr64 commented 9 months ago

So added 2 more buttons to the first device and made a new device with 2 buttons. All the buttons show up in Homekit under the IR Remote device and all are named "IR Remote Device". All the buttons do what they were programmed to do in Yolink app.

There was a change to Apple Home app recently where they used the same "name" for all sub-switches. But I think there is a way to fix that by using a new "Characteristic". I have done that, but I don't know if it will work for you so let me know. Each should be named "IR Key X" where X is a number. You may have to delete the accessory from the Homebridge cache to see the name update, not sure.

dkerr64 commented 9 months ago

When I do press a lot of the buttons in a row, Homebridge does lag and I get this message: [11/20/2023, 3:31:50 PM] [homebridge-yolink] This plugin slows down Homebridge. The read handler for the characteristic 'On' didn't respond at all!. Please check that you properly call the callback! See https://homebridge.io/w/JtMGR for more info. Not sure if its helpful but maybe something that can be optimized? of maybe users shouldnt press a lot of the buttons together hahaha

Unfortunately we may have to live with this. The YoLink LoRa protocol is slow, possibly because Long Range is not high speed! This message is most common during plugin initialization especially if you have a lot of devices (I see it every time).

As for your specific case... activating multiple switches quickly, I'm not surprised. I semaphore the network access to YoLink devices, so sending the IR code function does not release the semaphore until YoLink hub responds that the code was sent... which blocks sending the next one until the prior one completed. So activating multiple switches here is serialized. I dare not risk removing the semaphore protection without one of these devices to test with. And I suspect it will break things anyway.

dkerr64 commented 9 months ago

So issue now is, plugin need to read the different "devices". Button index 0, 1, 2 are under the first device "Floodlight" and 3,4 are under "DIY" device. Those should be added to Homekit as their own Device instead of under IR Remote. Right? I send screenshots from the yolink app setup if that's helpful.

As implemented the entire IR remote blaster is represented as a single device/accessory in HomeBridge with multiple switches within... all done automatically with no user configuration necessary. What you are asking for is probably doable but would require quite a bit of coding and the user would have to manually configure which IR keys to associate with which "device". It would need to be manual as that information is not available through the API.

Similarly, the HomeKit API provides for a "Television" device which it would be quite appropriate to make available as a configuration option, again would have to be all manually configured by the user.

So, doable, but a quite a bit more work. I'll think through how it might be designed, but no promises for a quick solution.

Thanks.

bhamid79 commented 9 months ago

Thank so much David. I can work with what we have now and if you're able to get the rest... that would be amazing. Sucks that the "device" and associated buttons aren't available through the API. You would think they would be attached to the key somehow.

I'm not a programmer but I did figure out configuring HTTP Switch plugins to access IP camera APIs for custom stuff. If you can give me a breakdown of whats happening in the IR Remote code I can try to reverse engineer and maybe help out. Let me know. As of now I do get an error with the new version. The name with key # isn't coming through:

[11/22/2023, 12:44:02 AM] [homebridge-yolink] This plugin generated a warning from the characteristic 'Configured Name': Characteristic not in required or optional characteristic section for service Switch. Adding anyway.. See https://homebridge.io/w/JtMGR for more info.
[11/22/2023, 12:44:02 AM] [homebridge-yolink] This plugin generated a warning from the characteristic 'Configured Name': Characteristic not in required or optional characteristic section for service Switch. Adding anyway.. See https://homebridge.io/w/JtMGR for more info.
[11/22/2023, 12:44:02 AM] [homebridge-yolink] This plugin generated a warning from the characteristic 'Configured Name': Characteristic not in required or optional characteristic section for service Switch. Adding anyway.. See https://homebridge.io/w/JtMGR for more info.
[11/22/2023, 12:44:02 AM] [homebridge-yolink] This plugin generated a warning from the characteristic 'Configured Name': Characteristic not in required or optional characteristic section for service Switch. Adding anyway.. See https://homebridge.io/w/JtMGR for more info.
[11/22/2023, 12:44:02 AM] [homebridge-yolink] This plugin generated a warning from the characteristic 'Configured Name': Characteristic not in required or optional characteristic section for service Switch. Adding anyway.. See https://homebridge.io/w/JtMGR for more info.
dkerr64 commented 9 months ago

I understand why you are seeing the configured name characteristic warning. A "workaround" is to delete the cached accessory in homebridge. But that has nasty side effects (deletes on Apple Home and deletes any attached automations), so last resort. I am looking into how to get rid of that warning so suggest you do nothing for now.

I have figured out how to fix the "this plugin slows down Homebridge" message. But in process have turned up another problem... it appears that YoLink is rate limiting access to devices through their API. Specifically a maximum of 6 requests to a single device within space of 1 minute, and an overall maximum of 20 requests across all devices. I have been able to confirm this by simply turning on/off an outlet several times in a row. You have to wait 60 seconds for it to reset.

This is a huge problem, especially for an IR blaster. Imaging trying to mimic a TV remote and enter a channel number, or increase volume with a sequence of "button presses". You hit 6 requests very rapidly. I have reached out to YoLink developer support team as they do not impose these limits on their own iOS app. No response from them yet.

dkerr64 commented 9 months ago

Try v1.4.1 that I just published. Should be more tolerant of errors.

I would like you to try sending a number (over 6) of IR requests in less than a minute please and watch the logs. I think you will get an error after sending 6, I'd like you to confirm that. You then have to wait one minute for YoLink to accept more requests.

Thanks.

dkerr64 commented 9 months ago

Closing as completed.

bhamid79 commented 9 months ago

Thanks a lot David. I'm traveling at the moment but I'll try the multiple IR requests later next week when I get home. I'll update here with my findings. Cheers!