staromeste / homebridge-http-advanced-accessory

Supports all devices on HomeBridge Platform / Bridges devices to http
Apache License 2.0
65 stars 22 forks source link

TypeError: actionDescription.mappers.forEach is not a function #14

Open markob100 opened 5 years ago

markob100 commented 5 years ago

I am getting the following error. I am trying to use HttpAdvancedAccessory with SomaCtrl (i) to get various WindowCovering Characteristics (CurrentPosition and PositionState in one accessory, and BatteryLevel in another accessory) and (ii) to set TargetPosition.

TypeError: actionDescription.mappers.forEach is not a function
    at createAction (/usr/local/lib/node_modules/homebridge-http-advanced-accessory/index.js:57:30)
    at new HttpAdvancedAccessory (/usr/local/lib/node_modules/homebridge-http-advanced-accessory/index.js:89:4)
    at Server._loadAccessories (/usr/local/lib/node_modules/homebridge/lib/server.js:308:29)
    at Server.run (/usr/local/lib/node_modules/homebridge/lib/server.js:91:38)
    at module.exports (/usr/local/lib/node_modules/homebridge/lib/cli.js:59:10)
    at Object.<anonymous> (/usr/local/lib/node_modules/homebridge/bin/homebridge:17:22)
    at Module._compile (module.js:635:30)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)
    at tryModuleLoad (module.js:497:12)

It looks like I’m making a mistake with the mappers. Runs fine when I remove the ‘getters’ from the config, just leaving the ‘setter’ which doesn’t require any mapping beyond specifying the http endpoint.

Below is the data returned from the url http://192.168.194.2:3000/d12b7e625b6e which I’m trying to map from.

{
"id":"d12b7e625b6e",
"battery":99,
"batteryLevelLastChanged":"2019-08-20T21:40:04.209Z",
"position":19,
"positionLastChanged":"2019-08-20T21:40:04.046Z",
"connectionState":"connected",
"state":"open",
"group":"Kitchen",
"name":"Kitchen2"
}

And here is my config.json in full.

{
   "bridge": {
       "name": "HomebridgeDev2",
       "username": "C1:38:5A:AC:39:32",
       "port": 51828,
       "pin": "123-45-680"
   },
   "accessories": [
       {
           "accessory": "HttpAdvancedAccessory",
           "service": "WindowCovering",
           "name": "Kitchen Blind 2s",
           "forceRefreshDelay": 300,
           "debug" : true,
           "optionCharacteristic" :["CurrentPosition","TargetPosition","PositionState"],
           "urls":{
              "getCurrentPosition": {
                 "url" : "http://192.168.194.2:3000/d12b7e625b6e",
                 "mappers" :{
                         "type": "jpath",
                         "parameters": {
                             "jpath": "$.position"
                         }
                     }
              },
"setTargetPosition":{
"url":"http://192.168.194.2:3000/d12b7e625b6e/move?position=${value}",
"httpMethod":"POST"
},
"getPositionState":{
"url" : "http://192.168.194.2:3000/d12b7e625b6e",
                 "mappers" :{
                         "type": "jpath",
                         "parameters": {
                         "jpath": "$.state"
                         }
                     }
}
           }
        },
        {
        "accessory": "HttpAdvancedAccessory",
        "service": "Battery",
        "name": "Kitchen Blind 2 Battery",
        "forceRefreshDelay": 300,
        "debug" : true,
"optionCharacteristic": "BatteryLevel",
        "urls":{
           "getBatteryLevel": {
              "url" : "http://192.168.194.2:3000/d12b7e625b6e",
              "mappers" :{
"type": "jpath",
                         "parameters": {
                             "jpath": "$.battery"
}
           }
}
}
}
]
}

Any ideas?! I am probably doing something simple and stupid with the jpath syntax. Any thoughts/advice/mockery gratefully received.

staromeste commented 5 years ago

