Skip to content

Commit

Permalink
Add ImagePath Sensors (#342)
Browse files Browse the repository at this point in the history
  • Loading branch information
firstof9 authored and github-actions[bot] committed Jan 17, 2021
2 parents a1d45c1 + 92bda11 commit 127c030
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 484 deletions.
100 changes: 62 additions & 38 deletions custom_components/mail_and_packages/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@

import async_timeout
from homeassistant.const import CONF_HOST
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from . import const
from .helpers import process_emails, update_time
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from .const import (
CONF_AMAZON_FWDS,
CONF_IMAGE_SECURITY,
CONF_IMAP_TIMEOUT,
CONF_PATH,
CONF_SCAN_INTERVAL,
COORDINATOR,
DOMAIN,
ISSUE_URL,
PLATFORM,
VERSION,
)
from .helpers import process_emails

_LOGGER = logging.getLogger(__name__)

Expand All @@ -23,39 +33,54 @@ async def async_setup_entry(hass, config_entry):
"""Load the saved entities."""
_LOGGER.info(
"Version %s is starting, if you have any issues please report" " them here: %s",
const.VERSION,
const.ISSUE_URL,
VERSION,
ISSUE_URL,
)
hass.data.setdefault(const.DOMAIN, {})
hass.data.setdefault(DOMAIN, {})
updated_config = config_entry.data.copy()

# Set default image path
if CONF_PATH not in config_entry.data.keys():
updated_config[CONF_PATH] = "www/mail_and_packages/"
# Set image security always on
if CONF_IMAGE_SECURITY not in config_entry.data.keys():
updated_config[CONF_IMAGE_SECURITY] = True

# Force path update
if config_entry.data[CONF_PATH] != "www/mail_and_packages/":
updated_config = config_entry.data.copy()
updated_config[CONF_PATH] = "www/mail_and_packages/"

if updated_config != config_entry.data:
hass.config_entries.async_update_entry(config_entry, data=updated_config)

config_entry.options = config_entry.data

config = config_entry.data

async def async_update_data():
"""Fetch data """
async with async_timeout.timeout(config.get(const.CONF_IMAP_TIMEOUT)):
async with async_timeout.timeout(config.get(CONF_IMAP_TIMEOUT)):
return await hass.async_add_executor_job(process_emails, hass, config)

coordinator = DataUpdateCoordinator(
hass,
_LOGGER,
name=f"Mail and Packages ({config.get(CONF_HOST)})",
update_method=async_update_data,
update_interval=timedelta(
minutes=config_entry.options.get(const.CONF_SCAN_INTERVAL)
),
update_interval=timedelta(minutes=config_entry.options.get(CONF_SCAN_INTERVAL)),
)

# Fetch initial data so we have data when entities subscribe
await coordinator.async_refresh()

hass.data[const.DOMAIN][config_entry.entry_id] = {
const.COORDINATOR: coordinator,
hass.data[DOMAIN][config_entry.entry_id] = {
COORDINATOR: coordinator,
}

config_entry.add_update_listener(update_listener)
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, const.PLATFORM)
hass.config_entries.async_forward_entry_setup(config_entry, PLATFORM)
)

return True
Expand All @@ -64,12 +89,8 @@ async def async_update_data():
async def async_unload_entry(hass, config_entry):
"""Handle removal of an entry."""
try:
await hass.config_entries.async_forward_entry_unload(
config_entry, const.PLATFORM
)
_LOGGER.info(
"Successfully removed sensor from the %s integration", const.DOMAIN
)
await hass.config_entries.async_forward_entry_unload(config_entry, PLATFORM)
_LOGGER.info("Successfully removed sensor from the %s integration", DOMAIN)
except ValueError:
pass
return True
Expand All @@ -78,9 +99,9 @@ async def async_unload_entry(hass, config_entry):
async def update_listener(hass, config_entry):
"""Update listener."""
config_entry.data = config_entry.options
await hass.config_entries.async_forward_entry_unload(config_entry, const.PLATFORM)
await hass.config_entries.async_forward_entry_unload(config_entry, PLATFORM)
hass.async_add_job(
hass.config_entries.async_forward_entry_setup(config_entry, const.PLATFORM)
hass.config_entries.async_forward_entry_setup(config_entry, PLATFORM)
)


