MrAsterisco / homebridge-hisense-tv

A Homebridge plugin to control RemoteNow-compatible HiSense TVs.
MIT License
18 stars 8 forks source link

Cannot connect to more than 1 Hisense TVs #51

Open Shaun-R opened 6 months ago

Shaun-R commented 6 months ago

Describe Your Problem

G'day and happy new year! Thank you so much for making this plugin available.

I own three Hisense TVs:

I'm based in Australia, so these are Australian model numbers. However I understand that Hisense use VIDAA OS in the UK and other EU markets in addition to Australia, and having browsed other Issues raised here it is pretty clear that at least some of us are also Aussies, so I am pretty confident in this working for all three TVs.

All three TVs are connected to WiFi and work correctly with the RemoteNOW app on my iPhone 14 Pro.

I'm running Homebridge in Docker on a Synology NAS. My Homebridge Docker image has Python 3.10 installed, so I have modified my commands from "python3.8" to just "python3" accordingly.

I have

  1. Installed homebridge-hisense-tv-remotenow in Homebridge
  2. From the Terminal window in the Homebridge Web UI, I ran the commands
    pip3 install netifaces
    pip3 install paho-mqtt

    Both of these installed correctly. If I re-run the commands, I get

    Requirement already satisfied: netifaces in /usr/local/lib/python3.10/dist-packages (0.11.0)
    WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv

    and

    Requirement already satisfied: paho-mqtt in /usr/local/lib/python3.10/dist-packages (1.6.1)
    WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
  3. I then ran the commands
    cd /var/lib/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin
    python3 hisensetv.py 192.168.1.45 --authorize --ifname bond0
  4. Entered the 4-digit code displayed on my 50S8 TV, into the Terminal prompt
  5. Restarted Homebridge
  6. Homebridge then showed this in its logs (Setup Code redacted):
    [1/2/2024, 1:24:42 PM] [HiSenseTV] Adding new accessory: Hisense 50S8
    [1/2/2024, 1:24:43 PM] Hisense 50S8 2251 is running on port 42907.
    [1/2/2024, 1:24:43 PM] Please add [Hisense 50S8 2251] manually in Home app. Setup Code: xxx-xx-xxx
  7. I then added the following to my config.json (MAC address redacted), and restarted Homebridge:
    {
    "ifname": "bond0",
    "devices": [
        {
            "id": "Hisense 50S8",
            "name": "Bed 3 Hisense TV",
            "ipaddress": "192.168.1.45",
            "macaddress": "xx:xx:xx:xx:xx:xx",
            "sslmode": "default"
        }
    ],
    "platform": "HiSenseTV"
    }
  8. From my iPhone, I successfully added the TV as a new Accessory to the Home app. I was prompted to name the Inputs. One of them shows up as "Unknown" but all the show up as-expected.
  9. I am able to successfully control the 50S8 TV without issue. Great! Now let's add the other two TVs. I started with the older 55PX running VIDAA 2.5
  10. Still from the Terminal window in the Homebridge Web UI, I tried running the following:
    python3 hisensetv.py 192.168.1.46 --authorize --ifname bond0

    Sadly, I get an error message (full details in the Logs section)

    ConnectionResetError: [Errno 104] Connection reset by peer

    So, I tried running the same command but with the --no-ssl switch, but get a timeout error instead:

    hisensetv.HisenseTvTimeoutError: failed to recieve a response in 10.000s

I have tried adding the newer 55Q8 (VIDAA U 4) TV, both

python3 hisensetv.py 192.168.1.47 --authorize --ifname bond0

and with the --no-ssl switch:

python3 hisensetv.py 192.168.1.47 --authorize --no-ssl --ifname bond0