I think the problem here is that mappers should be an array [] even if it has only one element. So maybe "mappers" :[{ "type": "jpath", "parameters": { "jpath": "$.state" } }] should work.

markob100 commented 5 years ago

Thank you so much - that has solved the mappers problem! (Though I haven’t tested in Home yet, just checked that HomeBridge has successfully loaded.)

The first accessory (the WindowCovering service) seems to load fine; the second (the Battery service) does not and shows the following error (terminating HomeBridge): TypeError: Cannot read property 'characteristics' of null

I don’t know if this is a config problem or it just happens that the http endpoint isn’t returning data. Do you have any thoughts? If the latter I will try and figure out a way to use ‘inconclusive’ so that if it gets a null return it fails gracefully (showing 0 or something) rather than crashing out.

Thanks Mark

Sent from my iPad

On 21 Aug 2019, at 10:59, Guido Moscarella notifications@github.com wrote:

I think the problem here is that mappers should be an array [] even if it has only one element. So maybe "mappers" :[{ "type": "jpath", "parameters": { "jpath": "$.state" } }] should work.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

markob100 commented 5 years ago

Update - I think I’ve resolved the Battery service problem.

Looking at the supported services list, I see that the Battery service is called BatteryService rather than Battery.

This seems to be an anomaly in comparison with the naming convention for the other services, but replacing “Service”:”Battery” with “Service”:”BatteryService” seems to have resolved the error.

I will test this evening with the Home app and update with the results.

Thanks again Mark

Sent from my iPad

On 21 Aug 2019, at 11:56, Mark O'Brien mark.e.obrien@gmail.com wrote:

Thank you so much - that has solved the mappers problem! (Though I haven’t tested in Home yet, just checked that HomeBridge has successfully loaded.)

The first accessory (the WindowCovering service) seems to load fine; the second (the Battery service) does not and shows the following error (terminating HomeBridge): TypeError: Cannot read property 'characteristics' of null

I don’t know if this is a config problem or it just happens that the http endpoint isn’t returning data. Do you have any thoughts? If the latter I will try and figure out a way to use ‘inconclusive’ so that if it gets a null return it fails gracefully (showing 0 or something) rather than crashing out.

Thanks Mark

Sent from my iPad

On 21 Aug 2019, at 10:59, Guido Moscarella notifications@github.com wrote:

I think the problem here is that mappers should be an array [] even if it has only one element. So maybe "mappers" :[{ "type": "jpath", "parameters": { "jpath": "$.state" } }] should work.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

markob100 commented 5 years ago

Thanks for your help with this.

The results of testing with the Home app shows the following error. It looks like the plugin expects a ‘getter’ for TargetPosition. Since there isn’t anything in the config.json (as you can see above) for this, it crashes.

I’m a bit stuck, because I don’t know why it expects getTargetPosition, or where that data should come from. Conceptually - the plugin gets Current Position from the accessory (along with Current State) and passes it to HK and sets Target Position based on data from HK which it then passes to the accessory. Why is it expecting to get Target Position from the accessory? The accessory is getting told where to move by HK, not telling HK where it has been told to move by [something else]. Am I thinking about this in the wrong way?

[2019-8-21 21:56:38] [Kitchen Blind 2s] creating new emitter for getTargetPosition
[2019-8-21 21:56:38] [Kitchen Blind 2s] creating new emitter for getCurrentPosition
[2019-8-21 21:56:38] [Kitchen Blind 2s] requested update for action getTargetPosition
[2019-8-21 21:56:38] [Kitchen Blind 2s] getTargetPosition emitter returned data: undefined
[2019-8-21 21:56:38] [Kitchen Blind 2s] updating TargetPosition with value 0
[2019-8-21 21:56:38] [Kitchen Blind 2s] calling callback for action getTargetPosition
[2019-8-21 21:56:38] TypeError: Cannot read property 'url' of undefined
    at HttpAdvancedAccessory.<anonymous> (/usr/local/lib/node_modules/homebridge-http-advanced-accessory/index.js:208:68)
    at HttpAdvancedAccessory.<anonymous> (/usr/local/lib/node_modules/homebridge-http-advanced-accessory/index.js:391:8)
    at Timeout._onTimeout (/usr/local/lib/node_modules/homebridge-http-advanced-accessory/node_modules/polling-to-event/index.js:77:5)
    at ontimeout (timers.js:475:11)
    at tryOnTimeout (timers.js:310:5)
    at Timer.listOnTimeout (timers.js:270:5)