Expand All @@ -93,27 +114,30 @@ async def async_migrate_entry(hass, config_entry):
_LOGGER.debug("Migrating from version %s", version)
data = config_entry.data.copy()

if const.CONF_AMAZON_FWDS in data.keys():
if not isinstance(data[const.CONF_AMAZON_FWDS], list):
data[const.CONF_AMAZON_FWDS] = data[const.CONF_AMAZON_FWDS].split(",")
if CONF_AMAZON_FWDS in data.keys():
if not isinstance(data[CONF_AMAZON_FWDS], list):
data[CONF_AMAZON_FWDS] = data[CONF_AMAZON_FWDS].split(",")
else:
_LOGGER.warn("Missing configuration data: %s", const.CONF_AMAZON_FWDS)

if const.CONF_IMAP_TIMEOUT not in data.keys():
data[const.CONF_IMAP_TIMEOUT] = const.DEFAULT_IMAP_TIMEOUT
_LOGGER.warn("Missing configuration data: %s", CONF_AMAZON_FWDS)
hass.config_entries.async_update_entry(config_entry, data=data)
config_entry.version = 3
_LOGGER.debug("Migration to version %s complete", config_entry.version)

# 2 -> 3: Add missing default
elif version == 2:
if version == 2:
_LOGGER.debug("Migrating from version %s", version)
data = config_entry.data.copy()
updated_config = config_entry.data.copy()

if const.CONF_IMAP_TIMEOUT not in data.keys():
data[const.CONF_IMAP_TIMEOUT] = const.DEFAULT_IMAP_TIMEOUT
hass.config_entries.async_update_entry(config_entry, data=data)
config_entry.version = 3
# Force path change
updated_config[CONF_PATH] = "www/mail_and_packages/"

_LOGGER.debug("Migration to version %s complete", config_entry.version)
# Always on image security
if not config_entry.data[CONF_IMAGE_SECURITY]:
updated_config[CONF_IMAGE_SECURITY] = True

if updated_config != config_entry.data:
hass.config_entries.async_update_entry(config_entry, data=updated_config)

config_entry.version = 3
_LOGGER.debug("Migration to version %s complete", config_entry.version)

