├── pyproject.toml ├── custom_components └── hisensetv │ ├── pyproject.toml │ ├── __init__.py │ ├── manifest.json │ └── switch.py ├── hacs.json ├── .travis.yml └── README.rst /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length=79 3 | -------------------------------------------------------------------------------- /custom_components/hisensetv/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length=79 3 | -------------------------------------------------------------------------------- /custom_components/hisensetv/__init__.py: -------------------------------------------------------------------------------- 1 | """ Hisense Television Integration. """ 2 | -------------------------------------------------------------------------------- /hacs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hisense Television", 3 | "domains": ["switch"] 4 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.7" 4 | - "3.8" 5 | install: 6 | - pip install flake8>=3.8.2 flake8-bugbear>=20.1.4 pep8-naming>=0.10.0 7 | - pip install black>=19.10b0 8 | script: 9 | - black --check . 10 | - flake8 11 | -------------------------------------------------------------------------------- /custom_components/hisensetv/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "domain": "hisensetv", 3 | "name": "Hisense Television", 4 | "documentation": "https://developers.home-assistant.io/docs/creating_integration_manifest/", 5 | "dependencies": [], 6 | "codeowners": ["@newAM"], 7 | "requirements": ["hisensetv==0.0.7", "wakeonlan==1.1.6"] 8 | } 9 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | README 2 | ###### 3 | 4 | |hacs_badge| |Build Status| 5 | 6 | **Update 2020-07-09** This repository is no longer maintained. I do not use this component anymore. I found that my TV would drop the Ethernet connection and require physically unplugging/replugging it to maintain connectivity. 7 | 8 | Installation 9 | ************ 10 | Place the ``custom_components`` folder into your configuration directory 11 | (or add its contents to an existing ``custom_components`` folder). 12 | 13 | Alternatively install with `HACS `_. 14 | 15 | Authentication 16 | ************** 17 | You will need to perform one-time authentication for the API to work. 18 | 19 | This authentication can be performed on your local computer, or on your 20 | home-assistant server. 21 | 22 | .. code:: bash 23 | 24 | pip install hisensetv 25 | hisensetv 10.0.0.28 --authorize 26 | 27 | See `newAM/hisensetv `_ for more details. 28 | 29 | Configuration 30 | ************* 31 | 32 | .. code:: yaml 33 | 34 | switch: 35 | - platform: hisensetv 36 | host: 10.0.0.28 37 | mac: ab:cd:ef:12:34:56 38 | name: tv 39 | 40 | * ``host`` is the (static) IP address of your TV. 41 | * ``mac`` if the TVs MAC address for Wake on LAN (WOL). 42 | 43 | Warning 44 | ******* 45 | This is provided **as-is**. 46 | This is my first time going this deep into homeassistant and I have no idea 47 | if I have horribly messed something up. 48 | 49 | .. |hacs_badge| image:: https://img.shields.io/badge/HACS-Custom-orange.svg 50 | :target: https://github.com/custom-components/hacs 51 | .. |Build Status| image:: https://api.travis-ci.com/newAM/hisensetv_hass.svg?branch=master 52 | :target: https://travis-ci.com/newAM/hisensetv_hass 53 | -------------------------------------------------------------------------------- /custom_components/hisensetv/switch.py: -------------------------------------------------------------------------------- 1 | """ Hisense Television Integration. """ 2 | from hisensetv import HisenseTv 3 | from homeassistant.components.switch import PLATFORM_SCHEMA 4 | from homeassistant.components.switch import SwitchDevice 5 | from homeassistant.const import CONF_BROADCAST_ADDRESS 6 | from homeassistant.const import CONF_HOST 7 | from homeassistant.const import CONF_MAC 8 | from homeassistant.const import CONF_NAME 9 | from homeassistant.helpers.typing import ConfigType 10 | from homeassistant.helpers.typing import HomeAssistantType 11 | from typing import Callable 12 | from typing import Optional 13 | import homeassistant.helpers.config_validation as cv 14 | import logging 15 | import platform 16 | import socket 17 | import subprocess as sp 18 | import voluptuous as vol 19 | import wakeonlan 20 | import time 21 | 22 | _LOGGER = logging.getLogger(__name__) 23 | 24 | DEFAULT_NAME = "tv" 25 | DEFAULT_PING_TIMEOUT = 1 26 | 27 | DOMAIN = "hisensetv" 28 | _LOGGER = logging.getLogger(__name__) 29 | 30 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( 31 | { 32 | vol.Required(CONF_HOST): cv.string, 33 | vol.Required(CONF_MAC): cv.string, 34 | vol.Optional(CONF_BROADCAST_ADDRESS): cv.string, 35 | vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, 36 | } 37 | ) 38 | 39 | 40 | def setup_platform( 41 | hass: HomeAssistantType, 42 | config: ConfigType, 43 | add_entities: Callable, 44 | discovery_info: Optional[dict] = None, 45 | ): 46 | """Set up a Hisense TV.""" 47 | broadcast_address = config.get(CONF_BROADCAST_ADDRESS) 48 | host = config[CONF_HOST] 49 | mac = config[CONF_MAC] 50 | name = config[CONF_NAME] 51 | 52 | add_entities( 53 | [ 54 | HisenseTvEntity( 55 | host=host, 56 | mac=mac, 57 | name=name, 58 | broadcast_address=broadcast_address, 59 | ) 60 | ], 61 | True, 62 | ) 63 | 64 | 65 | class HisenseTvEntity(SwitchDevice): 66 | def __init__(self, host: str, mac: str, name: str, broadcast_address: str): 67 | self._name = name 68 | self._host = host 69 | self._mac = mac 70 | self._broadcast_address = broadcast_address 71 | self._is_on = True 72 | self._state = False 73 | self._last_state_change = 0 74 | 75 | def turn_on(self, **kwargs): 76 | if self._broadcast_address: 77 | wakeonlan.send_magic_packet( 78 | self._mac, ip_address=self._broadcast_address 79 | ) 80 | else: 81 | wakeonlan.send_magic_packet(self._mac) 82 | 83 | self._state = True 84 | self._last_state_change = time.monotonic() 85 | 86 | def turn_off(self, **kwargs): 87 | try: 88 | with HisenseTv(self._host) as tv: 89 | tv.send_key_power() 90 | self._state = False 91 | self._last_state_change = time.monotonic() 92 | except socket.error as e: 93 | if "host is unreachable" in str(e).lower(): 94 | _LOGGER.debug("unable to reach TV, likely powered off already") 95 | else: 96 | raise 97 | 98 | @property 99 | def is_on(self): 100 | """Return true if switch is on.""" 101 | return self._state 102 | 103 | @property 104 | def name(self): 105 | """Return the name of the switch.""" 106 | return self._name 107 | 108 | def update(self): 109 | """Check if device is on and update the state.""" 110 | # skip updating via ping if power state has changed in last 15s 111 | if time.monotonic() - self._last_state_change < 15: 112 | return 113 | 114 | if platform.system().lower() == "windows": 115 | ping_cmd = [ 116 | "ping", 117 | "-n", 118 | "1", 119 | "-w", 120 | str(DEFAULT_PING_TIMEOUT * 1000), 121 | str(self._host), 122 | ] 123 | else: 124 | ping_cmd = [ 125 | "ping", 126 | "-c", 127 | "1", 128 | "-W", 129 | str(DEFAULT_PING_TIMEOUT), 130 | str(self._host), 131 | ] 132 | 133 | status = sp.call(ping_cmd, stdout=sp.DEVNULL, stderr=sp.DEVNULL) 134 | self._state = not bool(status) 135 | --------------------------------------------------------------------------------