Harmony Hub Integration

That’s a pretty good idea. I modified the Hub driver to add switch capability and mapped the off() command to alloff(). This seems like a pretty safe change and should make it easier in RM to call off as a switch, since by default the Hub driver doesn’t have any compatible capabilities to have it show up in the custom commands selection. Just FYI on() command doesn’t take any action. The changes are up on Github.

1 Like

Thanks Matt! That will make it easier for sure.

Sorry to bother, not seeing the update in github, or at least it’s not showing a new commit?

Sorry I forgot to sync the repository. It should be up there now.

1 Like

Thanks

Works great @mattw.
@ogiewon, have you tried this Logitech Harmony Connect port? It works great and you don’t have to schedule a RPi reset every 3 days :wink:

2 Likes

Morning All. Going through more fun stuff to integrate and today I am onto Harmony!

I would like to use the momentary https switch. Doing so will require me to install the maddox harmony-api.

I am NOT suing RPI but rather synology docker which provides a GUI interface for the install.

Does anyone have experience with this.

In particular selecting the correct volume will enable the installation and loading of the api correctly.

PS - that is NOT the correct directory.

@mattw and @stephack

I just got around to trying Matt’s amazing port of the ST Logitech Harmony integration. This works very well.

So, it looks like we actually have quite a few options for Hubitat/Harmony Hub integration. Due to the instability of the ‘harmony-api’ (I have to reboot the PI/Linux host every few days or else it seems to lock up), I will be using @mattw’s solution for now. While it is not 100% local/LAN, it does remove a dependency to run another server in my house.

Thank you Matt!

Dan

2 Likes

Did you already figure this out? I noticed that in addition to each of my Activities showing up as a device, my Harmony Hub also shows up as a device. You can easily turn OFF the Harmony Hub Device, which will stop any activity that is running. I was able to turn it off via Alexa, so I would hope it would work in RM as well...

One issue with the UI. The page refreshes before I can select all activities. I found myself in a click-race with the refresh.

Yes, using the switch that was added allows me to shutoff all activities using a single switch per harmony hub.

Exactly what I was looking for.

1 Like

I also noticed that my nubs would slow down and require multiple remote button presses. Seems like the api puts too much stress on the devices. I even removed my sequencer app (which loved) because it wasn’t worth the cost to performance.

Same here. I suspected that the ‘harmony-api’ was polling too frequently and causing a load on the Harmony hub. My remote seemed unresponsive at times too.

1 Like

The problem with the ST port of the harmony connect app is that it suffers from the same flaw of the ST harmony app.

Some users report they cannot add additional hubs as the Harmony ST app will not find. I have this exact situation now with one of my hubs. The work around works just fine, but if you try to add another hub, hubitat will not find it.

I do have issues with the ST port that persist on hubitat and I was hoping the api solution would alleviate it.