But again I get the same errors.

  1. I tried going ahead and adding the TVs to my config.json anyway, then restarting Homebridge
  2. The logs show as if things are going well...
    [1/2/2024, 2:16:31 PM] Bed 3 Hisense TV A917 is running on port 35197.
    [1/2/2024, 2:16:31 PM] Please add [Bed 3 Hisense TV A917] manually in Home app. Setup Code: xxx-xx-xxx
    [1/2/2024, 2:16:31 PM] Bed 1 Hisense TV 2132 is running on port 40621.
    [1/2/2024, 2:16:31 PM] Please add [Bed 1 Hisense TV 2132] manually in Home app. Setup Code: xxx-xx-xxx
    [1/2/2024, 2:16:31 PM] Living Room Hisense TV 3236 is running on port 43178.
    [1/2/2024, 2:16:31 PM] Please add [Living Room Hisense TV 3236] manually in Home app. Setup Code: xxx-xx-xxx

    But moments later, the logs were overrun with dozens of identical entries every few seconds:

    [1/2/2024, 2:16:41 PM] [HiSenseTV] An error occurred while fetching inputs: TypeError: Cannot read properties of null (reading 'join')
    [1/2/2024, 2:16:41 PM] [HiSenseTV] An error occurred while fetching inputs: TypeError: Cannot read properties of null (reading 'join')
    [1/2/2024, 2:16:51 PM] [HiSenseTV] An error occurred while fetching inputs: TypeError: Cannot read properties of null (reading 'join')
    [1/2/2024, 2:16:51 PM] [HiSenseTV] An error occurred while fetching inputs: TypeError: Cannot read properties of null (reading 'join')
    [1/2/2024, 2:17:01 PM] [HiSenseTV] An error occurred while fetching inputs: TypeError: Cannot read properties of null (reading 'join')
  3. I added the TVs to the Home app on my iPhone, but they just show a single input of "Unknown" and don't respond to Power or any other button press.
  4. I tried uninstalling homebridge-hisense-tv-remotenow and removing the entry from config.json along with it, then reinstalling and re-doing setup (starting with the 50S8), but the same issue persists.

At this point, I'm at a loss.

I would be most grateful for any advice or insight you may be able to offer!

Logs

root@homebridge:/var/lib/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin $ python3 hisensetv.py 192.168.1.46 --authorize --ifname bond0
[2024-01-02 17:56:59,643] [INFO    ] Unverified SSL context created.
[2024-01-02 17:56:59,645] [INFO    ] Network interface MAC Address: xx:xx:xx:xx:xx:xx
Traceback (most recent call last):
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv.py", line 6, in <module>
    __main__.main()
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv/__main__.py", line 128, in main
    with tv:
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv/__init__.py", line 136, in __enter__
    self._mqtt_client.connect(self.hostname, self.port)
  File "/usr/local/lib/python3.10/dist-packages/paho/mqtt/client.py", line 914, in connect
    return self.reconnect()
  File "/usr/local/lib/python3.10/dist-packages/paho/mqtt/client.py", line 1073, in reconnect
    sock.do_handshake()
  File "/usr/lib/python3.10/ssl.py", line 1371, in do_handshake
    self._sslobj.do_handshake()
ConnectionResetError: [Errno 104] Connection reset by peer 
root@homebridge:/var/lib/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin $ python3 hisensetv.py 192.168.1.46 --authorize --no-ssl --ifname bond0
[2024-01-02 17:56:00,183] [INFO    ] No SSL context specified.
[2024-01-02 17:56:00,184] [INFO    ] Network interface MAC Address: xx:xx:xx:xx:xx:xx
Traceback (most recent call last):
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv/__init__.py", line 207, in _wait_for_response
    return self._queue[topic].get(block=True, timeout=self.timeout)
  File "/usr/lib/python3.10/queue.py", line 179, in get
    raise Empty
