I’m currently using a HTD (Home Theater Direct) GW-SL1 to connect to my HTD MC-66 6 zone controller. Anyone successfully connected this to Home Assistant? I’ve searched a ton, but unable to find a good how-to guide for this. I’ve tried the RUSSOUND_RNET integration, but it’s just different enough to not work unfortunately. Thanks in advance!
Hi Mark,
You had any luck? In the same boat.
Nope, sadly still in the same spot with it - just waiting for a smarter party than I to come along (or for HTD to welcome themselves to the 21st century and figure something out already…)
Will certainly post back here if I hear anything!
Sure Mark,
Yep it’s only taken what 2 years+ to get an app finally working reliably!
Been a few people asking the same question. I’ve reached out to HTD and asked the question about API integration. Collectively if we get the APIs I’m sure we can build the intergration.
Rob.
Wow! Super quick to respond…they’ve progressed somewhat.
https://www.htd.com/home-automation
Let me read over the next couple of days…maybe we could roundup some other HTD ownersvand create a component for HA??
I’ve been monitoring that page for the better part of two years, and honestly, I have seen ZERO movement. I’ve spoken to a couple different guys over at HTD (and actually picked up both of my systems directly from them [they’re only about 10 miles from my office here outside of Dallas]). Anyhow, they’re all super nice and try to be helpful - but they’ve literally, at least from my viewpoint, gotten no where - slowly.
They keep claiming that SmartThings, Google, etc. have no open APIs to use to leverage - and I’m not interested in adding yet another hub (HomeSeer, Control4, etc.) to my network/setup to try to integrate.
I’m also guessing the HomeAssistant demand to write some kind of python script simply isn’t robust enough to warrant them writing - and i’m neither knowledgeable enough / don’t have the time to fiddle with creating it myself.
They did send a bunch of docs with info on how it might be / could be / should be able to be done:
I have seen a couple of project on GitHub and around, but a lot of these focus on using a USB->Serial cable to push the commands. My setup (having two of these), needs to involve using the web connection / IP address vs. Pi -> USB-Serial Cable -> MC66.
I also ‘tried’ the baked-in Russound / HA integration (believe the control units are about the same) - and while it recognized them (somewhat), I wasn’t able fully to get it to work. Maybe the above docs coupled w/ the already supposedly working Russound integration would be a solid starting place?
With all that said - unsure anyone smarter / more willing / less time-contrained than I can take it on - and if so - I’d be honestly happy to buy a case of beer or bottle of bourbon of whatever for the efforts!
Running python3 /config/htdquery.py querypwr 1 0 and getting this error:
Traceback (most recent call last):
File "/config/htdquery.py", line 15, in <module>
detail = htd.queryZone_returndetail(int(argv[2]))
File "/config/mca66.py", line 199, in queryZone_returndetail
self.send_command_returndetail(cmd, zone)
File "/config/mca66.py", line 237, in send_command_returndetail
self.parse_reply_returndetail(data, zone)
File "/config/mca66.py", line 113, in parse_reply_returndetail
self.zonelist[zone]['power'] = "on" if (i[4] & 1<<7)>>7 else "off"
KeyError: 0
Tracking down the error I’m receiving into the parse_reply_returndetail function.
It’s failing on the ‘power’ line:
for i in Zone_List:
zone = i[2]
self.zonelist[zone]['power'] = "on" if (i[4] & 1<<7)>>7 else "off"
self.zonelist[zone]['input'] = i[8]+1
self.zonelist[zone]['input_name'] = self.input_names[i[8]]
self.zonelist[zone]['vol'] = i[9]-196 if i[9] else 0
self.zonelist[zone]['mute'] = "on" if (i[4] & 1<<6)>>6 else "off"
I’m by far a python expert here… The ‘message being passed’ is:
b'\x01\xd8\x00\x00\x00\xe6\x02\x00\x00\x06\x00??\x00\x00\x00\x00\x00\x00\x86\x02\x00\x01\x05\x00\x00\x00\x00\x01\xe3\x00\x04\x00\xf0\x02\x00\x02\x05\x00\x00\x00\x00\x01\xec\x00\x00\x00\xf6\x02\x00\x03\x05\x00\x00\x00\x00\x01\xec\x00\x00\x00\xf7\x02\x00\x04\x05\x00\x00\x00\x00\x01\xe0\x00\x00\x00\xec\x02\x00'
Unsure what i in Zone_List or i[2] are trying to do… Let me know if there’s anything more specific I can provide. Thank you!
@Markus99 Were you ever able to get this going? I am close but still getting an “Index out of range” error running htdquery.py. It’s giving me the status but dumping a lot of errors in the logs.
$ python3 /config/htdquery.py querypwr 2 0
Zone: 2
Power: off
Input: 1
Input Name: Stereo
Volume: 46
Mute: off
Traceback (most recent call last):
File "/config/htdquery.py", line 8, in <module>
detail = htd.queryZone_returndetail(int(argv[2]))
File "/config/mca66.py", line 198, in queryZone_returndetail
self.send_command_returndetail(cmd, zone)
File "/config/mca66.py", line 236, in send_command_returndetail
self.parse_reply_returndetail(data, zone)
File "/config/mca66.py", line 112, in parse_reply_returndetail
zone = i[2]
IndexError: index out of range
I honestly haven’t played with it any further. Seems like, last I did mess with it, I could pass commands but didn’t have the ability to succesfully query the zones.
My next thought’s just to leverage this to create buttons / scripts to turn on the zones and set the sources and volume at MCA startup and then just use their app to control it once it’s playing.
Also still holding out slim hope that someone smarter than I can come along and actually get this whole working.
@Markus99 I’ve made significant progress on getting this to work correctly. I have the ability to send power and volume to the htd and have the status report back to HA correctly. It is also reporting back to HA when changes are made in the app. I’ll hopefully have the mute toggle and input select going by tomorrow. I’ve also consolidate it down to 3 files without the need for any txt files to read from. Once I have it finished up I’ll post a link to the files.
Brilliant, sounds awesome @jagee23!
I wish I had the time (and python knowledge) to be of help. Excited to see some progress - I’ve been almost yelling at the HTD guys for YEARS to have SOME sort of integration (SmartThings, Google Home, HA, etc.) beyond just their app. They make pretty good hardware, but the software side is a little meh. Possibly until now!
Thrilled you’re making headway and pls do keep me updated!
@Markus99, I’ve update the code and added it to my github. https://github.com/jagee23/mca66
Take a look and see if it works for you.
The only outstanding issue I have is reporting mute state back to HA. If you toggle the mute status in the HTD app it is not reporting back to HA. However, if the change is made in HA it works correctly.
Also, there are some errors reporting in the log at times when some of the scripts run. I suspect there are multiple entities hitting the HTD gateway at the same time and it is not handling it well. I’ll continue to work on this but I dont think it is causing any issues that I can tell. I’ve actually excluded those from the logs but it would be nice if they didnt happen at all.
Wow, nice work @jagee23! I’ll download and take a look, so nice with spring / summer around the corner to be able to trigger / control these via HA! Will let you know if I see anything else / have any tidbits I can contribute. Might be a bit, as still underwater w/ family / work - but GREATLY appreciate all of your hard work / efforts!
Got a quick minute to get this setup, but haven’t started setting it up yet. Any chance you’re able to share any of the YAML you’re using on the front-end to leverage all of this great work? Thx in advance!
Right now I am just using a simple entity card and only have the zone power and volume for now. My next goal is to get everything added and have it look really nice. I am not exactly sure how I want to go with it just yet.
entities:
- entity: switch.htd_pwr_zone1
- entity: input_number.htd_vol_zone1
- entity: switch.htd_pwr_zone2
- entity: input_number.htd_vol_zone2
- entity: switch.htd_pwr_zone3
- entity: input_number.htd_vol_zone3
- entity: switch.htd_pwr_zone4
- entity: input_number.htd_vol_zone4
- entity: switch.htd_pwr_zone5
- entity: input_number.htd_vol_zone5
type: entities
Makes sense. I’ll see if I can find some time to mess w/ it and ‘pretty it up’ - will post back if / when - work’s killing me lately!
EDIT: OK, spent 3 minutes, will try to spare more later…
- type: vertical-stack
cards:
- type: entities
entities:
- entity: switch.htd_pwr_zone1
state_color: true
- entity: input_select.htd_source_zone1
- entity: input_number.htd_vol_zone1
- type: entities
entities:
- entity: switch.htd_pwr_zone2
state_color: true
- entity: input_select.htd_source_zone2
- entity: input_number.htd_vol_zone2
- type: entities
entities:
- entity: switch.htd_pwr_zone3
state_color: true
- entity: input_select.htd_source_zone3
- entity: input_number.htd_vol_zone3
- type: entities
entities:
- entity: switch.htd_pwr_zone4
state_color: true
- entity: input_select.htd_source_zone4
- entity: input_number.htd_vol_zone4
- type: entities
entities:
- entity: switch.htd_pwr_zone5
state_color: true
- entity: input_select.htd_source_zone5
- entity: input_number.htd_vol_zone5
- type: entities
entities:
- entity: switch.htd_pwr_zone6
state_color: true
- entity: input_select.htd_source_zone6
- entity: input_number.htd_vol_zone6
Found a little more time to spend, this uses a couple of custom-cards
## START HTD DOWNSTAIRS STACK ##
- type: vertical-stack
cards:
- type: custom:vertical-stack-in-card
cards:
- type: conditional
conditions:
- entity: switch.speakers_downstairs
state: "off"
card:
type: entities
entities:
- entity: switch.speakers_downstairs
state_color: true
icon: mdi:speaker
- type: conditional
conditions:
- entity: switch.speakers_downstairs
state: "on"
card:
type: glance
title: Downstairs Speakers
columns: 6
show_name: false
show_state: false
entities:
- entity: switch.htd_pwr_zone1
icon: mdi:sofa
tap_action:
action: toggle
- entity: switch.htd_pwr_zone2
icon: mdi:fire
tap_action:
action: toggle
- entity: switch.htd_pwr_zone3
icon: mdi:waves
tap_action:
action: toggle
- entity: switch.htd_pwr_zone4
icon: mdi:fridge-outline
tap_action:
action: toggle
- entity: switch.htd_pwr_zone5
icon: mdi:table-chair
tap_action:
action: toggle
- entity: switch.htd_pwr_zone6
icon: mdi:bed-empty
tap_action:
action: toggle
- type: custom:vertical-stack-in-card
cards:
- type: conditional
conditions:
- entity: switch.htd_pwr_zone1
state: "on"
card:
type: entities
entities:
- entity: input_select.htd_source_zone1
icon: mdi:sofa
- type: conditional
conditions:
- entity: switch.htd_pwr_zone1
state: "on"
card:
type: custom:slider-entity-row
entity: input_number.htd_vol_zone1
full_row: true
- type: custom:vertical-stack-in-card
cards:
- type: conditional
conditions:
- entity: switch.htd_pwr_zone2
state: "on"
card:
type: entities
entities:
- entity: input_select.htd_source_zone2
icon: mdi:sofa
- type: conditional
conditions:
- entity: switch.htd_pwr_zone2
state: "on"
card:
type: custom:slider-entity-row
entity: input_number.htd_vol_zone2
full_row: true
- type: custom:vertical-stack-in-card
cards:
- type: conditional
conditions:
- entity: switch.htd_pwr_zone3
state: "on"
card:
type: entities
entities:
- entity: input_select.htd_source_zone3
icon: mdi:sofa
- type: conditional
conditions:
- entity: switch.htd_pwr_zone3
state: "on"
card:
type: custom:slider-entity-row
entity: input_number.htd_vol_zone3
full_row: true
- type: custom:vertical-stack-in-card
cards:
- type: conditional
conditions:
- entity: switch.htd_pwr_zone4
state: "on"
card:
type: entities
entities:
- entity: input_select.htd_source_zone4
icon: mdi:sofa
- type: conditional
conditions:
- entity: switch.htd_pwr_zone4
state: "on"
card:
type: custom:slider-entity-row
entity: input_number.htd_vol_zone4
full_row: true
- type: custom:vertical-stack-in-card
cards:
- type: conditional
conditions:
- entity: switch.htd_pwr_zone5
state: "on"
card:
type: entities
entities:
- entity: input_select.htd_source_zone5
icon: mdi:sofa
- type: conditional
conditions:
- entity: switch.htd_pwr_zone5
state: "on"
card:
type: custom:slider-entity-row
entity: input_number.htd_vol_zone5
full_row: true
- type: custom:vertical-stack-in-card
cards:
- type: conditional
conditions:
- entity: switch.htd_pwr_zone6
state: "on"
card:
type: entities
entities:
- entity: input_select.htd_source_zone6
icon: mdi:sofa
- type: conditional
conditions:
- entity: switch.htd_pwr_zone6
state: "on"
card:
type: custom:slider-entity-row
entity: input_number.htd_vol_zone6
full_row: true
### END DOWNSTAIRS SPEAKERS VERTICAL STACK ##
Essentially it hides everything unless the AMP is on (I have my amp plugged into a smart plug (switch.speakers_downstairs).
Once that is on, it then unhides a glance card w/ all 6 zones.
Then, for each Zone that’s turned on, it unhides that zones input select and volume slider.
Personally, I leave the amp OFF unless I’m using it, so also trying to adjust the script to not check the switches/sensors unless that switch.speakers_downstairs is on. Haven’t checked to confirm all of the .py is working and such, but figured I’d post what I’d done to-date. Thinking about adding a row of buttons w/in each zones conditional card as ‘quick action / presets’ that trigger scripts to set that zone to a certain input and/or volume - or volume up 3 / down 3 buttons. Also might do a row at the top of quick presets - all outside on/off, all inside on/off, all to source X, etc…
I like it…nice job! Keep me updated as you make progress. I was also looking at the mini media player card - https://github.com/kalkih/mini-media-player and thinking about how I could potentially incorporate that. I primarily use the 1st source input so I think this could work.
Also, I’ve been thinking about the mute function issue. I’m thinking about just abandoning that all together. Wouldn’t turning the zone off and back on serve the same purpose as toggling the mute or can you think of a reason the toggle would be better?
Just getting back to this, again, and seeing that about 1/2 the time I run a command (this was run on the console via Docker), I’m seeing something like this:
bash-5.0# python3 /config/packages/mca66/htd.py pwr 1 1
ParseReply_MessagePassedIn: b'\x00\x00\x00\x01\xdf\x00\x00\x00\xec\x02\x00\x06\x05\x00\x00\x00\x00\x01\xe2\x00\x00\x00\xf0\x02\x00\x01\x05\x80\x07\xc2\x01\x01\xde\x00\x04\x005'
{
"error": 1
}
If I re-run the command, it’ll typically return the correct values.
bash-5.0# python3 /config/packages/mca66/htd.py pwr 1 1
ParseReply_MessagePassedIn: b'\x02\x00\x01\x05\x80\x07\xc2\x00\x01\xde\x00\x04\x004\x02\x00\x01\x05\x80\x07\xc2\x01\x01\xde\x00\x04\x005'
{
"Zone": 1,
"Power": "on",
"Input": 2,
"Volume": 26,
"Mute": "off"
}
Also, seeing this when trying to getzone
bash-5.0# python3 /config/packages/mca66/htd.py getzone 1
ParseReply_MessagePassedIn: b'\x00\xf0\x02\x00\x00\x06\x00??\x00\x00\x00\x00\x00\x00\x86\x02\x00\x01\x05\x80\x07\xc2\x00\x01\xde\x00\x04\x004\x02\x00\x02\x05\x00\x00\x00\x00\x01\xde\x00\x00\x00\xe8\x02\x00\x03\x05\x00\x00\x00\x00\x01\xe0\x00\x00\x00\xeb\x02\x00\x04\x05\x00\x00\x00\x00\x01\xda\x00\x00\x00\xe6\x02\x00\x05\x05\x00\x00\x00\x00\x01\xdf\x00\x00\x00\xec'
{
"error": 1
}
Unsure if it’s just my gateway that hates me (it’s an older one [had it about 5-6 years now]) or what…