Is this possible with Alexa + ChannelsDVR?

So here is my setup:

  1. IR Control with Alexa Device
  2. Zinwell ATSC 3.0 BOX because it has IR Controls.
  3. Uray HDMI Encoder to grab the video off of the Zinwell since thats the best method for bypassing HDCP in a way.

Is there anyway to make it so when you change the channel it can also change the channel of the Zinwell to match the exact channel. This could be extremely useful for those ATSC 3.0 DRM Stations worst case scenario? Ive heard of adbtuner as well maybe theres deeplinks in the app as well that could utilize this instead of this setup.

I'm very close to getting this working in some form just need a possible way to be able to run commands when I tune to a channel on channelsdvr.

Yes you can use the AH4C project which lets you run commands when the DVR wants to tune a channel.

Im currently in the process of trying that Im stuck at this part would like some advice:


Here are the bmitune.sh file I could manage to use it was copied off of another device but something is clearly wrong here with the format somewhere.


I copied the prebmitune.sh and stopbmitune.sh files from the Directv Ospery device. I'm not sure whats going on in general.

adbTarget is to control Android devices

you would need to implement your own method to invoke Alexa or the IR emitter there

Here are some relevant posts regarding using the Zinwell with an Encoder. The issues would be the same with ah4c and ADBTuner -- as far as controlling the Zinwell, and capturing HDR output with currently available encoders:

I somehow managed to pull it off. I got it working with just the android directv prebmitune.sh and the android directv bmitune.sh slightly modified. As far as I am aware prebmitune.sh is required for any setup but really wont matter in this case as the device is 24/7 and always on the app for livetv.

The bmitune.sh was the tricky part because at first I thought of adding if commands if it matched a certain channel but it kept giving me errors for unknown command and syntax errors. But I found out adb shell input text 2.1 for channel 2 will always go to the nextgentv version. So from there I added a sleep 1 and then another adb command to send a dpad center press since its required.

This is the code here that should be added under $adbtarget adb shell input text $1

Sleep 1

$adbtarget adb shell input keyevent 23

It was that easy all along I will upload the scripts later when I get the chance I currently am working at my job until later today.

Also the stopbmitune.sh will not be required in this case as like I said earlier its always on the correct app so turning off the zinwell doesnt make sense.

1 Like

Here are the files via Google Drive:

Zinwell Bmitune Scripts

1 Like

@Timbo303

I believe you'll find you've scooped up a few things in your scripts that don't apply to your ah4c project. So, I thought I'd see if I can clean things up, and then perhaps merge this thread in with the ah4c thread where it likely belongs.

Based on what you've posted through screenshots and on your Google Drive, I'd suggest these simplified scripts to control your Zinwell NextGenTV STB using ah4c. If you could test these, I'll add them to the next build of ah4c under scripts/zinwell/livetv:

prebmitune.sh:

#!/bin/bash
#prebmitune.sh for zinwell/livetv
#2025.01.26
echo "Script not required"

bmitune.sh:

#!/bin/bash
#bmitune.sh for zinwell/livetv
#2025.01.28

#Debug on if uncommented
set -x

#Global
channelID=\""$1\""
streamerIP="$2"
adbTarget="adb -s $streamerIP"

#Trap end of script run
finish() {
  echo "bmitune.sh is exiting for $streamerIP with exit code $?"
}

trap finish EXIT

#Tuning is based on channel number values from zinwell.m3u
tuneChannel() {
  $adbTarget shell input text $channelID
  sleep 1
  $adbTarget shell input keyevent KEYCODE_DPAD_CENTER
}

main() {
  tuneChannel
}

main

stopbmitune.sh:

#!/bin/bash
#stopbmitune.sh for zinwell/livetv
#2025.01.26
echo "Script not required"

zinwell.m3u:

#EXTM3U

#EXTINF:-1 channel-id="102.1" tvc-guide-stationid="",CBS 2 NEXTGENTV
http://{{ .IPADDRESS }}/play/tuner/102.1

#EXTINF:-1 channel-id="105.1" tvc-guide-stationid="",NBC 5 NEXTGENTV
http://{{ .IPADDRESS }}/play/tuner/105.1

#EXTINF:-1 channel-id="132.1" tvc-guide-stationid="",FOX 32 NEXTGENTV
http://{{ .IPADDRESS }}/play/tuner/132.1

Just the prebmitune.sh and the stopbmitune.sh work on your list. Bmitune.sh doesnt work at all when it comes to changing channels. I think specialID, Streameripnoport, and the M3uname lines along with matching the tuner ip with encoder ip was required for the channels to change. Thats why it worked in the first place for bmitune.sh as I tried yours.

Another thing the .Ipaddress doesnt work for me I had to input it manually in the m3u to fix that. I think it has something to do with portainer

Could you post the env vars you're using in your Portainer-Stack, along with the the date of the ah4c compose? I think something is not quite right with your values.

EDIT: Also, I modified the bmitune.sh script above very slightly, so give it a try as well.

Here is the Values:

CHANNELSIP 192.168.1.98:8089
CREATE_M3US True
ENCODER1_URL http://192.168.1.141/0.ts
ENCODER2_URL
ENCODER3_URL
ENCODER4_URL
IPADDRESS 192.168.1.136:7664
LIVETV_ATTEMPTS 1
NUMBER_TUNERS 1
PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
STREAMER_APP scripts/zinwell/livetv
TUNER1_IP 192.168.1.135:5555
TUNER2_IP
TUNER3_IP
TUNER4_IP
TZ US/Central

