Skip to content

Commit

Permalink
feat: ✨ Added thresholds to consume via automations
Browse files Browse the repository at this point in the history
Three thresholds were added in the config flow: Info (>50%), Warning (>75) and Critical (>95%) for the used weight of a spool. If one of them are exceeded, an HomeAssistant event is raised. See README for more.

closes #22
  • Loading branch information
Disane87 committed Oct 4, 2023
1 parent 11fa660 commit af9accc
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 8 deletions.
16 changes: 16 additions & 0 deletions custom_components/spoolman/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@

from .const import (
API_HEALTH_ENDPOINT,
CONF_NOTIFICATION_THRESHOLD_CRITICAL,
CONF_NOTIFICATION_THRESHOLD_INFO,
CONF_NOTIFICATION_THRESHOLD_WARNING,
CONF_UPDATE_INTERVAL,
CONF_URL,
DOMAIN,
CONF_SHOW_ARCHIVED,
NOTIFICATION_THRESHOLDS,
)


Expand Down Expand Up @@ -85,6 +89,18 @@ async def async_step_user(
vol.Optional(CONF_UPDATE_INTERVAL, default=15): vol.All( # type: ignore
vol.Coerce(int), vol.Range(min=1)
),
vol.Required(
CONF_NOTIFICATION_THRESHOLD_INFO,
default=NOTIFICATION_THRESHOLDS.get("info", 0), # type: ignore
): vol.All(int, vol.Range(min=0, max=100)),
vol.Required(
CONF_NOTIFICATION_THRESHOLD_WARNING,
default=NOTIFICATION_THRESHOLDS.get("warning", 0), # type: ignore
): vol.All(int, vol.Range(min=0, max=100)),
vol.Required(
CONF_NOTIFICATION_THRESHOLD_CRITICAL,
default=NOTIFICATION_THRESHOLDS.get("critical", 0), # type: ignore
): vol.All(int, vol.Range(min=0, max=100)),
vol.Required(CONF_SHOW_ARCHIVED): bool,
}
),
Expand Down
8 changes: 8 additions & 0 deletions custom_components/spoolman/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,17 @@
CONF_URL = "spoolman_url"
CONF_SHOW_ARCHIVED = "show_archived"
CONF_UPDATE_INTERVAL = "update-interval"
CONF_NOTIFICATION_THRESHOLD_INFO = "notification_threshold_info"
CONF_NOTIFICATION_THRESHOLD_WARNING = "notification_threshold_warning"
CONF_NOTIFICATION_THRESHOLD_CRITICAL = "notification_threshold_critical"

API_SPOOL_ENDPOINT = "api/v1/spool"
API_HEALTH_ENDPOINT = "api/v1/health"

PUBLIC_IMAGE_PATH = "www/spoolman_images"
LOCAL_IMAGE_PATH = "/local/spoolman_images"

EVENT_THRESHOLD_EXCEEDED = "threshold_exceeded"


NOTIFICATION_THRESHOLDS = {"critical": 95, "warning": 75, "info": 50}
69 changes: 63 additions & 6 deletions custom_components/spoolman/sensor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
"""Spoolman home assistant sensor."""
from .const import (
CONF_URL,
DOMAIN,
EVENT_THRESHOLD_EXCEEDED,
NOTIFICATION_THRESHOLDS,
PUBLIC_IMAGE_PATH,
LOCAL_IMAGE_PATH,
)
from .coordinator import SpoolManCoordinator

import logging
import os
from PIL import Image

Expand All @@ -13,8 +23,9 @@
from homeassistant.const import (
UnitOfMass,
)
from .const import CONF_URL, DOMAIN, PUBLIC_IMAGE_PATH, LOCAL_IMAGE_PATH
from .coordinator import SpoolManCoordinator

_LOGGER = logging.getLogger(__name__)


ICON = "mdi:printer-3d-nozzle"

Expand Down Expand Up @@ -44,8 +55,10 @@ def __init__(self, hass, coordinator, spool_data, idx, config_entry) -> None:
super().__init__(coordinator)

conf_url = hass.data[DOMAIN][CONF_URL]
self.config = hass.data[DOMAIN]

self._spool = spool_data
self.handled_threshold_events = []
self._filament = self._spool["filament"]
self._entry = config_entry
self._attr_name = f"{self._filament['vendor']['name']} {self._filament['name']} {self._filament['material']}"
Expand All @@ -61,7 +74,7 @@ def __init__(self, hass, coordinator, spool_data, idx, config_entry) -> None:
)

self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, conf_url)},
identifiers={(DOMAIN, conf_url, location_name)}, # type: ignore
name=location_name,
manufacturer="https://github.com/Donkie/Spoolman",
model="Spoolman",
Expand All @@ -76,17 +89,61 @@ def _handle_coordinator_update(self) -> None:
self._spool = self.coordinator.data[self.idx]

self._filament = self._spool["filament"]
self._spool["used_percentage"] = (
round(self._spool["used_weight"] / self._filament["weight"], 3) * 100
)

if self._spool["archived"] is False:
self.check_for_threshold(self._spool, self._spool["used_percentage"])

self.async_write_ha_state()

@property
def extra_state_attributes(self):
"""Return the attributes of the sensor."""
spool = self._spool
spool["used_percentage"] = (
round(self._spool["used_weight"] / self._filament["weight"], 3) * 100
)

return self.flatten_dict(spool)

def check_for_threshold(self, spool, used_percentage):
"""Check if the used percentage is above a threshold and fire an event if it is."""
for key, _value in sorted(
NOTIFICATION_THRESHOLDS.items(), key=lambda x: x[1], reverse=True
):
threshold_name = key
config_threshold = self.config[f"notification_threshold_{threshold_name}"]

if threshold_name in self.handled_threshold_events:
_LOGGER.debug(
"SpoolManCoordinator.check_for_threshold: '%s' already handled for spool '%s' in '%s' with '%s'",
threshold_name,
self._attr_name,
self._spool["location"],
used_percentage,
)
break

if used_percentage >= config_threshold:
_LOGGER.debug(
"SpoolManCoordinator.check_for_threshold: '%s' reached for spool '%s' in '%s' with '%s'",
threshold_name,
self._attr_name,
self._spool["location"],
used_percentage,
)
self.hass.bus.fire(
EVENT_THRESHOLD_EXCEEDED,
{
"entity_id": self.entity_id,
"data": spool,
"threshold_name": threshold_name,
"threshold_value": config_threshold,
"used_percentage": used_percentage,
},
)
self.handled_threshold_events.append(threshold_name)
break

def flatten_dict(self, d, parent_key="", sep="_"):
"""Flattens a dictionary."""
flat_dict = {}
Expand Down
5 changes: 4 additions & 1 deletion custom_components/spoolman/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
"data": {
"spoolman_url": "Host (inkl. Protokol)",
"update-interval": "Update Interval (Minuten)",
"show_archived": "Archivierte anzeigen"
"show_archived": "Archivierte anzeigen",
"notification_threshold_info": "Schwellenwert Info",
"notification_threshold_warning": "Schwellenwert Warnung",
"notification_threshold_critical": "Schwellenwert Kritisch"
}
}
},
Expand Down
5 changes: 4 additions & 1 deletion custom_components/spoolman/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
"data": {
"spoolman_url": "Host (incl. protocol)",
"update-interval": "Update interval (minutes)",
"show_archived": "Show archived"
"show_archived": "Show archived",
"notification_threshold_info": "Threshold Info",
"notification_threshold_warning": "Threshold Warning",
"notification_threshold_critical": "Threshold Critical"
}
}
},
Expand Down

0 comments on commit af9accc

Please sign in to comment.