[2019-8-21 21:56:38] Got SIGTERM, shutting down Homebridge...
[2019-8-21 21:56:38] [Kitchen Blind 2s] requested update for action getCurrentPosition
[2019-8-21 21:56:38] [Kitchen Blind 2s] getDispatch function called for url: http://192.168.194.2:3000/d12b7e625b6e
[2019-8-21 21:56:38] [Kitchen Blind 2s] received response from action: http://192.168.194.2:3000/d12b7e625b6e
[2019-8-21 21:56:38] [Kitchen Blind 2s] Applying mappers on {"id":"d12b7e625b6e","battery":96,"batteryLevelLastChanged":"2019-08-21T20:56:26.734Z","position":94,"positionLastChanged":"2019-08-21T20:56:26.449Z","connectionState":"connected","state":"open","group":"Kitchen","name":"Kitchen2"}
[2019-8-21 21:56:38] [Kitchen Blind 2s] Mapper 0 mapped {"id":"d12b7e625b6e","battery":96,"batteryLevelLastChanged":"2019-08-21T20:56:26.734Z","position":94,"positionLastChanged":"2019-08-21T20:56:26.449Z","connectionState":"connected","state":"open","group":"Kitchen","name":"Kitchen2"} to 94
[2019-8-21 21:56:38] [Kitchen Blind 2s] Mapping result is 94
[2019-8-21 21:56:38] [Kitchen Blind 2s] We have a value: 94, int: 94
[2019-8-21 21:56:38] [Kitchen Blind 2s] getCurrentPosition emitter returned data: 94
[2019-8-21 21:56:38] [Kitchen Blind 2s] updating CurrentPosition with value 94
[2019-8-21 21:56:38] [Kitchen Blind 2s] calling callback for action getCurrentPosition
staromeste commented 5 years ago

HK can ask the Blind what is its target position. If there there is no way for you to know that, maybe you can try and set the same as the CurrentPosition. Let me know if it doesn't work, we may have to change the code.

On Thu, 22 Aug 2019 at 16:23, markob100 notifications@github.com wrote:

Thanks for your help with this.

The results of testing with the Home app shows the following error. It looks like the plugin expects a ‘getter’ for TargetPosition. Since there isn’t anything in the config.json (as you can see above) for this, it crashes.

I’m a bit stuck, because I don’t know why it expects getTargetPosition, or where that data should come from. Conceptually - the plugin gets Current Position from the accessory (along with Current State) and passes it to HK and sets Target Position based on data from HK which it then passes to the accessory. Why is it expecting to get Target Position from the accessory? The accessory is getting told where to move by HK, not telling HK where it has been told to move by [something else]. Am I thinking about this in the wrong way?

[2019-8-21 21:56:38] [Kitchen Blind 2s] creating new emitter for getTargetPosition

[2019-8-21 21:56:38] [Kitchen Blind 2s] creating new emitter for getCurrentPosition

[2019-8-21 21:56:38] [Kitchen Blind 2s] requested update for action getTargetPosition

[2019-8-21 21:56:38] [Kitchen Blind 2s] getTargetPosition emitter returned data: undefined

[2019-8-21 21:56:38] [Kitchen Blind 2s] updating TargetPosition with value 0

[2019-8-21 21:56:38] [Kitchen Blind 2s] calling callback for action getTargetPosition