_queue.Empty

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv.py", line 6, in <module>
    __main__.main()
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv/__main__.py", line 130, in main
    tv.start_authorization()
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv/__init__.py", line 54, in wrapper
    return func(self, *args, **kwargs)
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv/__init__.py", line 632, in start_authorization
    self._wait_for_response(topic=self._our_topic)
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv/__init__.py", line 209, in _wait_for_response
    raise HisenseTvTimeoutError(
hisensetv.HisenseTvTimeoutError: failed to recieve a response in 10.000s
root@homebridge:/var/lib/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin $ 

Config

{
    "ifname": "bond0",
    "devices": [
        {
            "id": "Hisense 50S8",
            "name": "Bed 3 Hisense TV",
            "ipaddress": "192.168.1.45",
            "macaddress": "xx:xx:xx:xx:xx:xx",
            "sslmode": "default"
        },
        {
            "id": "Hisense 55Q8",
            "name": "Bed 1 Hisense TV",
            "ipaddress": "192.168.1.47",
            "macaddress": "xx:xx:xx:xx:xx:xx",
            "sslmode": "default"
        },
        {
            "id": "Hisense 55PX",
            "name": "Living Room Hisense TV",
            "ipaddress": "192.168.1.46",
            "macaddress": "xx:xx:xx:xx:xx:xx",
            "sslmode": "default"
        }
    ],
    "platform": "HiSenseTV"
}

Screenshots

If you need any screenshots, please let me know - I'm not sure there are any relevant screenshots I can provide here though!

Environment

Shaun-R commented 6 months ago

I was looking over #30 and tried following the steps in comment-1015280575, and this led me down a new rabbit hole...

Interestingly, if I run --get state --no-ssl against the 55PX (VIDAA 2.5), it responds as if it is paired!

root@homebridge:/var/lib/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin $ python3 hisensetv.py 192.168.1.46 --get state --no-ssl --ifname bond0
[2024-01-02 18:32:25,543] [INFO    ] No SSL context specified.
[2024-01-02 18:32:25,545] [INFO    ] Network interface MAC Address: xx:xx:xx:xx:xx:xx
{
    "statetype": "sourceswitch",
    "sourceid": "4",
    "sourcename": "HDMI 2",
    "is_signal": 1,
    "is_lock": 0,
    "hotel_mode": 0,
    "displayname": "Apple TV"
}
root@homebridge:/var/lib/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin $ 

So I went ahead and added it to config.json with the SSL Mode set to Disabled:

{
                    "id": "Hisense 55PX",
                    "name": "Living Room Hisense TV",
                    "ipaddress": "192.168.1.46",
                    "macaddress": "xx:xx:xx:xx:xx:xx",
                    "sslmode": "disabled"
                }

Restarted Homebridge, added the accessory, and bam! It's working!! Hooray!

So now I have 2 out of 3 TVs successfully added (50S8 and 55PX)

Sadly, --get state doesn't seem to work for the 50Q8 (VIDAA U4), no matter whether I provide SSL Certificates, use the --no-ssl switch, or just a regular command:

root@homebridge:/var/lib/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin $ python3 hisensetv.py 192.168.1.47 --get state --certfile /var/lib/homebridge/node_modules/homebridge-hisense-tv-remotenow/rcm_certchain_pem.cer --keyfile /var/lib/homebridge/node_modules/homebridge-hisense-tv-remotenow/rcm_pem_privkey.pkcs8  --ifname bond0
Traceback (most recent call last):
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv.py", line 6, in <module>
    __main__.main()
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv/__main__.py", line 119, in main
    ssl_context.load_cert_chain(certfile=args.certfile, keyfile=args.keyfile)
ssl.SSLError: [SSL] PEM lib (_ssl.c:3900)

root@homebridge:/var/lib/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin $ python3 hisensetv.py 192.168.1.47 --get state  --ifname bond0
[2024-01-02 18:54:41,083] [INFO    ] Unverified SSL context created.
[2024-01-02 18:54:41,085] [INFO    ] Network interface MAC Address: 00:11:32:7e:33:ad
Traceback (most recent call last):
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv.py", line 6, in <module>
    __main__.main()
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv/__main__.py", line 128, in main
    with tv:
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv/__init__.py", line 136, in __enter__
    self._mqtt_client.connect(self.hostname, self.port)
  File "/usr/local/lib/python3.10/dist-packages/paho/mqtt/client.py", line 914, in connect
    return self.reconnect()
  File "/usr/local/lib/python3.10/dist-packages/paho/mqtt/client.py", line 1073, in reconnect
    sock.do_handshake()
  File "/usr/lib/python3.10/ssl.py", line 1371, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:1007)