return True
56 changes: 17 additions & 39 deletions custom_components/mail_and_packages/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Adds config flow for Mail and Packages."""

import logging
from collections import OrderedDict

import homeassistant.helpers.config_validation as cv
import voluptuous as vol
Expand Down Expand Up @@ -34,7 +33,7 @@
DEFAULT_SCAN_INTERVAL,
DOMAIN,
)
from .helpers import _check_ffmpeg, _test_login, _validate_path, get_resources, login
from .helpers import _check_ffmpeg, _test_login, get_resources, login

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -111,13 +110,9 @@ def _get_default(key):
vol.Optional(
CONF_IMAP_TIMEOUT, default=_get_default(CONF_IMAP_TIMEOUT)
): vol.Coerce(int),
vol.Optional(CONF_PATH, default=_get_default(CONF_PATH)): str,
vol.Optional(
CONF_DURATION, default=_get_default(CONF_DURATION)
): vol.Coerce(int),
vol.Optional(
CONF_IMAGE_SECURITY, default=_get_default(CONF_IMAGE_SECURITY)
): bool,
vol.Optional(
CONF_GENERATE_MP4, default=_get_default(CONF_GENERATE_MP4)
): bool,
Expand Down Expand Up @@ -177,25 +172,17 @@ async def async_step_config_2(self, user_input=None):
if user_input is not None:
user_input[CONF_AMAZON_FWDS] = user_input[CONF_AMAZON_FWDS].split(",")
self._data.update(user_input)
valid = await _validate_path(user_input[CONF_PATH])
if user_input[CONF_GENERATE_MP4]:
valid = await _check_ffmpeg()
else:
valid = True

if valid:
if user_input[CONF_GENERATE_MP4]:
valid = await _check_ffmpeg()
else:
valid = True

if valid:
if user_input[CONF_FOLDER] is not None:
if not user_input[CONF_PATH].endswith("/"):
user_input[CONF_PATH] += "/"
self._data.update(user_input)
return self.async_create_entry(
title=self._data[CONF_HOST], data=self._data
)
else:
self._errors["base"] = "ffmpeg_not_found"
return self.async_create_entry(
title=self._data[CONF_HOST], data=self._data
)
else:
self._errors["base"] = "invalid_path"
self._errors["base"] = "ffmpeg_not_found"

return await self._show_config_2(user_input)

Expand Down Expand Up @@ -271,25 +258,16 @@ async def async_step_options_2(self, user_input=None):
if user_input is not None:
user_input[CONF_AMAZON_FWDS] = user_input[CONF_AMAZON_FWDS].split(",")
self._data.update(user_input)
valid = await _validate_path(user_input[CONF_PATH])

if user_input[CONF_GENERATE_MP4]:
valid = await _check_ffmpeg()
else:
valid = True

if valid:
if user_input[CONF_GENERATE_MP4]:
valid = await _check_ffmpeg()
else:
valid = True

if valid:
if user_input[CONF_FOLDER] is not None:
if not user_input[CONF_PATH].endswith("/"):
user_input[CONF_PATH] += "/"
self._data.update(user_input)

return self.async_create_entry(title="", data=self._data)
else:
self._errors["base"] = "ffmpeg_not_found"
return self.async_create_entry(title="", data=self._data)
else:
self._errors["base"] = "invalid_path"
self._errors["base"] = "ffmpeg_not_found"

return await self._show_step_options_2(user_input)

Expand Down
16 changes: 15 additions & 1 deletion custom_components/mail_and_packages/const.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
DOMAIN = "mail_and_packages"
DOMAIN_DATA = "{}_data".format(DOMAIN)
VERSION = "0.3.0-b32"
VERSION = "0.3.0-b33"
ISSUE_URL = "http://github.com/moralmunky/Home-Assistant-Mail-And-Packages"
PLATFORM = "sensor"
DATA = "data"
Expand Down Expand Up @@ -270,6 +270,20 @@
],
}

# Name, unit of measure, icon
IMAGE_SENSORS = {
"usps_mail_image_system_path": [
"Mail Image System Path",
None,
"mdi:folder-multiple-image",
],
"usps_mail_image_url": [
"Mail Image URL",
None,
"mdi:link-variant",
],
}

# Sensor Index
SENSOR_NAME = 0
SENSOR_UNIT = 1
Expand Down
18 changes: 3 additions & 15 deletions custom_components/mail_and_packages/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,6 @@ def get_resources():
return known_available_resources


async def _validate_path(path):
""" make sure path is valid """
if os.path.exists(path):
return True
else:
return False


async def _check_ffmpeg():
""" check if ffmpeg is installed """
if which("ffmpeg") is not None:
Expand Down Expand Up @@ -86,7 +78,6 @@ def process_emails(hass, config):
pwd = config.get(CONF_PASSWORD)
folder = config.get(const.CONF_FOLDER)
resources = config.get(CONF_RESOURCES)
image_security = config.get(const.CONF_IMAGE_SECURITY)

# Login to email server and select the folder
account = login(host, port, user, pwd)
Expand All @@ -102,11 +93,7 @@ def process_emails(hass, config):

# Create image file name dict container
_image = {}
if image_security:
image_name = str(uuid.uuid4()) + ".gif"
else:
image_name = const.DEFAULT_GIF_FILE_NAME

image_name = f"{str(uuid.uuid4())}.gif"
_image[const.ATTR_IMAGE_NAME] = image_name
data.update(_image)

Expand All @@ -120,7 +107,7 @@ def process_emails(hass, config):
def fetch(hass, config, account, data, sensor):
"""Fetch data for a single sensor, including any sensors it depends on."""

img_out_path = config.get(const.CONF_PATH)
img_out_path = f"{hass.config.path()}/{config.get(const.CONF_PATH)}"
gif_duration = config.get(const.CONF_DURATION)
generate_mp4 = config.get(const.CONF_GENERATE_MP4)
amazon_fwds = config.get(const.CONF_AMAZON_FWDS)
Expand Down Expand Up @@ -440,6 +427,7 @@ def _generate_mp4(path, image_file):
cleanup_images(os.path.split(mp4_file))
_LOGGER.debug("Removing old mp4: %s", mp4_file)

# TODO: find a way to call ffmpeg the right way from HA
subprocess.call(
[
"ffmpeg",
Expand Down
Loading

0 comments on commit 127c030

Please sign in to comment.