Added Search Configuration to IMAP Sensor (#19749)
* Added Search Configuration to IMAP Sensor The IMAP sensor currently only counts unread emails in a folder. By exposing the IMAP search parameter, the sensor can be used to count other results: - All emails in an inbox - Emails sent from an address - Emails matching a subject - Other advanced searches, especially with vendor-specific extensions. Gmail in particular supports X-GM-RAW, which lets you use any Gmail search directly ("emails with X label older than 14 days with", etc) For my use case, I just wanted total emails in a folder, to show an "X/Y" counter for total/unread. I started work on a one-off script to throw the data in, but figured I'd try to extend Home Assistant more directly, especially since this IMAP sensor correctly handles servers that push data. This is my first Home Assistant contribution, so apologies in advance if something is out of place! It's a pretty minimal modification. * Added Server Response Checking Looks like no library exception is thrown, so check for response text before parsing out results (previous code just counts spaces, so an error actually returns a state value of 4). * IMAP Warning -> Error, Count Initializes to None IMAP search response parsing throws an error instead of a warning. Email count initializes as None instead 0. Email count is untouched in case of failure to parse response (i.e. if server is temporarily down or throwing errors, or maybe due to user updating their authentication/login/etc). Fixed line length on error so it fits under 80 characters. * Fixed Indent on Logger Error Sorry about the churn! Python is pretty far from my daily-use language. (I did run this one through pep8, at least)
This commit is contained in:
parent
0987219b28
commit
6bf42ad43d
1 changed files with 21 additions and 11 deletions
|
@ -24,6 +24,7 @@ REQUIREMENTS = ['aioimaplib==0.7.13']
|
|||
|
||||
CONF_SERVER = 'server'
|
||||
CONF_FOLDER = 'folder'
|
||||
CONF_SEARCH = 'search'
|
||||
|
||||
DEFAULT_PORT = 993
|
||||
|
||||
|
@ -36,6 +37,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|||
vol.Required(CONF_SERVER): cv.string,
|
||||
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
||||
vol.Optional(CONF_FOLDER, default='INBOX'): cv.string,
|
||||
vol.Optional(CONF_SEARCH, default='UnSeen UnDeleted'): cv.string,
|
||||
})
|
||||
|
||||
|
||||
|
@ -49,7 +51,8 @@ async def async_setup_platform(hass,
|
|||
config.get(CONF_PASSWORD),
|
||||
config.get(CONF_SERVER),
|
||||
config.get(CONF_PORT),
|
||||
config.get(CONF_FOLDER))
|
||||
config.get(CONF_FOLDER),
|
||||
config.get(CONF_SEARCH))
|
||||
if not await sensor.connection():
|
||||
raise PlatformNotReady
|
||||
|
||||
|
@ -60,7 +63,7 @@ async def async_setup_platform(hass,
|
|||
class ImapSensor(Entity):
|
||||
"""Representation of an IMAP sensor."""
|
||||
|
||||
def __init__(self, name, user, password, server, port, folder):
|
||||
def __init__(self, name, user, password, server, port, folder, search):
|
||||
"""Initialize the sensor."""
|
||||
self._name = name or user
|
||||
self._user = user
|
||||
|
@ -68,7 +71,8 @@ class ImapSensor(Entity):
|
|||
self._server = server
|
||||
self._port = port
|
||||
self._folder = folder
|
||||
self._unread_count = 0
|
||||
self._email_count = None
|
||||
self._search = search
|
||||
self._connection = None
|
||||
self._does_push = None
|
||||
self._idle_loop_task = None
|
||||
|
@ -90,8 +94,8 @@ class ImapSensor(Entity):
|
|||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the number of unread emails."""
|
||||
return self._unread_count
|
||||
"""Return the number of emails found."""
|
||||
return self._email_count
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
|
@ -127,7 +131,7 @@ class ImapSensor(Entity):
|
|||
while True:
|
||||
try:
|
||||
if await self.connection():
|
||||
await self.refresh_unread_count()
|
||||
await self.refresh_email_count()
|
||||
await self.async_update_ha_state()
|
||||
|
||||
idle = await self._connection.idle_start()
|
||||
|
@ -146,16 +150,22 @@ class ImapSensor(Entity):
|
|||
|
||||
try:
|
||||
if await self.connection():
|
||||
await self.refresh_unread_count()
|
||||
await self.refresh_email_count()
|
||||
except (aioimaplib.AioImapException, asyncio.TimeoutError):
|
||||
self.disconnected()
|
||||
|
||||
async def refresh_unread_count(self):
|
||||
"""Check the number of unread emails."""
|
||||
async def refresh_email_count(self):
|
||||
"""Check the number of found emails."""
|
||||
if self._connection:
|
||||
await self._connection.noop()
|
||||
_, lines = await self._connection.search('UnSeen UnDeleted')
|
||||
self._unread_count = len(lines[0].split())
|
||||
result, lines = await self._connection.search(self._search)
|
||||
|
||||
if result == 'OK':
|
||||
self._email_count = len(lines[0].split())
|
||||
else:
|
||||
_LOGGER.error("Can't parse IMAP server response to search "
|
||||
"'%s': %s / %s",
|
||||
self._search, result, lines[0])
|
||||
|
||||
def disconnected(self):
|
||||
"""Forget the connection after it was lost."""
|
||||
|
|
Loading…
Add table
Reference in a new issue