Commit 66e9d0a9 authored by Dave Russell's avatar Dave Russell
Browse files

Add MQTT controller support

This commit adds support for an MQTT-based controller to be used with the climate component.
A user would need to have an appropriate MQTT client that can emit IR/RF/etc based on the
payload received.
parent ff011272
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ DEFAULT_NAME = "SmartIR Climate"
CONF_UNIQUE_ID = 'unique_id'
CONF_DEVICE_CODE = 'device_code'
CONF_CONTROLLER_SEND_SERVICE = "controller_send_service"
CONF_CONTROLLER_COMMAND_TOPIC = "controller_command_topic"
CONF_TEMPERATURE_SENSOR = 'temperature_sensor'
CONF_HUMIDITY_SENSOR = 'humidity_sensor'
CONF_POWER_SENSOR = 'power_sensor'
@@ -43,6 +44,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
    vol.Required(CONF_DEVICE_CODE): cv.positive_int,
    vol.Required(CONF_CONTROLLER_SEND_SERVICE): cv.entity_id,
    vol.Required(CONF_CONTROLLER_COMMAND_TOPIC): cv.string,
    vol.Optional(CONF_TEMPERATURE_SENSOR): cv.entity_id,
    vol.Optional(CONF_HUMIDITY_SENSOR): cv.entity_id,
    vol.Optional(CONF_POWER_SENSOR): cv.entity_id
@@ -95,6 +97,7 @@ class SmartIRClimate(ClimateDevice, RestoreEntity):
        self._name = config.get(CONF_NAME)
        self._device_code = config.get(CONF_DEVICE_CODE)
        self._controller_send_service = config.get(CONF_CONTROLLER_SEND_SERVICE)
        self._controller_command_topic = config.get(CONF_CONTROLLER_COMMAND_TOPIC)
        self._temperature_sensor = config.get(CONF_TEMPERATURE_SENSOR)
        self._humidity_sensor = config.get(CONF_HUMIDITY_SENSOR)
        self._power_sensor = config.get(CONF_POWER_SENSOR)
@@ -129,7 +132,8 @@ class SmartIRClimate(ClimateDevice, RestoreEntity):
            self.hass,
            self._supported_controller, 
            self._commands_encoding,
            self._controller_send_service)
            self._controller_send_service
            self._controller_command_topic)
            
    async def async_added_to_hass(self):
        """Run when entity about to be added."""
+51 −32
Original line number Diff line number Diff line
@@ -7,21 +7,27 @@ from homeassistant.core import split_entity_id
from . import Helper

BROADLINK_CONTROLLER = 'Broadlink'
MQTT_CONTROLLER = 'MQTT'
XIAOMI_CONTROLLER = 'Xiaomi'

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

BROADLINK_COMMANDS_ENCODING = [
    ENC_BASE64, ENC_HEX, ENC_PRONTO]

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

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

        if controller == BROADLINK_CONTROLLER:
            if encoding not in BROADLINK_COMMANDS_ENCODING:
                raise Exception("The encoding is not supported "
@@ -30,15 +36,19 @@ class Controller():
        self.hass = hass
        self._service_domain = split_entity_id(service)[0]
        self._service_name = split_entity_id(service)[1]
        self._command_topic = topic
        self._controller = controller
        self._encoding = encoding

        if controller == XIAOMI_CONTROLLER:
            raise Exception("The Xiaomi IR controller "
                            "is not yet supported.")
        if self._service_domain == 'mqtt':
            if self._command_topic == '':
                raise Exception("controller_command_topic must be "
                                "specified for mqtt controllers.")

    async def send(self, command):
        if self._controller == BROADLINK_CONTROLLER:
        if self._controller not in [BROADLINK_CONTROLLER, MQTT_CONTROLLER]:
            raise Exception("Unsupported controller")

        if self._encoding == ENC_HEX:
            try:
                command = binascii.unhexlify(command)
@@ -58,6 +68,15 @@ class Controller():
                raise Exception("Error while converting "
                                "Pronto to Base64 encoding")

        if self._controller == BROADLINK_CONTROLLER:
            service_data = {'packet': command}

        if self._controller = MQTT_CONTROLLER:
            service_data = {
                     'topic': self._command_topic,
                     'payload': command
                 }

        await self.hass.services.async_call(
            self._service_domain, self._service_name, 
                {'packet': command})
 No newline at end of file
            service_data)
 No newline at end of file
+5 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ DEFAULT_NAME = "SmartIR Fan"
CONF_UNIQUE_ID = 'unique_id'
CONF_DEVICE_CODE = 'device_code'
CONF_CONTROLLER_SEND_SERVICE = "controller_send_service"
CONF_CONTROLLER_COMMAND_TOPIC = "controller_command_topic"
CONF_POWER_SENSOR = 'power_sensor'

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
@@ -33,6 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
    vol.Required(CONF_DEVICE_CODE): cv.positive_int,
    vol.Required(CONF_CONTROLLER_SEND_SERVICE): cv.entity_id,
    vol.Required(CONF_CONTROLLER_COMMAND_TOPIC): cv.string,
    vol.Optional(CONF_POWER_SENSOR): cv.entity_id
})

@@ -83,6 +85,7 @@ class SmartIRFan(FanEntity, RestoreEntity):
        self._name = config.get(CONF_NAME)
        self._device_code = config.get(CONF_DEVICE_CODE)
        self._controller_send_service = config.get(CONF_CONTROLLER_SEND_SERVICE)
        self._controller_command_topic = config.get(CONF_CONTROLLER_COMMAND_TOPIC)
        self._power_sensor = config.get(CONF_POWER_SENSOR)

        self._manufacturer = device_data['manufacturer']
@@ -112,7 +115,8 @@ class SmartIRFan(FanEntity, RestoreEntity):
            self.hass,
            self._supported_controller, 
            self._commands_encoding,
            self._controller_send_service)
            self._controller_send_service
            self._controller_command_topic)

    async def async_added_to_hass(self):
        """Run when entity about to be added."""
+5 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ DEFAULT_NAME = "SmartIR Media Player"
CONF_UNIQUE_ID = 'unique_id'
CONF_DEVICE_CODE = 'device_code'
CONF_CONTROLLER_SEND_SERVICE = "controller_send_service"
CONF_CONTROLLER_COMMAND_TOPIC = "controller_command_topic"
CONF_POWER_SENSOR = 'power_sensor'

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
@@ -33,6 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
    vol.Required(CONF_DEVICE_CODE): cv.positive_int,
    vol.Required(CONF_CONTROLLER_SEND_SERVICE): cv.entity_id,
    vol.Required(CONF_CONTROLLER_COMMAND_TOPIC): cv.string,
    vol.Optional(CONF_POWER_SENSOR): cv.entity_id
})

@@ -83,6 +85,7 @@ class SmartIRMediaPlayer(MediaPlayerDevice, RestoreEntity):
        self._name = config.get(CONF_NAME)
        self._device_code = config.get(CONF_DEVICE_CODE)
        self._controller_send_service = config.get(CONF_CONTROLLER_SEND_SERVICE)
        self._controller_command_topic = config.get(CONF_CONTROLLER_COMMAND_TOPIC)
        self._power_sensor = config.get(CONF_POWER_SENSOR)

        self._manufacturer = device_data['manufacturer']
@@ -130,7 +133,8 @@ class SmartIRMediaPlayer(MediaPlayerDevice, RestoreEntity):
            self.hass,
            self._supported_controller, 
            self._commands_encoding,
            self._controller_send_service)
            self._controller_send_service
            self._controller_command_topic)

    async def async_added_to_hass(self):
        """Run when entity about to be added."""