I realistically just need to understand where the docker install would mount (ie. docker/jonmaxxon/harmony-api

When installing a docker by command line, docker automatically installs the files into the correct directory.

In synology, unfortunately, you have to tell docker where to put the files.

Can you tell me (on your RPI) the name of the directory containing the docker for the harmony-api?

I have never used docker. I installed harmony-api as a Linux service. First on a Raspberry Pi, and later on Ubuntu.

Are the hubs on the same account? The app is pulling a list of hubs from Harmony servers so it shouldn't be any local issue finding the hubs. If the hubs are on multiple accounts, you can try changing line 54 singleInstance to false and installing another instance of the app on a different account.

Yes, the hubs are on the same account. It may be a harmony issue as well and not ST, but the hubitat app will not find all my hubs.

Harmony however does.

@mattw , @ogiewon do either of you see status updates on your Harmony devices in Hubitat when you turn on/off via the remote control (or anything other than Hubitat)? If I turn off via Alexa (direct integration) or my remote, it does not automatically sync to my Hubitat devices. Not a big deal but I was just curious if you both were seeing this as well and also if you found a workaround. I was considering making a rule that refreshes the hub device every minute or so.

I see the exact same thing. However, if you wait long enough, it should synchronize. In fact, I see the exact same behavior within SmartThings.

The biggest downside I can see for this is that you cannot use the status of the Harmony Activity switch devices to trigger other actions within Hubitat as there is too much of a delay (up to 5 minutes).

Here is the section of code which appears to be called every 5 minutes (there is a runIn(5, ...) command in the second routine below. I guess you could just reduce this time to every 1 minute, but you will be hitting the Logitech server 5 times more frequently.

def poll() {
	// GET THE LIST OF ACTIVITIES
    if (state.HarmonyAccessToken) {
        def tokenParam = [auth: state.HarmonyAccessToken]
        def params = [
            uri: "https://home.myharmony.com/cloudapi/state?${toQueryString(tokenParam)}",
            headers: ["Accept": "application/json"],
            contentType: 'application/json'
        ]
        //asynchttp_v1.get('pollResponse', params)
        httpGet(params) { response -> pollResponse(response) }
        
      } else {
        log.warn "Harmony - Access token has expired"
      }
}

def pollResponse(response) {
	if (response.status != 200) {
	    log.error "Harmony - response has error: $response.errorMessage"
	    if (response.status == 401) { // token is expired
			state.remove("HarmonyAccessToken")
			log.warn "Harmony - Access token has expired"
	    }
	} else {
		def ResponseValues
		try {
			// json response already parsed into JSONElement object
			ResponseValues = response.data
		} catch (e) {
			log.error "Harmony - error parsing json from response: $e"
		}
		if (ResponseValues) {
	        def map = [:]
	        ResponseValues.hubs.each {
		        // Device-Watch relies on the Logitech Harmony Cloud to get the Device state.
		        def isAlive = it.value.status
		        def d = getChildDevice("harmony-${it.key}")
		        d?.sendEvent(name: "DeviceWatch-DeviceStatus", value: isAlive!=504? "online":"offline", displayed: false, isStateChange: true)
		        if (it.value.message == "OK") {
					map["${it.key}"] = "${it.value.response.data.currentAvActivity},${it.value.response.data.activityStatus}"
					def hub = getChildDevice("harmony-${it.key}")
					if (hub) {
						if (it.value.response.data.currentAvActivity == "-1") {
							hub.sendEvent(name: "currentActivity", value: "--", descriptionText: "There isn't any activity running", displayed: false)
						} else {
							def currentActivity
							def activityDTH = getChildDevice("harmony-${it.key}-${it.value.response.data.currentAvActivity}")
							if (activityDTH)
								currentActivity = activityDTH.device.displayName
							else
								currentActivity = getActivityName(it.value.response.data.currentAvActivity,it.key)
							hub.sendEvent(name: "currentActivity", value: currentActivity, descriptionText: "Current activity is ${currentActivity}", displayed: false)
						}
					}
	          	} else {
	            	log.trace "Harmony - error response: $it.value.message"
	          	}
        	}
	        def activities = getChildDevices()
	        def activitynotrunning = true
	        activities.each { activity ->
	            def act = activity.deviceNetworkId.split('-')
	            if (act.size() > 2) {
	                def aux = map.find { it.key == act[1] }
	                if (aux) {
	                    def aux2 = aux.value.split(',')
	                    def childDevice = getChildDevice(activity.deviceNetworkId)
	                    if ((act[2] == aux2[0]) && (aux2[1] == "1" || aux2[1] == "2")) {
                            if(childDevice?.currentSwitch != "on")
	                        	childDevice?.sendEvent(name: "switch", value: "on")
	                        if (aux2[1] == "1")
	                            runIn(5, "poll", [overwrite: true])
	                    } else {
                            if(childDevice?.currentSwitch != "off")
	                        	childDevice?.sendEvent(name: "switch", value: "off")
	                        if (aux2[1] == "3")
	                            runIn(5, "poll", [overwrite: true])
	                    }
	                }
	            }
	        }
		} else {
			log.debug "Harmony - did not get json results from response body: $response.data"
		}
	}
}
2 Likes