root@homebridge:/var/lib/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin $ python3 hisensetv.py 192.168.1.47 --get state --no-ssl --ifname bond0
[2024-01-02 18:54:52,078] [INFO    ] No SSL context specified.
[2024-01-02 18:54:52,079] [INFO    ] Network interface MAC Address: 00:11:32:7e:33:ad
Traceback (most recent call last):
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv.py", line 6, in <module>
    __main__.main()
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv/__main__.py", line 128, in main
    with tv:
  File "/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin/hisensetv/__init__.py", line 144, in __enter__
    raise HisenseTvTimeoutError(f"failed to connect in {self.timeout:.3f}s")
hisensetv.HisenseTvTimeoutError: failed to connect in 10.000s
root@homebridge:/var/lib/homebridge/node_modules/homebridge-hisense-tv-remotenow/bin $ 

Given this, I am feeling like maybe VIDAA U4 isn't compatible with this plugin? Perhaps the MQTT commands are different? I'm not sure. I'd be keen to do whatever I can to help out in troubleshooting if you like!

Happily, starting with VIDAA U6 (2022) and continuing in VIDAA U7 (2023), native AirPlay and HomeKit support is baked into VIDAA OS. Sadly, VIDAA U4 (2020) and U5 (2021) are stuck in a weird limbo state where they have the Apple TV+ app but no native AirPlay or HomeKit capability - so it would be awesome to get this plugin going here.

MrAsterisco commented 6 months ago

Hey @Shaun-R !

Happy New Year to you too! Thanks for posting such a detailed issue: it's been a bit of a roller-coaster to read 😃

My gut feeling after spending quite a lot of time trying to troubleshoot HiSense TVs is that they tend to change things for each software version (in some cases, even models with the same major version runs differently). This, among other reasons, is why I sadly decided to move away from HiSense for good.

Regarding the first issue, although it has already been resolved:

Interestingly, if I run --get state --no-ssl against the 55PX (VIDAA 2.5), it responds as if it is paired!

Very interesting! Does this mean you can connect to the TV without pairing (aka. inserting the code) on the RemoteNOW app? Does it connect immediately? If that's the case, we might have to add it to the README, as it's the first model that doesn't seem to require pairing.


Regarding the second problem:

sslv3 alert handshake failure (_ssl.c:1007)

This line means that the certificates being used are wrong. Trying without certificates and getting a timeout means the TV isn't responding without a valid certificate, which is a common security measure: all seems to point to yet another SSL certificate that is baked into that model. This is not the first time we see HiSense just changing SSL certificates for the sake of it.

You can approach this two ways:

  1. If you have an Android device and are familiar with exploring APKs, you could try to decompile the RemoteNOW app and see if you can identify the SSL certificate that it's using. I'm aware there are other ways to sniff the SSL certificates, but I'm not super familiar with them: perhaps there's a way to explore the TV internal storage somehow?
  2. You could try to use MQTT Explorer to see if, instead, SSL has nothing to do with the issue and it's just a different command.

Either way, I'm happy to support you as much as I can on this quest, but I'm afraid you'll have to get your hands dirty.

Happily, starting with VIDAA U6 (2022) and continuing in VIDAA U7 (2023), native AirPlay and HomeKit support is baked into VIDAA OS.

I'm so happy to hear that! I'll add it to the README file.

Shaun-R commented 6 months ago

Thanks for your quick reply!

So I downloaded MQTT and these keyfiles, and have done some digging.

As per @gjlamb,

