[Release] Logitech Harmony Hub Driver v0.1.20230311

I'm having the same issue with all three of my hubs. It looks like it's not able to http post to the hubs.

groovyx.net.http.HttpResponseException: on line 214 (initialize)

As a quick test, I fired up Postman and tried the same call and I'm getting back a HTTP 417 code. All three respond to pings and I'm able to access them through the Harmony app. Plus, all three are setup with the XMPP "feature" setup. I can also access them through the Harmony API (using GitHub - maddox/harmony-api: ๐Ÿ—ผ A simple server allowing you to query/control multiple local Harmony Home Hubs over HTTP or MQTT).

All three of my hubs are on firmware: 4.15.250, app version 5.6, build 14 (if that helps).

Any suggestions?

1 Like

I wonder if Logitech is locking down their webSockets interface?

I'm on hub FW 4.15.250 as well and still running just fine.

1 Like

Was thinking the same thing. I really hope not. Its so easy to work with and works so well.

That's what I'm thinking. I'm currently doing a port of the ST KuKuHarmony project to read status (and enable individual device control) using the Harmony API project.

However, I LOVE your approach for activities as it doesn't require the nodejs app and all that. I'm thinking that your app code could be enhanced with the XMPP features. That would get around Logitech locking down the WS interface.

As long as the webSockets interface is not blocked by Logitech, you could simply extend the capabilities of my existing code to allow individual device control. The interface supports it. However, my focus was simply on Activities. Please feel free to enhance it with pull requests.

Ok. This looks like it's an issue in the 4.15.250 firmware that Logitech rolled out. I'm seeing grumblings from other platforms (Homebridge, HomeAssistant, OpenHAB, etc) regarding websockets being unavailable. I've been looking around the net trying to figure out exactly what Logitech changed and it looks like something in the headers, but I can't pinpoint what exactly.

So, if you haven't updated your firmware to 4.15.250, don't do it yet as it will kill your websockets interface.

3 Likes

Would this just affect new installs since @destructure00 does not have this problem on this firmware?

That's what I am thinking. What happens is that the code that fails is looking for the remote id in the initialize() function. initialize() is only called when the app is installed or updated. I'm pretty certain that if @destructure00 removes the app code and then recreates it (or just calls the initialize() function from the device page), it will fail the same way ours is due to whatever Logitech did in the latest update.

1 Like

I can confirm that my 2 Harmony Hubs, that updated to the latest firmware this week, are still running this driver OK. Looks like I don't want to go anywhere near the initialise button.

1 Like

I am on the latest FW and its working as of yesterday. Right now my hub died so I am waiting on support to get me up again so I can't check.

However, I have not enabled XMPP as I'm not sure if that will disable WS. I'll leave it as is.

What is also weird is my iOS app is reporting one of my hubs twice.

I have a feeling they are going to make this messy.

Initialize is called every time your hub restarts. Fortunately, the Initialize function does not attempt to rediscover the remoteId if it has already done so successfully. So, for existing users, you're safe as long as you don't remove the device. For new users, we'll need to figure out how to discover the remoteID.

    if (state.remoteId == null) {
        httpPost(uri: "http://${ip}:8088",
                 path: '/',
                 contentType: 'application/json',
                 requestContentType: 'application/json',
                 headers: ['Origin': 'http//:localhost.nebula.myharmony.com'],
                 body: '{"id": 124, "cmd": "connect.discoveryinfo?get", "params": {}}'
                ) { response ->
            log.debug "hub remote id: ${response.data.data.remoteId}"
            state.remoteId = response.data.data.remoteId
        }
    }
2 Likes

@ogiewon I might have a fix. Give me a sec to test it.

2 Likes

Got it! They changed remoteId to activeRemoteId, the Origin header and the command to get the remote id.

Here's the updated code:

if (state.remoteId == null) {
        httpPost(uri: "http://${ip}:8088",
                 path: '/',
                 contentType: 'application/json',
                 requestContentType: 'application/json',
                 //headers: ['Origin': 'http//:localhost.nebula.myharmony.com'],
                 //body: '{"id": 124, "cmd": "connect.discoveryinfo?get", "params": {}}'

                 //Logitech: You suck. :) Updated Origin and body cmd.
                 headers: ['Origin': 'http://sl.dhg.myharmony.com'],
	         body: '{"id": 1, "cmd": "setup.account?getProvisionInfo", "params": {}}'
                ) { response ->
			//activeRemoteId is the new property name instead of just remoteId.
		        //log.debug "hub remote id: ${response.data.data.remoteId}"
                       //state.remoteId = response.data.data.remoteId
			
			log.debug "hub remote id: ${response.data.data.activeRemoteId}"
                        state.remoteId = response.data.data.activeRemoteId
                  }
        }
4 Likes

Nice work! I will update the code in my GitHub repository with your change. Thank you!

4 Likes

Dear Logitech,

FU and your sneaky changing of command and property names. Love your products, but I hate your devs.

Signed,
Me.

1 Like

No problem! Glad I could help.

BTW: This is the project that I got the "fix" from. They seem to be REALLY fast at figuring out Logitech's changes: harmony-websocket/harmony-websocket.js at master ยท lopelex/harmony-websocket ยท GitHub

1 Like

My GitHub repo has been updated, but I cannot test currently. I would also like to make the code work for both versions of Harmony Hub firmware, but that will take a little more time to deal with the error handling. Maybe tonight or later this week.

2 Likes

I'd offer to test, but all three of mine are updated (ugh). However, I think a try/catch around the initialize() httpPost OR catching the response code into a variable should suffice. I was getting a response code of 417 before the fix, so maybe have 4 variables at the beginning of the function and toggle between them depending on the response code?

def pre250Origin = 'http//:localhost.nebula.myharmony.com'
def post250Origin = 'http://sl.dhg.myharmony.com'
def pre250Body = '{"id": 124, "cmd": "connect.discoveryinfo?get", "params": {}}'
def post250Body = '{"id": 1, "cmd": "setup.account?getProvisionInfo", "params": {}}'

Just a thought. I'm going to see about creating the child devices in a pull request and see how far I can get. :slight_smile:

Yes, this is what I was thinking as well. Just try/catch the new method, if is doesn't work, then try/catch the old method. If one of them works sucessfully, then move on without throwing any errors. If neither works, then log an error to the live logs to help troubleshoot in the future (when Logitech break things again.)

1 Like