Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ omit =
homeassistant/components/sensor/twitch.py
homeassistant/components/sensor/uber.py
homeassistant/components/sensor/worldclock.py
homeassistant/components/switch/acer_projector.py
homeassistant/components/switch/arest.py
homeassistant/components/switch/dlink.py
homeassistant/components/switch/edimax.py
Expand Down
145 changes: 145 additions & 0 deletions homeassistant/components/switch/acer_projector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
"""
Use serial protocol of acer projector to obtain state of the projector.

This component allows to control almost all projectors from acer using
their RS232 serial communication protocol.
"""

import logging
import re

from homeassistant.components.switch import SwitchDevice
from homeassistant.const import (STATE_ON, STATE_OFF, STATE_UNKNOWN,
CONF_NAME, CONF_FILENAME)

LAMP_HOURS = 'Lamp Hours'
INPUT_SOURCE = 'Input Source'
ECO_MODE = 'ECO Mode'
MODEL = 'Model'
LAMP = 'Lamp'

# Commands known to the projector
CMD_DICT = {LAMP: '* 0 Lamp ?\r',
LAMP_HOURS: '* 0 Lamp\r',
INPUT_SOURCE: '* 0 Src ?\r',
ECO_MODE: '* 0 IR 052\r',
MODEL: '* 0 IR 035\r',
STATE_ON: '* 0 IR 001\r',
STATE_OFF: '* 0 IR 002\r'}

_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['pyserial<=3.0']

ICON = 'mdi:projector'


# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
"""Connect with serial port and return Acer Projector."""
serial_port = config.get(CONF_FILENAME, None)
name = config.get(CONF_NAME, 'Projector')
timeout = config.get('timeout', 1)
write_timeout = config.get('write_timeout', 1)

if not serial_port:
_LOGGER.error('Missing path of serial device')
return

devices = []
devices.append(AcerSwitch(serial_port, name, timeout, write_timeout))
add_devices_callback(devices)


class AcerSwitch(SwitchDevice):
"""Represents an Acer Projector as an switch."""

def __init__(self, serial_port, name='Projector',
timeout=1, write_timeout=1, **kwargs):
"""Init of the Acer projector."""
import serial
self.ser = serial.Serial(port=serial_port, timeout=timeout,
write_timeout=write_timeout, **kwargs)
self._serial_port = serial_port
self._name = name
self._state = STATE_UNKNOWN
self._attributes = {
LAMP_HOURS: STATE_UNKNOWN,
INPUT_SOURCE: STATE_UNKNOWN,
ECO_MODE: STATE_UNKNOWN,
}
self.update()

def _write_read(self, msg):
"""Write to the projector and read the return."""
import serial
ret = ""
# Sometimes the projector won't answer for no reason,
# or the projector was disconnected during runtime.
# Thisway the projector can be reconnected and will still
# work
try:
if not self.ser.is_open:
self.ser.open()
msg = msg.encode('utf-8')
self.ser.write(msg)
# size is an experience value there is no real limit.
# AFAIK there is no limit and no end character so
# we will usually need to wait for timeout
ret = self.ser.read_until(size=20).decode('utf-8')
except serial.SerialException:
_LOGGER.error('Problem comunicating with %s', self._serial_port)
self.ser.close()
return ret

def _write_read_format(self, msg):
"""Write msg, obtain awnser and format output."""
# awnsers are formated as ***\rawnser\r***
awns = self._write_read(msg)
match = re.search(r'\r(.+)\r', awns)
if match:
return match.group(1)
return STATE_UNKNOWN

@property
def name(self):
"""Return name of the projector."""
return self._name

@property
def state(self):
"""Return the current state of the projector."""
return self._state

@property
def state_attributes(self):
"""Return state attributes."""
return self._attributes

def update(self):
"""Get the latest state from the projector."""
msg = CMD_DICT[LAMP]
awns = self._write_read_format(msg)
if awns == 'Lamp 1':
self._state = STATE_ON
elif awns == 'Lamp 0':
self._state = STATE_OFF
else:
self._state = STATE_UNKNOWN

for key in self._attributes.keys():
msg = CMD_DICT.get(key, None)
if msg:
awns = self._write_read_format(msg)
self._attributes[key] = awns

def turn_on(self):
"""Turn the projector on."""
msg = CMD_DICT[STATE_ON]
self._write_read(msg)
self._state = STATE_ON

def turn_off(self):
"""Turn the projector off."""
msg = CMD_DICT[STATE_OFF]
self._write_read(msg)
self._state = STATE_OFF
3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ pynx584==0.2
# homeassistant.components.sensor.openweathermap
pyowm==2.3.1

# homeassistant.components.switch.acer_projector
pyserial<=3.0

# homeassistant.components.device_tracker.snmp
pysnmp==4.2.5

Expand Down