[2019-8-21 21:56:38] TypeError: Cannot read property 'url' of undefined

at HttpAdvancedAccessory.<anonymous> (/usr/local/lib/node_modules/homebridge-http-advanced-accessory/index.js:208:68)

at HttpAdvancedAccessory.<anonymous> (/usr/local/lib/node_modules/homebridge-http-advanced-accessory/index.js:391:8)

at Timeout._onTimeout (/usr/local/lib/node_modules/homebridge-http-advanced-accessory/node_modules/polling-to-event/index.js:77:5)

at ontimeout (timers.js:475:11)

at tryOnTimeout (timers.js:310:5)

at Timer.listOnTimeout (timers.js:270:5)

[2019-8-21 21:56:38] Got SIGTERM, shutting down Homebridge...

[2019-8-21 21:56:38] [Kitchen Blind 2s] requested update for action getCurrentPosition

[2019-8-21 21:56:38] [Kitchen Blind 2s] getDispatch function called for url: http://192.168.194.2:3000/d12b7e625b6e

[2019-8-21 21:56:38] [Kitchen Blind 2s] received response from action: http://192.168.194.2:3000/d12b7e625b6e

[2019-8-21 21:56:38] [Kitchen Blind 2s] Applying mappers on {"id":"d12b7e625b6e","battery":96,"batteryLevelLastChanged":"2019-08-21T20:56:26.734Z","position":94,"positionLastChanged":"2019-08-21T20:56:26.449Z","connectionState":"connected","state":"open","group":"Kitchen","name":"Kitchen2"}

[2019-8-21 21:56:38] [Kitchen Blind 2s] Mapper 0 mapped {"id":"d12b7e625b6e","battery":96,"batteryLevelLastChanged":"2019-08-21T20:56:26.734Z","position":94,"positionLastChanged":"2019-08-21T20:56:26.449Z","connectionState":"connected","state":"open","group":"Kitchen","name":"Kitchen2"} to 94

[2019-8-21 21:56:38] [Kitchen Blind 2s] Mapping result is 94

[2019-8-21 21:56:38] [Kitchen Blind 2s] We have a value: 94, int: 94

[2019-8-21 21:56:38] [Kitchen Blind 2s] getCurrentPosition emitter returned data: 94

[2019-8-21 21:56:38] [Kitchen Blind 2s] updating CurrentPosition with value 94

[2019-8-21 21:56:38] [Kitchen Blind 2s] calling callback for action getCurrentPosition

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/staromeste/homebridge-http-advanced-accessory/issues/14?email_source=notifications&email_token=ABBP2MPK6LVJ2Q5ELPMSSH3QF2OPHA5CNFSM4IOEIW32YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD45IIRY#issuecomment-523928647, or mute the thread https://github.com/notifications/unsubscribe-auth/ABBP2MIY6RYZ5GUC5KAHQE3QF2OPHANCNFSM4IOEIW3Q .

markob100 commented 5 years ago

Thanks for engaging with this.

Mapping getTargetPosition to CurrentPosition does basically work, but with some misleading behaviour in the Home app whilst the blind is moving. What happens is:

I suppose an elegant solution would be to be able to map the last known output of setTargetPosition to getTargetPosition (perhaps starting with CurrentPosition on launch i.e. before there is a ‘last’ setTargetPosition), since I can’t expose the ‘setted’ TargetPosition from the device http endpoint, but I recognise this might be an edge case and not worth the coding effort.

One other thought is that PositionState doesn’t seem to be updating properly - I think this is a problem with the http endpoint rather than your plugin code. So I am speculating that HK is ‘filling in the gaps’ based on (what it believes to be) its knowledge of CurrentPosition and TargetPosition. I wonder if fixing PositionState will override that and fix the display issue described above (i.e. HK will ignore TargetPosition and CurrentPosition in reporting whether the blind is opening/closing/stopped). I will experiment and let you know.