Commit 90cd36a2 authored by Vassilis Panos's avatar Vassilis Panos
Browse files

Update to 1.3.8

parent b3c39b6a
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -7,8 +7,21 @@ The key features of the component are:
* Support for voice assistants.

## **Component setup instructions**
Create the folder `custom_components`, if it does not exist, in the home assistant’s config directory. Create the `smartir` folder and copy `__init__.py`, ` climate.py`, ` fan.py` and `media_player.py` files into it.
Add the following to your configuration.yaml file.
1. Create a directory `custom_components` in your Home Assistant configuration directory.
2. Copy `smartir` from this project including **all** files and sub-directories into the directory `custom_components`.

It should look similar to this after installation:
```
.homeassistant/
|-- custom_components/
|   |-- smartir/
|       |-- __init__.py
|       |-- climate.py
|       |-- fan.py
|       |-- media_player.py
|       |-- etc...
```
3. Add the following to your configuration.yaml file.
```yaml
smartir:
```
+4 −4
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@ from homeassistant.helpers.typing import ConfigType
_LOGGER = logging.getLogger(__name__)

DOMAIN = 'smartir'
VERSION = '1.3.7'
VERSION = '1.3.8'
VERSION_URL = (
    "https://raw.githubusercontent.com/"
    "smartHomeHub/SmartIR/{}/version.json")
@@ -125,16 +125,16 @@ class Helper():
                for chunk in req.iter_content(1024):
                    fil.write(chunk)
        else:
            raise Exception('File not found')
            raise Exception("File not found")

    @staticmethod
    def pronto2lirc(pronto):
        codes = [int(binascii.hexlify(pronto[i:i+2]), 16) for i in range(0, len(pronto), 2)]

        if codes[0]:
            raise ValueError('Pronto code should start with 0000')
            raise ValueError("Pronto code should start with 0000")
        if len(codes) != 4 + 2 * (codes[2] + codes[3]):
            raise ValueError('Number of pulse widths does not match the preamble')
            raise ValueError("Number of pulse widths does not match the preamble")

        frequency = 1 / (codes[1] * 0.241246)
        return [int(round(code / frequency)) for code in codes[4:]]
