Skip to content

Commit

Permalink
Add project image preview entity
Browse files Browse the repository at this point in the history
  • Loading branch information
WaresWichall committed Sep 1, 2024
1 parent 7c7611b commit 8f4c174
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2036,8 +2036,22 @@ async def get_latest_project(

if projects and len(projects) > 0:
for proj in projects:
if printer_id is None or proj.printer_id == printer_id:
# Look for matching project and fill image URL from previous cloud print if available
if (
latest_project is None and
(printer_id is None or proj.printer_id == printer_id)
):
latest_project = proj

if latest_project.image_url or not latest_project.name:
break

elif latest_project and proj.name == latest_project.name:
if proj.image_url:
latest_project.set_image_url(proj.image_url)
break

elif latest_project:
break

if latest_project:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

PUBLIC_API_ENDPOINT = "p/p/workbench/api"

PROJECT_IMAGE_URL_BASE = "https://workbentch.s3.us-east-2.amazonaws.com/"

REX_JS_FILE = re.compile(r'src="(/js/app\.[^.]+\.js)"')
# REX_CLIENT_ID = re.compile(r',clientId:"([^"]+)",')
REX_CLIENT_ID = re.compile(r'\'(?!getEl)([a-zA-Z0-9]{20})\'')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ def _update_latest_project_slice_param(
new_slice_param,
):
if self._check_latest_project_id_valid(incoming_project_id):
self._latest_project.update_slice_param(
self._latest_project.set_slice_param(
new_slice_param,
)

Expand Down Expand Up @@ -1416,6 +1416,13 @@ def latest_project_name(self):

return None

@property
def latest_project_image_url(self):
if self.latest_project:
return self.latest_project.image_url

return None

@property
def latest_project_progress_percentage(self):
if self.latest_project:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import time

from .anycubic_const import (
PROJECT_IMAGE_URL_BASE,
REX_GCODE_EXT,
)

Expand Down Expand Up @@ -91,7 +92,7 @@ def __init__(
self._printer_id = int(printer_id) if printer_id is not None else None
self._gcode_id = int(gcode_id)
self._model = int(model) if model is not None else None
self._img = str(img) if img is not None else None
self.set_image_url(img)
self._estimate = int(estimate)
self._remain_time = int(remain_time) if remain_time is not None else None
self._material = str(material) if material is not None else None
Expand All @@ -114,7 +115,7 @@ def __init__(
self._slice_end_time = int(slice_end_time) if slice_end_time is not None else None
self._total_time = str(total_time) if total_time is not None else None
self._print_time = int(print_time) if print_time is not None else None
self._slice_param = slice_param
self.set_slice_param(slice_param)
self._delete = int(delete) if delete is not None else None
self._auto_operation = auto_operation
self._monitor = monitor
Expand Down Expand Up @@ -152,11 +153,7 @@ def __init__(
self._temp_min_nozzle = None
self._temp_max_nozzle = None
self._download_progress = 0
if self._slice_param and isinstance(self._slice_param, str):
try:
self._slice_param = json.loads(str(self._slice_param))
except Exception as e:
print(f"Error in json parsing slice_param: {e}\n{self._slice_param}")

if self._slice_result and isinstance(self._slice_result, str):
try:
self._slice_result = json.loads(str(self._slice_result))
Expand Down Expand Up @@ -242,6 +239,9 @@ def from_gcode_json(cls, api_parent, data):
slice_param=data['slice_param'],
)

def set_image_url(self, image_url):
self._image_url = str(image_url) if image_url is not None else None

def set_filename(self, filename):
self._gcode_name = REX_GCODE_EXT.sub('', str(filename))

Expand Down Expand Up @@ -353,12 +353,6 @@ def update_with_mqtt_checking_status_data(
):
self._print_status = int(AnycubicPrintStatus.Checking)

def update_slice_param(
self,
new_slice_param,
):
self._slice_param = new_slice_param

def _set_settings(
self,
new_settings,
Expand All @@ -381,6 +375,28 @@ def _set_settings(
f"Unexpected data for project settings: {new_settings}"
)

def set_slice_param(
self,
new_slice_param,
):
self._slice_param = {}

if new_slice_param and isinstance(new_slice_param, str):
try:
self._slice_param.update(json.loads(new_slice_param))
except Exception as e:
raise AnycubicDataParsingError(
f"Error parsing project slice_param json: {e}\n{new_slice_param}"
)

elif new_slice_param and isinstance(new_slice_param, dict):
self._slice_param.update(new_slice_param)

elif new_slice_param:
raise AnycubicDataParsingError(
f"Unexpected data for project slice_param: {new_slice_param}"
)

def _get_print_setting(self, key):
return self._settings.get(key)

Expand Down Expand Up @@ -615,9 +631,6 @@ def available_print_speed_modes_data_object(self):

@property
def slice_material_info_list(self):
if not isinstance(self._slice_param, dict):
return None

material_info_list = self._slice_param.get('paint_infos')

if not isinstance(material_info_list, list):
Expand All @@ -639,6 +652,18 @@ def slice_total_filament_used(self):

return total_filament

@property
def image_url(self):
if isinstance(self._image_url, str) and self._image_url.startswith("http"):
return self._image_url

img_endpoint = self._slice_param.get('image_id')

if img_endpoint and isinstance(img_endpoint, str):
return PROJECT_IMAGE_URL_BASE + img_endpoint

return None

def validate_target_nozzle_temperature(
self,
target_nozzle_temperature: int,
Expand Down
1 change: 1 addition & 0 deletions custom_components/anycubic_cloud/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
PLATFORMS = [
Platform.BINARY_SENSOR,
Platform.BUTTON,
Platform.IMAGE,
Platform.SENSOR,
Platform.SWITCH,
Platform.UPDATE,
Expand Down
1 change: 1 addition & 0 deletions custom_components/anycubic_cloud/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ def _build_printer_dict(self, printer) -> dict[str, Any]:
"current_project_complete": printer.latest_project_print_complete,
"current_project_failed": printer.latest_project_print_failed,
"current_project_is_paused": printer.latest_project_print_is_paused,
"current_project_image_url": printer.latest_project_image_url,
"print_state": printer.latest_project_print_status,
"print_approximate_completion_time": printer.latest_project_print_approximate_completion_time,
"print_current_layer": printer.latest_project_print_current_layer,
Expand Down
106 changes: 106 additions & 0 deletions custom_components/anycubic_cloud/image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"""Support for Anycubic Cloud image."""
from __future__ import annotations

from homeassistant.components.image import (
Image,
ImageEntity,
ImageEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .const import (
CONF_PRINTER_ID_LIST,
COORDINATOR,
DOMAIN,
)
from .coordinator import AnycubicCloudDataUpdateCoordinator
from .entity import AnycubicCloudEntity
from .helpers import printer_entity_unique_id, printer_state_for_key


IMAGE_TYPES = (
ImageEntityDescription(
key="current_project_image_url",
translation_key="current_project_image_url",
),
)

GLOBAL_IMAGE_TYPES = (
)


async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the image from a config entry."""

coordinator: AnycubicCloudDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id][
COORDINATOR
]

entity_list = list()

for printer_id in entry.data[CONF_PRINTER_ID_LIST]:
for description in IMAGE_TYPES:
entity_list.append(AnycubicCloudImage(
hass,
coordinator,
printer_id,
description,
))

for description in GLOBAL_IMAGE_TYPES:
entity_list.append(AnycubicCloudImage(
hass,
coordinator,
entry.data[CONF_PRINTER_ID_LIST][0],
description,
))

async_add_entities(entity_list)


class AnycubicCloudImage(AnycubicCloudEntity, ImageEntity):
"""An image for Anycubic Cloud."""

entity_description: ImageEntityDescription

def __init__(
self,
hass: HomeAssistant,
coordinator: AnycubicCloudDataUpdateCoordinator,
printer_id: int,
description: ImageEntityDescription,
) -> None:
"""Initialize."""
super().__init__(coordinator, printer_id)
ImageEntity.__init__(self, hass)
self.entity_description = description
self._attr_unique_id = printer_entity_unique_id(coordinator, self._printer_id, description.key)
self._known_image_url = None

def reset_cached_image(self):
self._cached_image = None

@property
def image_url(self) -> str | None:
image_url = printer_state_for_key(self.coordinator, self._printer_id, self.entity_description.key)
if self._known_image_url != image_url:
self.reset_cached_image()

self._known_image_url = image_url

return self._known_image_url

async def _async_load_image_from_url(self, url: str) -> Image | None:
"""Load an image by url."""
if response := await self._fetch_url(url):
return Image(
content=response.content,
content_type="image/png",
)
return None
1 change: 1 addition & 0 deletions custom_components/anycubic_cloud/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"dependencies": [
"file_upload",
"http",
"image",
"panel_custom"
],
"documentation": "https://www.home-assistant.io/integrations/anycubic_cloud",
Expand Down
5 changes: 5 additions & 0 deletions custom_components/anycubic_cloud/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@
"name": "Refresh MQTT Connection"
}
},
"image": {
"current_project_image_url": {
"name": "Project Image Preview"
}
},
"sensor": {
"current_status": {
"name": "Current Status"
Expand Down
5 changes: 5 additions & 0 deletions custom_components/anycubic_cloud/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@
"name": "Refresh MQTT Connection"
}
},
"image": {
"current_project_image_url": {
"name": "Project Image Preview"
}
},
"sensor": {
"current_status": {
"name": "Current Status"
Expand Down

0 comments on commit 8f4c174

Please sign in to comment.