Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: moralmunky/Home-Assistant-Mail-And-Packages
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0.4.2-b2
Choose a base ref
...
head repository: moralmunky/Home-Assistant-Mail-And-Packages
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: dev
Choose a head ref

Commits on Nov 14, 2024

  1. Copy the full SHA
    a98a75b View commit details

Commits on Nov 20, 2024

  1. Copy the full SHA
    080521c View commit details
  2. fix: update amazon delivered subject for amazon.de (#1009)

    * fix: update amazon delivered subject for amazon.de
    
    * update tests
    firstof9 authored Nov 20, 2024
    Copy the full SHA
    acea8e4 View commit details
  3. Copy the full SHA
    5a4f9f6 View commit details
  4. Copy the full SHA
    3dcde19 View commit details
  5. fix: attempt to fix IO blocking with ssl contexts (#1012)

    * fix: attempt to fix IO blocking with ssl contexts
    
    * linting
    firstof9 authored Nov 20, 2024
    Copy the full SHA
    3611e96 View commit details

Commits on Dec 2, 2024

  1. fix: Update Intelcom Shipper (#1024)

    * Update Intelcom Shipper
    
    Intelcom changed its name to Dragonfly and updated email notifications.
    
    * Update const.py
    glbailey authored Dec 2, 2024
    Copy the full SHA
    3c95c7d View commit details

Commits on Dec 3, 2024

  1. fix: add additional Hermes subject to search (#1022)

    * Added Otto mal subject
    
    * Update custom_components/mail_and_packages/const.py
    
    Co-authored-by: Chris <1105672+firstof9@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Chris <1105672+firstof9@users.noreply.github.com>
    TheHawk588 and firstof9 authored Dec 3, 2024
    Copy the full SHA
    b6c90de View commit details

Commits on Dec 4, 2024

  1. fix: adjust decoding for amazon emails (#1025)

    * fix: adjust decoding for amazon emails
    
    * adjust ssl context
    
    * attempt alternative processing method
    
    * attempt to get_payload with no value
    
    * adjust processing for amazon hub emails as well
    
    * formatting
    
    * update tests to py3.13
    firstof9 authored Dec 4, 2024
    Copy the full SHA
    dd73594 View commit details
  2. fix: config flow missing storage default (#1027)

    * fix: config flow missing storage default
    
    * formatting
    firstof9 authored Dec 4, 2024
    Copy the full SHA
    de0247f View commit details
  3. Copy the full SHA
    1ae4b70 View commit details
  4. fix: fix iCloud email fetching due to non-RFC IMAP server (#1026)

    * fix: fix iCloud email fetching due to non-RFC IMAP server
    
    * update test fixtures
    firstof9 authored Dec 4, 2024
    Copy the full SHA
    ac4085c View commit details

Commits on Dec 6, 2024

  1. fix: update Walmart delivered search (#1029)

    Updated Walmart deliveries to include "Arrived:"
    derpderpington authored Dec 6, 2024
    Copy the full SHA
    fcf6ad4 View commit details

Commits on Dec 18, 2024

  1. fix: add additional amazon email (#1034)

    * fix: add additional amazon email
    
    * update tests
    
    * update test workflow
    firstof9 authored Dec 18, 2024
    Copy the full SHA
    d618f42 View commit details

Commits on Dec 19, 2024

  1. Copy the full SHA
    9972855 View commit details
  2. Copy the full SHA
    f21fe35 View commit details
  3. Copy the full SHA
    e3d2a88 View commit details

Commits on Jan 4, 2025

  1. fix(shipper): Various german fixes (#1036)

    * various german fixes
    
    * black formatting
    KuotenoAshiato authored Jan 4, 2025
    Copy the full SHA
    9b03710 View commit details

Commits on Jan 13, 2025

  1. fix(shipper): add new auto-confirm for amazon shipment tracking (#1047

    )
    
    * fix(shipper): add new auto-confirm shipment tracking
    
    * fix(shipper): extend tests
    
    * Update tests/test_helpers.py
    
    Co-authored-by: Chris <1105672+firstof9@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Rasmus Hansen <r.fangelhansen@gmail.com>
    Co-authored-by: Chris <1105672+firstof9@users.noreply.github.com>
    3 people authored Jan 13, 2025
    Copy the full SHA
    2bce056 View commit details

Commits on Jan 22, 2025

  1. feat: add image grid output for vision enabled LLMs (#1057)

    * feat: add image grid output for vision enabled LLMs
    
    * update tests
    
    * linting
    
    * update tests
    
    * dynamically size tile output
    
    * add path sensor and update tests
    
    * fix tests
    
    * formatting
    firstof9 authored Jan 22, 2025
    Copy the full SHA
    2b48d13 View commit details

Commits on Jan 28, 2025

  1. fix: make sure default image location exists (#1059)

    * fix: make sure default image location exists
    
    * fix test
    firstof9 authored Jan 28, 2025
    Copy the full SHA
    5f15970 View commit details
  2. feat: add Rewe Lieferservice (#1060)

    * feat: add Rewe Lieferservice
    
    * formatting
    
    * add rewe_lieferservice to SHIPPERS
    
    * update test
    firstof9 authored Jan 28, 2025
    Copy the full SHA
    4803473 View commit details

Commits on Jan 29, 2025

  1. Copy the full SHA
    b6d709b View commit details

Commits on Feb 10, 2025

  1. Copy the full SHA
    61b8ba6 View commit details

Commits on Feb 14, 2025

  1. Copy the full SHA
    0f1e948 View commit details
  2. fix: move amazon fwd email check to amazon reconfig function (#1067)

    * fix: move amazon fwd email check to amazon reconfig function
    
    * fix: format with black
    
    ---------
    
    Co-authored-by: Hogantg <hogan.gleadhill@ahead.com>
    hogantg and Hogantg authored Feb 14, 2025
    Copy the full SHA
    786937d View commit details

Commits on Feb 18, 2025

  1. Copy the full SHA
    7ef5b3c View commit details

Commits on Feb 21, 2025

  1. Copy the full SHA
    1efc3e1 View commit details

Commits on Feb 27, 2025

  1. fix: add regex searching fucntion for amazon emails (#1079)

    * fix: add regex searching fucntion for amazon emails
    
    * add capost tracking # and out for delivery emails
    
    * properly escape regex searches
    firstof9 authored Feb 27, 2025
    Copy the full SHA
    5ca8db8 View commit details

Commits on Mar 7, 2025

  1. Copy the full SHA
    c4e2263 View commit details
Showing with 3,561 additions and 375 deletions.
  1. +2 −1 .github/workflows/pytest.yaml
  2. +0 −1 .gitignore
  3. +69 −1 custom_components/mail_and_packages/__init__.py
  4. +1 −58 custom_components/mail_and_packages/binary_sensor.py
  5. +2 −7 custom_components/mail_and_packages/camera.py
  6. +12 −5 custom_components/mail_and_packages/config_flow.py
  7. +174 −26 custom_components/mail_and_packages/const.py
  8. +14 −0 custom_components/mail_and_packages/entity.py
  9. +321 −149 custom_components/mail_and_packages/helpers.py
  10. +1 −0 custom_components/mail_and_packages/images/.PLACEHOLDER
  11. +10 −11 custom_components/mail_and_packages/sensor.py
  12. +2 −0 custom_components/mail_and_packages/strings.json
  13. +4 −2 custom_components/mail_and_packages/translations/ca.json
  14. +4 −2 custom_components/mail_and_packages/translations/de.json
  15. +4 −2 custom_components/mail_and_packages/translations/en.json
  16. +4 −2 custom_components/mail_and_packages/translations/es.json
  17. +4 −2 custom_components/mail_and_packages/translations/es_419.json
  18. +4 −2 custom_components/mail_and_packages/translations/fi.json
  19. +4 −2 custom_components/mail_and_packages/translations/fr.json
  20. +4 −2 custom_components/mail_and_packages/translations/hu.json
  21. +4 −2 custom_components/mail_and_packages/translations/it.json
  22. +4 −2 custom_components/mail_and_packages/translations/ko.json
  23. +4 −2 custom_components/mail_and_packages/translations/nl.json
  24. +4 −2 custom_components/mail_and_packages/translations/no.json
  25. +4 −2 custom_components/mail_and_packages/translations/pl.json
  26. +4 −2 custom_components/mail_and_packages/translations/pt.json
  27. +4 −2 custom_components/mail_and_packages/translations/pt_BR.json
  28. +4 −2 custom_components/mail_and_packages/translations/ru.json
  29. +4 −2 custom_components/mail_and_packages/translations/sk.json
  30. +4 −2 custom_components/mail_and_packages/translations/sl.json
  31. +4 −2 custom_components/mail_and_packages/translations/sv.json
  32. +4 −2 custom_components/mail_and_packages/translations/zh_Hant_HK.json
  33. +1 −0 pylintrc
  34. +1 −1 setup.cfg
  35. +163 −47 tests/conftest.py
  36. +25 −0 tests/const.py
  37. +64 −0 tests/test_binary_sensor.py
  38. +39 −5 tests/test_config_flow.py
  39. +619 −0 tests/test_emails/amazon_otp.eml
  40. +1,735 −0 tests/test_emails/capost_mail.eml
  41. +220 −21 tests/test_helpers.py
  42. +6 −2 tox.ini
3 changes: 2 additions & 1 deletion .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
@@ -15,7 +15,8 @@ jobs:
python-version:
# - "3.10"
# - "3.11"
- "3.12"
# - "3.12"
- "3.13"

steps:
- name: 📥 Checkout the repository
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -12,7 +12,6 @@ custom_components/mail_and_packages/.backup/__init__.py
custom_components/mail_and_packages/.backup/camera.py
custom_components/mail_and_packages/.backup/manifest.json
custom_components/mail_and_packages/.backup/sensor.py
custom_components/mail_and_packages/images/*
notes.txt

# Test files
70 changes: 69 additions & 1 deletion custom_components/mail_and_packages/__init__.py
Original file line number Diff line number Diff line change
@@ -2,15 +2,20 @@

import asyncio
import logging
import os
from datetime import timedelta

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_RESOURCES
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import (
ATTR_AMAZON_IMAGE,
ATTR_IMAGE_NAME,
ATTR_IMAGE_PATH,
CONF_AMAZON_DAYS,
CONF_AMAZON_DOMAIN,
CONF_AMAZON_FWDS,
@@ -29,7 +34,7 @@
PLATFORMS,
VERSION,
)
from .helpers import process_emails
from .helpers import default_image_path, hash_file, process_emails

_LOGGER = logging.getLogger(__name__)

@@ -54,6 +59,9 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
# Sort the resources
updated_config[CONF_RESOURCES] = sorted(updated_config[CONF_RESOURCES])

if CONF_PATH not in updated_config:
updated_config[CONF_PATH] = "custom_components/mail_and_packages/images/"

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

@@ -79,6 +87,18 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
return True


async def async_remove_config_entry_device( # pylint: disable-next=unused-argument
hass: HomeAssistant, config_entry: ConfigEntry, device_entry: dr.DeviceEntry
) -> bool:
"""Remove config entry from a device if its no longer present."""
return not any(
identifier
for identifier in device_entry.identifiers
if identifier[0] == DOMAIN
and config_entry.runtime_data.get_device(identifier[1])
)


async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Handle removal of an entry."""
_LOGGER.debug("Attempting to unload sensors from the %s integration", DOMAIN)
@@ -210,4 +230,52 @@ async def _async_update_data(self):

if data:
self._data = data
await self._binary_sensor_update()
return self._data

async def _binary_sensor_update(self):
"""Update binary sensor states."""
attributes = (ATTR_IMAGE_NAME, ATTR_IMAGE_PATH)
if set(attributes).issubset(self._data.keys()):
image = self._data[ATTR_IMAGE_NAME]
path = default_image_path(self.hass, self.config)
usps_image = f"{path}/{image}"
usps_none = f"{os.path.dirname(__file__)}/mail_none.gif"
usps_check = os.path.exists(usps_image)
_LOGGER.debug("USPS Check: %s", usps_check)
if usps_check:
image_hash = await self.hass.async_add_executor_job(
hash_file, usps_image
)
none_hash = await self.hass.async_add_executor_job(hash_file, usps_none)

_LOGGER.debug("USPS Image hash: %s", image_hash)
_LOGGER.debug("USPS None hash: %s", none_hash)

if image_hash != none_hash:
self._data["usps_update"] = True
else:
self._data["usps_update"] = False
attributes = (ATTR_AMAZON_IMAGE, ATTR_IMAGE_PATH)
if set(attributes).issubset(self._data.keys()):
image = self._data[ATTR_AMAZON_IMAGE]
path = f"{default_image_path(self.hass, self.config)}/amazon/"
amazon_image = f"{path}{image}"
amazon_none = f"{os.path.dirname(__file__)}/no_deliveries.jpg"
amazon_check = os.path.exists(amazon_image)
_LOGGER.debug("Amazon Check: %s", amazon_check)
if amazon_check:
image_hash = await self.hass.async_add_executor_job(
hash_file, amazon_image
)
none_hash = await self.hass.async_add_executor_job(
hash_file, amazon_none
)

_LOGGER.debug("Amazon Image hash: %s", image_hash)
_LOGGER.debug("Amazon None hash: %s", none_hash)

if image_hash != none_hash:
self._data["amazon_update"] = True
else:
self._data["amazon_update"] = False
59 changes: 1 addition & 58 deletions custom_components/mail_and_packages/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"""Binary sensors for Mail and Packages."""

import asyncio
import logging
import os

from homeassistant.components.binary_sensor import (
BinarySensorEntity,
@@ -15,16 +13,7 @@
DataUpdateCoordinator,
)

from .const import (
ATTR_AMAZON_IMAGE,
ATTR_IMAGE_NAME,
ATTR_IMAGE_PATH,
BINARY_SENSORS,
COORDINATOR,
DOMAIN,
VERSION,
)
from .helpers import default_image_path, hash_file
from .const import BINARY_SENSORS, COORDINATOR, DOMAIN, VERSION

_LOGGER = logging.getLogger(__name__)

@@ -77,55 +66,9 @@ def should_poll(self) -> bool:
"""No need to poll. Coordinator notifies entity of updates."""
return False

@property
def available(self) -> bool:
"""Return if entity is available."""
return self.coordinator.last_update_success

@property
def is_on(self) -> bool:
"""Return True if the image is updated."""
if self._type == "usps_update":
attributes = (ATTR_IMAGE_NAME, ATTR_IMAGE_PATH)
if set(attributes).issubset(self.coordinator.data.keys()):
image = self.coordinator.data[ATTR_IMAGE_NAME]
path = default_image_path(self.hass, self._config)
usps_image = f"{path}/{image}"
usps_none = f"{os.path.dirname(__file__)}/mail_none.gif"
usps_check = os.path.exists(usps_image)
_LOGGER.debug("USPS Check: %s", usps_check)
if usps_check:
loop = asyncio.get_running_loop()
image_hash = loop.run_in_executor(None, hash_file, usps_image)
none_hash = loop.run_in_executor(None, hash_file, usps_none)

_LOGGER.debug("USPS Image hash: %s", image_hash)
_LOGGER.debug("USPS None hash: %s", none_hash)

if image_hash != none_hash:
return True
return False

if self._type == "amazon_update":
attributes = (ATTR_AMAZON_IMAGE, ATTR_IMAGE_PATH)
if set(attributes).issubset(self.coordinator.data.keys()):
image = self.coordinator.data[ATTR_AMAZON_IMAGE]
path = f"{default_image_path(self.hass, self._config)}/amazon/"
amazon_image = f"{path}{image}"
amazon_none = f"{os.path.dirname(__file__)}/no_deliveries.jpg"
amazon_check = os.path.exists(amazon_image)
_LOGGER.debug("Amazon Check: %s", amazon_check)
if amazon_check:
loop = asyncio.get_running_loop()
image_hash = loop.run_in_executor(None, hash_file, amazon_image)
none_hash = loop.run_in_executor(None, hash_file, amazon_none)

_LOGGER.debug("Amazon Image hash: %s", image_hash)
_LOGGER.debug("Amazon None hash: %s", none_hash)

if image_hash != none_hash:
return True
return False
if self._type in self.coordinator.data.keys():
_LOGGER.debug(
"binary_sensor: %s value: %s",
9 changes: 2 additions & 7 deletions custom_components/mail_and_packages/camera.py
Original file line number Diff line number Diff line change
@@ -116,7 +116,7 @@ async def async_camera_image(
file = await self.hass.async_add_executor_job(open, self._file_path, "rb")
return file.read()
except FileNotFoundError:
_LOGGER.warning(
_LOGGER.info(
"Could not read camera %s image from file: %s",
self._name,
self._file_path,
@@ -125,7 +125,7 @@ async def async_camera_image(
def check_file_path_access(self, file_path: str) -> None:
"""Check that filepath given is readable."""
if not os.access(file_path, os.R_OK):
_LOGGER.warning(
_LOGGER.info(
"Could not read camera %s image from file: %s", self._name, file_path
)

@@ -208,8 +208,3 @@ def should_poll(self) -> bool:
async def async_update(self):
"""Update camera entity and refresh attributes."""
self.update_file_path()

@property
def available(self) -> bool:
"""Return if entity is available."""
return self._coordinator.last_update_success
17 changes: 12 additions & 5 deletions custom_components/mail_and_packages/config_flow.py
Original file line number Diff line number Diff line change
@@ -22,15 +22,16 @@
CONF_AMAZON_FWDS,
CONF_CUSTOM_IMG,
CONF_CUSTOM_IMG_FILE,
CONF_STORAGE,
CONF_DURATION,
CONF_FOLDER,
CONF_GENERATE_GRID,
CONF_GENERATE_MP4,
CONF_IMAGE_SECURITY,
CONF_IMAP_SECURITY,
CONF_IMAP_TIMEOUT,
CONF_PATH,
CONF_SCAN_INTERVAL,
CONF_STORAGE,
CONF_VERIFY_SSL,
CONFIG_VER,
DEFAULT_ALLOW_EXTERNAL,
@@ -230,6 +231,9 @@ def _get_default(key: str, fallback_default: Any = None) -> None:
vol.Optional(
CONF_DURATION, default=_get_default(CONF_DURATION)
): vol.Coerce(int),
vol.Optional(
CONF_GENERATE_GRID, default=_get_default(CONF_GENERATE_GRID)
): cv.boolean,
vol.Optional(
CONF_GENERATE_MP4, default=_get_default(CONF_GENERATE_MP4)
): cv.boolean,
@@ -295,7 +299,9 @@ def _get_default(key: str, fallback_default: Any = None) -> None:

return vol.Schema(
{
vol.Required(CONF_STORAGE, default=_get_default(CONF_STORAGE)): cv.string,
vol.Required(
CONF_STORAGE, default=_get_default(CONF_STORAGE, DEFAULT_STORAGE)
): cv.string,
}
)

@@ -382,6 +388,7 @@ async def _show_config_2(self, user_input):
CONF_DURATION: DEFAULT_GIF_DURATION,
CONF_IMAGE_SECURITY: DEFAULT_IMAGE_SECURITY,
CONF_IMAP_TIMEOUT: DEFAULT_IMAP_TIMEOUT,
CONF_GENERATE_GRID: False,
CONF_GENERATE_MP4: False,
CONF_ALLOW_EXTERNAL: DEFAULT_ALLOW_EXTERNAL,
CONF_CUSTOM_IMG: DEFAULT_CUSTOM_IMG,
@@ -531,9 +538,6 @@ async def async_step_reconfig_2(self, user_input=None):

async def _show_reconfig_2(self, user_input):
"""Step 2 setup."""
if self._data[CONF_AMAZON_FWDS] == []:
self._data[CONF_AMAZON_FWDS] = "(none)"

return self.async_show_form(
step_id="reconfig_2",
data_schema=_get_schema_step_2(self._data, user_input, self._data),
@@ -584,6 +588,9 @@ async def async_step_reconfig_amazon(self, user_input=None):

async def _show_reconfig_amazon(self, user_input):
"""Step 3 setup."""
if self._data[CONF_AMAZON_FWDS] == []:
self._data[CONF_AMAZON_FWDS] = "(none)"

return self.async_show_form(
step_id="reconfig_amazon",
data_schema=_get_schema_step_amazon(user_input, self._data),
Loading