As mentioned above, I'm able to connect to the TV using MQTT explorer with key_files certs from https://github.com/d3nd3/Hisense-mqtt-keyfiles. Not sure if looking at that repo would give insight on getting it working? I am now in the exact same spot: I can successfully connect when I provide my own certificate and turn off "validate certificate"

Screenshot 2024-01-02 at 9 06 42 pm Screenshot 2024-01-02 at 9 06 50 pm Screenshot 2024-01-02 at 9 08 49 pm

We can see here that MQTT is providing the TV's current state:

{ 
"statetype":"sourceswitch",
"sourceid":"HDMI2",
"sourcename":"HDMI2",
"is_signal":1,
"is_lock":0,
"hotel_mode":0,
"displayname":"Apple TV" 
}

And in the Publish section, it prompts me to publish the URL /remoteapp/tv/ui_service/xx:xx:xx:xx:xx:xx$normal/actions/gettvstate

As soon as I click the Publish button, the TV pops up with a 4-digit pairing code. I'm not quite sure how to actually insert this into the data I'm sending it in order to actually do anything with it, though.

Also, #26 is basically the same issue but with a U9G, which runs VIDAA U5 and has the same SSL handshake issue that I'm having on the Q8 running VIDAA U4. I suspect the SSL certificates are probably the same between U4 and U5.

I understand homebridge-hisense-tv supports SSL options:

If that were possible, I suspect this issue would be solved.

MrAsterisco commented 6 months ago

Mmm, you might be on to something, but #26 also had other issues, as it seems the TV responds in a different format. I also gotta admit that I lost track of that issue and I see now that I did not reply 😞

So, trying out what you're suggesting shouldn't be too hard, but we need to figure out how to convince Python we don't want to "validate the certificates". I was under the impression that that was achieved by using ssl._create_unverified_context() (as shown here), but I see in the code that we're only using that when no certificate and key files are provided.

So, we should start by modifying the plugin: how familiar are you with Python? Would you be able to test the change?

Here's what you'd have to do:

  1. Clone the plugin repo on your computer (no need to use the machine that runs Homebridge, you can use your own computer, as long as it has Python and the other dependencies installed),
  2. Open hisensetv/__main__.py (I recommend using PyCharm or Visual Studio Code with a Python plugin installed) and go to line 96 to add a new argument:
parser.addArgument(
    "--unverified-ssl", 
    action="store_true",
    help="Create an unverified SSL context. If a certificate and a key are provided via --keyfile and --certfile, they will be used"
)
  1. Move to line 117 and change the existing code by removing the both the elif and the else condition to replace them with:
else:
    if args.unverified_ssl:
        ssl_context = ssl._create_unverified_context()
        logger.info("Unverified SSL context created.")
    else:
        ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
        logger.info("Verified SSL context created.")

    if args.certfile is not None and args.keyfile is not None:
        ssl_context.load_cert_chain(certfile=args.certfile, keyfile=args.keyfile)
        logger.info("SSL context created with cert file (" + args.certfile + ") and private key (" + args.keyfile + ")")
  1. Run the Python script directly by running:
# Your Python executable might be called differently depending on your OS.
# The `hisensetv.py` file is in the root of the repository.
python3 hisensetv.py --authorize --ifname IFNAME --unverified-ssl --certfile CERTFILE --keyfile KEYFILE -v HOSTNAME

Unless I'm missing something, this change should support all the cases we've seen so far:

If this works, I'm happy to give you access to open a PR on the other repo (which is already a fork, so no need to fork it again).

After that, we can update the plugin configuration to support the new --unverified-ssl parameter.

LeLunZ commented 1 month ago

@Shaun-R ssl verification was disabled in the latest version of the python plugin. (I think) https://github.com/MrAsterisco/hisensetv/pull/3/files

        ssl_context.check_hostname = False
        ssl_context.verify_mode = ssl.CERT_NONE

Could you test the newest version 2.0.1 if you still have the TV?