+14 −42
Original line number Diff line number Diff line
import asyncio
from base64 import b64encode
import binascii
import json
import logging
import os.path
@@ -15,11 +13,12 @@ from homeassistant.components.climate.const import (
from homeassistant.const import (
    CONF_NAME, STATE_OFF, STATE_ON, STATE_UNKNOWN, ATTR_TEMPERATURE,
    PRECISION_TENTHS, PRECISION_HALVES, PRECISION_WHOLE)
from homeassistant.core import callback, split_entity_id
from homeassistant.core import callback
from homeassistant.helpers.event import async_track_state_change
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.restore_state import RestoreEntity
from . import COMPONENT_ABS_DIR, Helper
from .controller import Controller

_LOGGER = logging.getLogger(__name__)

@@ -125,6 +124,13 @@ class SmartIRClimate(ClimateDevice, RestoreEntity):
        self._temp_lock = asyncio.Lock()
        self._on_by_remote = False

        #Init the IR/RF controller
        self._controller = Controller(
            self.hass,
            self._supported_controller, 
            self._commands_encoding,
            self._controller_send_service)
            
    async def async_added_to_hass(self):
        """Run when entity about to be added."""
        await super().async_added_to_hass()
@@ -311,8 +317,6 @@ class SmartIRClimate(ClimateDevice, RestoreEntity):
    async def send_command(self):
        async with self._temp_lock:
            self._on_by_remote = False
            supported_controller = self._supported_controller
            commands_encoding = self._commands_encoding
            operation_mode = self._current_operation
            fan_mode = self._current_fan_mode
            target_temperature = '{0:g}'.format(self._target_temperature)
@@ -322,42 +326,10 @@ class SmartIRClimate(ClimateDevice, RestoreEntity):
            else:
                command = self._commands[operation_mode][fan_mode][target_temperature]

            service_domain = split_entity_id(self._controller_send_service)[0]
            service_name = split_entity_id(self._controller_send_service)[1]

            if supported_controller.lower() == 'broadlink':
                if commands_encoding.lower() == 'base64':
                    pass
                elif commands_encoding.lower() == 'hex':
                    try:
                        command = binascii.unhexlify(command)
                        command = b64encode(command).decode('utf-8')
                    except:
                        _LOGGER.error("Error while converting Hex to Base64")
                        return
                elif commands_encoding.lower() == 'pronto':
            try:
                        command = command.replace(' ',"")
                        command = bytearray.fromhex(command)
                        command = Helper.pronto2lirc(command)
                        command = Helper.lirc2broadlink(command)
                        command = b64encode(command).decode('utf-8')
                    except:
                        _LOGGER.error("Error while converting Pronto to Base64")
                        return
                else:
                    _LOGGER.error("The commands encoding provided in the JSON file is not supported")
                    return

                service_data = {
                    'packet': command
                }

            else:
                _LOGGER.error("The controller provided in the JSON file is not supported")
                return

            await self.hass.services.async_call(service_domain, service_name, service_data)
                await self._controller.send(command)
            except Exception as e:
                _LOGGER.exception(e)
            
    async def _async_temp_sensor_changed(self, entity_id, old_state, new_state):
        """Handle temperature sensor changes."""

smartir/controller.py

0 → 100644
+63 −0
Original line number Diff line number Diff line
import asyncio
from base64 import b64encode
import binascii
import logging

from homeassistant.core import split_entity_id
from . import Helper

BROADLINK_CONTROLLER = 'Broadlink'
XIAOMI_CONTROLLER = 'Xiaomi'

ENC_BASE64 = 'Base64'
ENC_HEX = 'Hex'
ENC_PRONTO = 'Pronto'

BROADLINK_COMMANDS_ENCODING = [
    ENC_BASE64, ENC_HEX, ENC_PRONTO]

class Controller():
    def __init__(self, hass, controller, encoding, service):
        if controller not in [
            BROADLINK_CONTROLLER, XIAOMI_CONTROLLER]:
            raise Exception("The controller is not supported.")

        if controller == BROADLINK_CONTROLLER:
            if encoding not in BROADLINK_COMMANDS_ENCODING:
                raise Exception("The encoding is not supported "
                                "by the Broadlink controller.")

            self.hass = hass
            self._service_domain = split_entity_id(service)[0]
            self._service_name = split_entity_id(service)[1]
            self._controller = controller
            self._encoding = encoding

        if controller == XIAOMI_CONTROLLER:
            raise Exception("The Xiaomi IR controller "
                            "is not yet supported.")

    async def send(self, command):
        if self._controller == BROADLINK_CONTROLLER:
            if self._encoding == ENC_HEX:
                try:
                    command = binascii.unhexlify(command)
                    command = b64encode(command).decode('utf-8')
                except:
                    raise Exception("Error while converting "
                                    "Hex to Base64 encoding")

            if self._encoding == ENC_PRONTO:
                try:
                    command = command.replace(' ', '')
                    command = bytearray.fromhex(command)
                    command = Helper.pronto2lirc(command)
                    command = Helper.lirc2broadlink(command)
                    command = b64encode(command).decode('utf-8')
                except:
                    raise Exception("Error while converting "
                                    "Pronto to Base64 encoding")

            await self.hass.services.async_call(
                self._service_domain, self._service_name, 
                {'packet': command})
 No newline at end of file
+13 −41
Original line number Diff line number Diff line
import asyncio
from base64 import b64encode
import binascii
import json
import logging
import os.path
@@ -14,11 +12,12 @@ from homeassistant.components.fan import (
    SUPPORT_SET_SPEED, SUPPORT_DIRECTION)
from homeassistant.const import (
    CONF_NAME, STATE_OFF, STATE_ON, STATE_UNKNOWN)
from homeassistant.core import callback, split_entity_id
from homeassistant.core import callback
from homeassistant.helpers.event import async_track_state_change
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.restore_state import RestoreEntity
from . import COMPONENT_ABS_DIR, Helper
from .controller import Controller

_LOGGER = logging.getLogger(__name__)

@@ -108,6 +107,13 @@ class SmartIRFan(FanEntity, RestoreEntity):
        self._temp_lock = asyncio.Lock()
        self._on_by_remote = False

        #Init the IR/RF controller
        self._controller = Controller(
            self.hass,
            self._supported_controller, 
            self._commands_encoding,
            self._controller_send_service)

    async def async_added_to_hass(self):
        """Run when entity about to be added."""
        await super().async_added_to_hass()
@@ -224,8 +230,6 @@ class SmartIRFan(FanEntity, RestoreEntity):
    async def send_command(self):
        async with self._temp_lock:
            self._on_by_remote = False
            supported_controller = self._supported_controller
            commands_encoding = self._commands_encoding
            speed = self._speed
            direction = self._direction or 'default'

@@ -234,42 +238,10 @@ class SmartIRFan(FanEntity, RestoreEntity):
            else:
                command = self._commands[direction][speed] 

            service_domain = split_entity_id(self._controller_send_service)[0]
            service_name = split_entity_id(self._controller_send_service)[1]

            if supported_controller.lower() == 'broadlink':
                if commands_encoding.lower() == 'base64':
                    pass
                elif commands_encoding.lower() == 'hex':
                    try:
                        command = binascii.unhexlify(command)
                        command = b64encode(command).decode('utf-8')
                    except:
                        _LOGGER.error("Error while converting Hex to Base64")
                        return
                elif commands_encoding.lower() == 'pronto':
            try:
                        command = command.replace(' ',"")
                        command = bytearray.fromhex(command)
                        command = Helper.pronto2lirc(command)
                        command = Helper.lirc2broadlink(command)
                        command = b64encode(command).decode('utf-8')
                    except:
                        _LOGGER.error("Error while converting Pronto to Base64")
                        return
                else:
                    _LOGGER.error("The commands encoding provided in the JSON file is not supported")
                    return

                service_data = {
                    'packet': command
                }

            else:
                _LOGGER.error("The controller provided in the JSON file is not supported")
                return

            await self.hass.services.async_call(service_domain, service_name, service_data)
                await self._controller.send(command)
            except Exception as e:
                _LOGGER.exception(e)

    async def _async_power_sensor_changed(self, entity_id, old_state, new_state):
        """Handle power sensor changes."""
Loading