It was created 2025-01-24 21:39:04

But I should point out its network might be the issue as it defaulted to 172.18.0.2 and the gateway is 172.18.0.1 which is a bridge network. I tried to change it to my host network but it didn't let me with an error message. Not certain how to fix this.

The values look mostly OK however there are some important ones missing. This list looks like it's from Portainer-Containers, however I'm actually looking for the values you're using in Portainer-Stacks. Go into the Stacks Editor, look in the Environment variables in Advanced mode, and you can copy-and-paste the values here.

Based on what you posted above, here's roughly what I think you should show. This is a pared down list, that shows just those values that are required for your scenario:

TAG=latest
DOMAIN=localdomain
HOST_PORT=7664
WSCR_PORT=7665
IPADDRESS=192.168.1.136:7664
NUMBER_TUNERS=1
TUNER1_IP=192.168.1.135:5555
ENCODER1_URL=http://192.168.1.141/0.ts
STREAMER_APP=scripts/zinwell/livetv
CHANNELSIP=192.168.1.98
UPDATE_SCRIPTS=true
UPDATE_M3US=true
TZ=US/Central
HOST_DIR=/data

Note that CHANNELSIP should only in include the IP and not the port. Your LAN's actual domain name may be something other than localdomain. CREATE_M3US and LIVETV_ATTEMPTS should not be set in your project -- those are used for a different purpose (as described in the Docker Compose comments).

@Timbo303 I'm guessing you missed this, as I believe the modification I made to the bmitune.sh above will likely work for you. Please give it another try.

I should point out another issue I must of had missed. It turns out channel 32 will only type the 3 when you use that command. It doesnt seem to type the 2. That is a problem in my scenario as there is a 30.1 channel in chicago. So I was spending all night trying to figure out the best way to make different commands for each channel ID. This is what I came up with as I cant figure out the exact syntax for putting bc (the basic calculator command that makes decimals possible) as bash only supports float point integers. I did try to make the number a string but then $channelID has to be a string too for that to work as bash is limited.

bmitune.sh

#!/bin/bash
#bmitune.sh for zinwell/livetv
#2025.01.26

#Debug on if uncommented
set -x

#Global
channelID="$1"
streamerIP="$2"
adbTarget="adb -s $streamerIP"

#Trap end of script run
finish() {
echo "bmitune.sh is exiting for $streamerIP with exit code $?"
}

#Tuning is based on channel number values from zinwell.m3u
tuneChannel() {
if [[ $channelID == 32 ]]; then
$adbTarget shell input keyevent KEYCODE_3
sleep 1
$adbTarget shell input keyevent KEYCODE_2
sleep 1
$adbTarget shell input keyevent KEYCODE_DPAD_CENTER
fi
if [[ $channelID == 2 ]]; then
$adbTarget shell input text $channelID
sleep 1
$adbTarget shell input keyevent KEYCODE_DPAD_CENTER
fi
if [[ $channelID == 5 ]]; then
$adbTarget shell input text $channelID
sleep 1
$adbTarget shell input keyevent KEYCODE_DPAD_CENTER
fi
}
main() {
tuneChannel
}
main

zinwell.m3u

#EXTM3U

#EXTINF:-1 channel-id="2" channel-number="102.1" tvc-guide-stationid="",
http://{{ .IPADDRESS }}/play/tuner/2

#EXTINF:-1 channel-id="5" channel-number="105.1" tvc-guide-stationid="",
http://{{ .IPADDRESS }}/play/tuner/5

#EXTINF:-1 channel-id="32" channel-number="132.1" tvc-guide-stationid="",
http://{{ .IPADDRESS }}/play/tuner/32

OK, so you're saying your original bmitune.sh (the script I was trying to clean-up to add to the next build of ah4c) doesn't actually work? And of course, if that's true, my cleaned-up version won't work either.

Does the script you posted most recently work correctly? If so, I have another tuneChannel function we can use that will duplicate that -- but do it in a fashion where additional channels can be added to the M3U without needing to modify the bmitune.sh script.

I fixed the {{.IPADDRESS}} in the m3u thanks to your help however the port was wrong it should be 7654 not 7664 for the m3u. I would like to see how we could simplify the tunechannel() stuff since like I said you need to input the keycodes manually for 2 digits or more (you can also do this for 1 digit channels).

{{ .IPADDRESS }} needs to have a space as shown between each inside curly brace. Your version above doesn't have that.

Here's an example of a tuneChannel() function, that takes channel numbers with multiple digits, and sends each digit as an individual keyevent:

 tuneChannel() {
  for (( digit=0; digit<${#channelID}; digit++ )); do
    keypress=${channelID:$digit:1}
    $adbTarget shell input keyevent KEYCODE_$keypress
  done
}

The port number can be whatever you want it to be. It's 7654 INSIDE the container, but that can be 7664 or whatever on your host computer. The port you want to use OUTSIDE the container is defined by HOST_PORT in your Portainer-Stack variables. The value you use there should be reflected in your IPADDRESS value which contains both the hostname (or IP address), and the port you chose to use.

I have 3 ah4c containers running on ports 7654, 7664 and 7674.