From 56da7e835cbd811f42e7ee0c7d5336ba08a93a9e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:20:58 +0000 Subject: [PATCH 1/5] Initial plan From 7a02f51804f924be1debf928ae0e72d3dea9f5e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:24:24 +0000 Subject: [PATCH 2/5] Fix tag type definition URL and improve error handling Co-authored-by: Misiu <1741838+Misiu@users.noreply.github.com> --- custom_components/opendisplay/config_flow.py | 30 +++++++--- custom_components/opendisplay/tag_types.py | 58 ++++++++++++++------ 2 files changed, 65 insertions(+), 23 deletions(-) diff --git a/custom_components/opendisplay/config_flow.py b/custom_components/opendisplay/config_flow.py index 29803d9..1c1ef9c 100644 --- a/custom_components/opendisplay/config_flow.py +++ b/custom_components/opendisplay/config_flow.py @@ -322,12 +322,22 @@ async def async_step_bluetooth_confirm( } else: # ATC devices: Use tagtypes.json lookup and store individual fields - tag_types_manager = await get_tag_types_manager(self.hass) + # Try to get tag types manager, but don't fail if unavailable + tag_types_manager = None + try: + tag_types_manager = await get_tag_types_manager(self.hass) + _LOGGER.debug("Tag types manager loaded successfully") + except Exception as tag_err: + _LOGGER.warning( + "Could not load tag types during config flow, will use fallback values: %s", + tag_err + ) + model_name = get_hw_string(hw_type) if hw_type else "Unknown" _LOGGER.debug("Resolved hw_type %s to model: %s", hw_type, model_name) - # Refine color_scheme using TagTypes db - if tag_types_manager.is_in_hw_map(hw_type): + # Refine color_scheme using TagTypes db if available + if tag_types_manager and tag_types_manager.is_in_hw_map(hw_type): tag_type = await tag_types_manager.get_tag_info(hw_type) color_table = tag_type.color_table @@ -342,10 +352,16 @@ async def async_step_bluetooth_confirm( else: # Fallback to protocol detection color_scheme = capabilities.color_scheme - _LOGGER.warning( - "hw_type %s not in TagTypes, using protocol color_scheme: %d", - hw_type, color_scheme - ) + if not tag_types_manager: + _LOGGER.info( + "Tag types not available, using protocol-detected color_scheme: %d", + color_scheme + ) + else: + _LOGGER.warning( + "hw_type %s not in TagTypes, using protocol color_scheme: %d", + hw_type, color_scheme + ) # Build device metadata from capabilities device_metadata = { diff --git a/custom_components/opendisplay/tag_types.py b/custom_components/opendisplay/tag_types.py index fa9b012..1142e75 100644 --- a/custom_components/opendisplay/tag_types.py +++ b/custom_components/opendisplay/tag_types.py @@ -16,8 +16,8 @@ _LOGGER = logging.getLogger(__name__) -GITHUB_API_URL = "https://api.github.com/repos/OpenDisplay/OpenDisplay/contents/resources/tagtypes" -GITHUB_RAW_URL = "https://raw.githubusercontent.com/OpenDisplay/OpenDisplay/master/resources/tagtypes" +GITHUB_API_URL = "https://api.github.com/repos/OpenEPaperLink/OpenEPaperLink/contents/resources/tagtypes" +GITHUB_RAW_URL = "https://raw.githubusercontent.com/OpenEPaperLink/OpenEPaperLink/master/resources/tagtypes" CACHE_DURATION = timedelta(hours=48) # Cache tag definitions for 48 hours STORAGE_VERSION = 1 STORAGE_KEY = "opendisplay_tagtypes" @@ -239,6 +239,13 @@ async def load_stored_data(self) -> None: if fetch_success: await self._cleanup_legacy_file() else: + # If fetch failed and we have no types, load fallback definitions + if not self._tag_types: + _LOGGER.warning( + "Failed to fetch tag types from GitHub and no stored data available. " + "Loading fallback definitions. Tag types will be refreshed on next integration reload." + ) + self._load_fallback_types() await self._cleanup_legacy_file() async def _save_to_store(self) -> None: @@ -308,30 +315,32 @@ async def ensure_types_loaded(self) -> None: This is the primary method that should be called before accessing tag type information to ensure data availability. - Raises: - HomeAssistantError: If tag types could not be loaded + If tag types cannot be loaded from GitHub or storage, fallback + definitions will be used to ensure basic functionality. """ async with self._lock: if not self._tag_types: await self.load_stored_data() - # If still no types after loading from storage, this is a critical failure + # After load_stored_data, we should always have types (either from storage, + # GitHub, or fallback). If not, something is seriously wrong. if not self._tag_types: - raise HomeAssistantError( - translation_domain=DOMAIN, - translation_key="tagtypes_load_failed", + _LOGGER.error( + "Critical error: No tag types available after loading. " + "This should not happen as fallback types should be loaded." ) + # Load fallback as last resort + self._load_fallback_types() # If the cache is expired, attempt refresh if not self._last_update or datetime.now() - self._last_update > CACHE_DURATION: _LOGGER.debug("Tag types cache expired, attempting refresh") fetch_success = await self._fetch_tag_types() - # If refresh failed and have no valid types, raise an exception - if not fetch_success and not self._tag_types: - raise HomeAssistantError( - translation_domain=DOMAIN, - translation_key="tagtypes_refresh_failed" + # If refresh failed, log a warning but continue with existing types + if not fetch_success: + _LOGGER.warning( + "Failed to refresh tag types from GitHub. Using cached or fallback definitions." ) async def _fetch_tag_types(self) -> bool: @@ -348,11 +357,17 @@ async def _fetch_tag_types(self) -> bool: falls back to built-in basic definitions. """ try: + _LOGGER.debug("Fetching tag type definitions from GitHub: %s", GITHUB_API_URL) async with aiohttp.ClientSession() as session: # First get the directory listing from GitHub API headers = {"Accept": "application/vnd.github.v3+json"} async with session.get(GITHUB_API_URL, headers=headers) as response: if response.status != 200: + _LOGGER.error( + "GitHub API request failed with status %d for URL: %s", + response.status, + GITHUB_API_URL + ) raise Exception(f"GitHub API returned status {response.status}") directory_contents = await response.json() @@ -405,13 +420,24 @@ async def _fetch_tag_types(self) -> bool: if new_types: self._tag_types = new_types self._last_update = datetime.now() - _LOGGER.info(f"Successfully loaded {len(new_types)} tag definitions") + _LOGGER.info( + "Successfully loaded %d tag definitions from GitHub", + len(new_types) + ) await self._save_to_store() return True - _LOGGER.error("No valid tag definitions found") + _LOGGER.warning( + "No valid tag definitions found in GitHub repository at %s", + GITHUB_API_URL + ) except Exception as e: - _LOGGER.error(f"Error fetching tag types: {str(e)}") + _LOGGER.error( + "Error fetching tag types from %s: %s", + GITHUB_API_URL, + str(e), + exc_info=True + ) return False # Do NOT load fallback types - let caller decide how to handle failure From a6ce3955289c798481e7f7dd3c6c1f6242f05fc5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:34:49 +0000 Subject: [PATCH 3/5] Update fallback tag type definitions with complete data from OpenEPaperLink Co-authored-by: Misiu <1741838+Misiu@users.noreply.github.com> --- custom_components/opendisplay/tag_types.py | 114 ++++++++++++++++++--- 1 file changed, 98 insertions(+), 16 deletions(-) diff --git a/custom_components/opendisplay/tag_types.py b/custom_components/opendisplay/tag_types.py index 1142e75..7b75d04 100644 --- a/custom_components/opendisplay/tag_types.py +++ b/custom_components/opendisplay/tag_types.py @@ -466,27 +466,109 @@ def _validate_tag_definition(self, data: Dict) -> bool: def _load_fallback_types(self) -> None: """Load basic fallback definitions if fetching fails on first run. - Populates the manager with a minimal set of built-in tag type + Populates the manager with a comprehensive set of built-in tag type definitions to ensure basic functionality when GitHub is unreachable. - This provides support for common tag models with basic dimensions, - though without detailed configuration options. + This provides support for all known tag models with proper dimensions, + version information, and basic configuration options. - The fallback types include: - - - Common M2 tag sizes (1.54", 2.9", 4.2") - - AP display types - - LILYGO TPANEL - - Segmented tag type + The fallback types include all tag definitions from the OpenEPaperLink + repository at: https://github.com/OpenEPaperLink/OpenEPaperLink/tree/master/resources/tagtypes """ fallback_definitions = { - 0: {"name": "M2 1.54\"", "width": 152, "height": 152}, - 1: {"name": "M2 2.9\"", "width": 296, "height": 128}, - 2: {"name": "M2 4.2\"", "width": 400, "height": 300}, - 224: {"name": "AP display", "width": 320, "height": 170}, - 225: {"name": "AP display", "width": 160, "height": 80}, - 226: {"name": "LILYGO TPANEL", "width": 480, "height": 480}, - 240: {"name": "Segmented", "width": 0, "height": 0}, + 0: {"version": 4, "name": "M2 1.54\"", "width": 152, "height": 152, "bpp": 2, "rotatebuffer": 0}, + 1: {"version": 5, "name": "M2 2.9\"", "width": 296, "height": 128, "bpp": 2, "rotatebuffer": 1}, + 2: {"version": 5, "name": "M2 4.2\"", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, + 3: {"version": 6, "name": "M2 2.2\"", "width": 212, "height": 104, "bpp": 2, "rotatebuffer": 1}, + 4: {"version": 4, "name": "M2 2.6\"", "width": 296, "height": 152, "bpp": 2, "rotatebuffer": 1}, + 5: {"version": 4, "name": "M2 7.4\"", "width": 640, "height": 384, "bpp": 2, "rotatebuffer": 0}, + 6: {"version": 4, "name": "Opticon 2.2\"", "width": 250, "height": 128, "bpp": 2, "rotatebuffer": 3}, + 7: {"version": 4, "name": "Opticon 2.9\"", "width": 296, "height": 128, "bpp": 2, "rotatebuffer": 3}, + 8: {"version": 2, "name": "Opticon 4.2\"", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 2}, + 9: {"version": 2, "name": "Opticon 7.5\"", "width": 640, "height": 384, "bpp": 2, "rotatebuffer": 2}, + 17: {"version": 3, "name": "M2 2.9\" (UC8151)", "width": 296, "height": 128, "bpp": 2, "rotatebuffer": 1}, + 18: {"version": 3, "name": "M2 4.2\" UC", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, + 33: {"version": 2, "name": "ST‐GM29XXF 2.9\"", "width": 296, "height": 128, "bpp": 1, "rotatebuffer": 1}, + 34: {"version": 2, "name": "M2 2.7\"", "width": 264, "height": 176, "bpp": 2, "rotatebuffer": 1}, + 38: {"version": 1, "name": "M2 7.5\" BW", "width": 640, "height": 384, "bpp": 1, "rotatebuffer": 0}, + 39: {"version": 3, "name": "ST‐GM29MT1 2.9\"", "width": 296, "height": 128, "bpp": 1, "rotatebuffer": 1}, + 40: {"version": 2, "name": "M3 1.6\" BWRY", "width": 168, "height": 168, "bpp": 2, "rotatebuffer": 0}, + 41: {"version": 1, "name": "M3 2.4\" BWRY", "width": 296, "height": 168, "bpp": 2, "rotatebuffer": 3}, + 42: {"version": 1, "name": "M3 3.0\" BWRY", "width": 400, "height": 168, "bpp": 2, "rotatebuffer": 3}, + 43: {"version": 1, "name": "M3 2.9\" BWRY", "width": 384, "height": 168, "bpp": 2, "rotatebuffer": 3}, + 44: {"version": 1, "name": "M3 4.3\" BWRY", "width": 522, "height": 152, "bpp": 2, "rotatebuffer": 3}, + 45: {"version": 2, "name": "M3 12.2\"", "width": 960, "height": 768, "bpp": 2, "rotatebuffer": 2}, + 46: {"version": 5, "name": "M3 9.7\"", "width": 960, "height": 672, "bpp": 2, "rotatebuffer": 2}, + 47: {"version": 4, "name": "M3 4.3\"", "width": 522, "height": 152, "bpp": 2, "rotatebuffer": 3}, + 48: {"version": 2, "name": "M3 1.6\"", "width": 200, "height": 200, "bpp": 2, "rotatebuffer": 0}, + 49: {"version": 1, "name": "M3 2.2\"", "width": 296, "height": 160, "bpp": 2, "rotatebuffer": 3}, + 50: {"version": 1, "name": "M3 2.6\"", "width": 360, "height": 184, "bpp": 2, "rotatebuffer": 3}, + 51: {"version": 3, "name": "M3 2.9\"", "width": 384, "height": 168, "bpp": 2, "rotatebuffer": 3}, + 52: {"version": 2, "name": "M3 4.2\"", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, + 53: {"version": 2, "name": "M3 6.0\"", "width": 600, "height": 448, "bpp": 2, "rotatebuffer": 0}, + 54: {"version": 5, "name": "M3 7.5\"", "width": 800, "height": 480, "bpp": 2, "rotatebuffer": 0}, + 55: {"version": 3, "name": "M3 11.6\"", "width": 960, "height": 640, "bpp": 2, "rotatebuffer": 2}, + 60: {"version": 3, "name": "M3 4.2\" BWY", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, + 64: {"version": 1, "name": "M3 2.9\" BW", "width": 384, "height": 168, "bpp": 1, "rotatebuffer": 3}, + 65: {"version": 1, "name": "M3 5.85\"", "width": 792, "height": 272, "bpp": 2, "rotatebuffer": 0}, + 66: {"version": 1, "name": "M3 5.85\" BW", "width": 792, "height": 272, "bpp": 1, "rotatebuffer": 0}, + 67: {"version": 2, "name": "M3 1.3\" Peghook", "width": 144, "height": 200, "bpp": 2, "rotatebuffer": 0}, + 68: {"version": 2, "name": "M3 5.81\" BW", "width": 720, "height": 256, "bpp": 1, "rotatebuffer": 1}, + 69: {"version": 3, "name": "M3 2.2 Lite\"", "width": 250, "height": 128, "bpp": 2, "rotatebuffer": 3}, + 70: {"version": 1, "name": "M3 2.2\" BW", "width": 296, "height": 160, "bpp": 2, "rotatebuffer": 3}, + 71: {"version": 4, "name": "M3 2.7\"", "width": 300, "height": 200, "bpp": 2, "rotatebuffer": 3}, + 72: {"version": 1, "name": "M3 5.81\" BWR", "width": 720, "height": 256, "bpp": 2, "rotatebuffer": 1}, + 73: {"version": 2, "name": "M3 5.81\" V2 BWR", "width": 720, "height": 256, "bpp": 2, "rotatebuffer": 0}, + 74: {"version": 1, "name": "M3 1.6\" 200px BWRY", "width": 200, "height": 200, "bpp": 2, "rotatebuffer": 0}, + 75: {"version": 1, "name": "M3 2.2\" BWRY", "width": 296, "height": 160, "bpp": 2, "rotatebuffer": 3}, + 76: {"version": 1, "name": "M3 7.5\" BWRY", "width": 800, "height": 480, "bpp": 2, "rotatebuffer": 0}, + 77: {"version": 3, "name": "M3 11.6\" BWRY", "width": 960, "height": 640, "bpp": 2, "rotatebuffer": 0}, + 78: {"version": 2, "name": "M3 2.6\" BW", "width": 360, "height": 184, "bpp": 1, "rotatebuffer": 3}, + 80: {"version": 2, "name": "HD150 5.83\" BWR", "width": 648, "height": 480, "bpp": 2, "rotatebuffer": 0}, + 84: {"version": 4, "name": "HS BW 2.13\"", "width": 256, "height": 128, "bpp": 1, "rotatebuffer": 1}, + 85: {"version": 5, "name": "HS BWR 2.13\"", "width": 256, "height": 128, "bpp": 2, "rotatebuffer": 1}, + 86: {"version": 6, "name": "HS BWR 2.66\"", "width": 296, "height": 152, "bpp": 2, "rotatebuffer": 1}, + 87: {"version": 3, "name": "TLSR BWR 1.54\"", "width": 200, "height": 200, "bpp": 2, "rotatebuffer": 1}, + 88: {"version": 3, "name": "TLSR BW 2.13\"", "width": 256, "height": 128, "bpp": 1, "rotatebuffer": 1}, + 89: {"version": 3, "name": "TLSR BWR 2.13\"", "width": 264, "height": 136, "bpp": 2, "rotatebuffer": 1}, + 90: {"version": 1, "name": "HS BW 2.13\" LowRes", "width": 212, "height": 104, "bpp": 1, "rotatebuffer": 1}, + 96: {"version": 6, "name": "HS BWY 3.5\"", "width": 384, "height": 184, "bpp": 2, "rotatebuffer": 1}, + 97: {"version": 4, "name": "HS BWR 3.5\"", "width": 384, "height": 184, "bpp": 2, "rotatebuffer": 1}, + 98: {"version": 4, "name": "HS BW 3.5\"", "width": 384, "height": 184, "bpp": 1, "rotatebuffer": 1}, + 99: {"version": 6, "name": "TLSR BWR 4.2\"", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, + 102: {"version": 2, "name": "HS BWY 7,5\"", "width": 800, "height": 480, "bpp": 2, "rotatebuffer": 2}, + 103: {"version": 3, "name": "HS 2.00\" BWY", "width": 152, "height": 200, "bpp": 2, "rotatebuffer": 1}, + 104: {"version": 4, "name": "HS BWY 3.46\"", "width": 480, "height": 176, "bpp": 2, "rotatebuffer": 1}, + 105: {"version": 4, "name": "TLSR BW 2.13\"", "width": 250, "height": 136, "bpp": 1, "rotatebuffer": 1}, + 106: {"version": 1, "name": "HS BWR 5,83\"", "width": 648, "height": 480, "bpp": 2, "rotatebuffer": 0}, + 107: {"version": 3, "name": "HS BWRY 7,5\"", "width": 800, "height": 480, "bpp": 2, "rotatebuffer": 2}, + 108: {"version": 3, "name": "HS BWRY 2,00\"", "width": 152, "height": 200, "bpp": 2, "rotatebuffer": 1}, + 109: {"version": 3, "name": "HS BWRY 3,5\"", "width": 384, "height": 184, "bpp": 2, "rotatebuffer": 1}, + 110: {"version": 3, "name": "HS BWRY 2,9\"", "width": 296, "height": 128, "bpp": 2, "rotatebuffer": 1}, + 111: {"version": 2, "name": "HS BWRY 2,60\"", "width": 296, "height": 152, "bpp": 2, "rotatebuffer": 1}, + 128: {"version": 1, "name": "Chroma 7.4\"", "width": 640, "height": 384, "bpp": 2, "rotatebuffer": 0}, + 129: {"version": 2, "name": "Chroma Aeon 74 7.4\"", "width": 800, "height": 480, "bpp": 2, "rotatebuffer": 0}, + 130: {"version": 2, "name": "Chroma29 2.9\"", "width": 296, "height": 128, "bpp": 2, "rotatebuffer": 1}, + 131: {"version": 2, "name": "Chroma42 4.2\"", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, + 176: {"version": 5, "name": "Gicisky BLE EPD BW 2.13\"", "width": 250, "height": 128, "bpp": 1, "rotatebuffer": 3}, + 177: {"version": 5, "name": "Gicisky BLE EPD BWR 2.13\"", "width": 250, "height": 128, "bpp": 2, "rotatebuffer": 3}, + 178: {"version": 2, "name": "Gicisky BLE EPD BW 2.9\"", "width": 296, "height": 128, "bpp": 1, "rotatebuffer": 1}, + 179: {"version": 2, "name": "Gicisky BLE EPD BWR 2.9\"", "width": 296, "height": 128, "bpp": 2, "rotatebuffer": 1}, + 181: {"version": 2, "name": "Gicisky BLE EPD BWR 4.2\"", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, + 186: {"version": 5, "name": "Gicisky BLE TFT 2.13\"", "width": 250, "height": 136, "bpp": 1, "rotatebuffer": 1}, + 189: {"version": 2, "name": "BLE EPD BWR 2.9\" Silabs", "width": 384, "height": 168, "bpp": 2, "rotatebuffer": 1}, + 190: {"version": 1, "name": "ATC MiThermometer BLE", "width": 6, "height": 8, "bpp": 1, "rotatebuffer": 1}, + 192: {"version": 2, "name": "BWRY example", "width": 360, "height": 184, "bpp": 2, "rotatebuffer": 1}, + 193: {"version": 1, "name": "ACeP 4.01", "width": 640, "height": 400, "bpp": 3, "rotatebuffer": 0}, + 194: {"version": 1, "name": "Spectra 7.3", "width": 800, "height": 480, "bpp": 4, "rotatebuffer": 0}, + 224: {"version": 2, "name": "TFT 320x172", "width": 320, "height": 172, "bpp": 16, "rotatebuffer": 0}, + 225: {"version": 2, "name": "TFT 160x80", "width": 160, "height": 80, "bpp": 16, "rotatebuffer": 1}, + 226: {"version": 1, "name": "LILYGO TPANEL 4\"", "width": 480, "height": 480, "bpp": 16, "rotatebuffer": 0}, + 227: {"version": 1, "name": "GDEM1085Z51 10.85\"", "width": 1360, "height": 480, "bpp": 2, "rotatebuffer": 0}, + 228: {"version": 1, "name": "BLE TFT 128x128", "width": 128, "height": 128, "bpp": 2, "rotatebuffer": 0}, + 229: {"version": 1, "name": "TFT 240x320", "width": 320, "height": 172, "bpp": 16, "rotatebuffer": 0}, + 240: {"version": 2, "name": "SLT‐EM007 Segmented", "width": 0, "height": 0, "bpp": 1, "rotatebuffer": 0}, + 250: {"version": 1, "name": "ConfigMode", "width": 0, "height": 0, "bpp": 1, "rotatebuffer": 0}, } self._tag_types = { type_id: TagType(type_id, data) for type_id, data in fallback_definitions.items() From 00c48b02300d11e8b6c3ecef9428c6de2cd145fb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:40:00 +0000 Subject: [PATCH 4/5] Remove unnecessary bpp and rotatebuffer fields from fallback definitions Co-authored-by: Misiu <1741838+Misiu@users.noreply.github.com> --- custom_components/opendisplay/tag_types.py | 186 ++++++++++----------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/custom_components/opendisplay/tag_types.py b/custom_components/opendisplay/tag_types.py index 7b75d04..7ebafa2 100644 --- a/custom_components/opendisplay/tag_types.py +++ b/custom_components/opendisplay/tag_types.py @@ -476,99 +476,99 @@ def _load_fallback_types(self) -> None: repository at: https://github.com/OpenEPaperLink/OpenEPaperLink/tree/master/resources/tagtypes """ fallback_definitions = { - 0: {"version": 4, "name": "M2 1.54\"", "width": 152, "height": 152, "bpp": 2, "rotatebuffer": 0}, - 1: {"version": 5, "name": "M2 2.9\"", "width": 296, "height": 128, "bpp": 2, "rotatebuffer": 1}, - 2: {"version": 5, "name": "M2 4.2\"", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, - 3: {"version": 6, "name": "M2 2.2\"", "width": 212, "height": 104, "bpp": 2, "rotatebuffer": 1}, - 4: {"version": 4, "name": "M2 2.6\"", "width": 296, "height": 152, "bpp": 2, "rotatebuffer": 1}, - 5: {"version": 4, "name": "M2 7.4\"", "width": 640, "height": 384, "bpp": 2, "rotatebuffer": 0}, - 6: {"version": 4, "name": "Opticon 2.2\"", "width": 250, "height": 128, "bpp": 2, "rotatebuffer": 3}, - 7: {"version": 4, "name": "Opticon 2.9\"", "width": 296, "height": 128, "bpp": 2, "rotatebuffer": 3}, - 8: {"version": 2, "name": "Opticon 4.2\"", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 2}, - 9: {"version": 2, "name": "Opticon 7.5\"", "width": 640, "height": 384, "bpp": 2, "rotatebuffer": 2}, - 17: {"version": 3, "name": "M2 2.9\" (UC8151)", "width": 296, "height": 128, "bpp": 2, "rotatebuffer": 1}, - 18: {"version": 3, "name": "M2 4.2\" UC", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, - 33: {"version": 2, "name": "ST‐GM29XXF 2.9\"", "width": 296, "height": 128, "bpp": 1, "rotatebuffer": 1}, - 34: {"version": 2, "name": "M2 2.7\"", "width": 264, "height": 176, "bpp": 2, "rotatebuffer": 1}, - 38: {"version": 1, "name": "M2 7.5\" BW", "width": 640, "height": 384, "bpp": 1, "rotatebuffer": 0}, - 39: {"version": 3, "name": "ST‐GM29MT1 2.9\"", "width": 296, "height": 128, "bpp": 1, "rotatebuffer": 1}, - 40: {"version": 2, "name": "M3 1.6\" BWRY", "width": 168, "height": 168, "bpp": 2, "rotatebuffer": 0}, - 41: {"version": 1, "name": "M3 2.4\" BWRY", "width": 296, "height": 168, "bpp": 2, "rotatebuffer": 3}, - 42: {"version": 1, "name": "M3 3.0\" BWRY", "width": 400, "height": 168, "bpp": 2, "rotatebuffer": 3}, - 43: {"version": 1, "name": "M3 2.9\" BWRY", "width": 384, "height": 168, "bpp": 2, "rotatebuffer": 3}, - 44: {"version": 1, "name": "M3 4.3\" BWRY", "width": 522, "height": 152, "bpp": 2, "rotatebuffer": 3}, - 45: {"version": 2, "name": "M3 12.2\"", "width": 960, "height": 768, "bpp": 2, "rotatebuffer": 2}, - 46: {"version": 5, "name": "M3 9.7\"", "width": 960, "height": 672, "bpp": 2, "rotatebuffer": 2}, - 47: {"version": 4, "name": "M3 4.3\"", "width": 522, "height": 152, "bpp": 2, "rotatebuffer": 3}, - 48: {"version": 2, "name": "M3 1.6\"", "width": 200, "height": 200, "bpp": 2, "rotatebuffer": 0}, - 49: {"version": 1, "name": "M3 2.2\"", "width": 296, "height": 160, "bpp": 2, "rotatebuffer": 3}, - 50: {"version": 1, "name": "M3 2.6\"", "width": 360, "height": 184, "bpp": 2, "rotatebuffer": 3}, - 51: {"version": 3, "name": "M3 2.9\"", "width": 384, "height": 168, "bpp": 2, "rotatebuffer": 3}, - 52: {"version": 2, "name": "M3 4.2\"", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, - 53: {"version": 2, "name": "M3 6.0\"", "width": 600, "height": 448, "bpp": 2, "rotatebuffer": 0}, - 54: {"version": 5, "name": "M3 7.5\"", "width": 800, "height": 480, "bpp": 2, "rotatebuffer": 0}, - 55: {"version": 3, "name": "M3 11.6\"", "width": 960, "height": 640, "bpp": 2, "rotatebuffer": 2}, - 60: {"version": 3, "name": "M3 4.2\" BWY", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, - 64: {"version": 1, "name": "M3 2.9\" BW", "width": 384, "height": 168, "bpp": 1, "rotatebuffer": 3}, - 65: {"version": 1, "name": "M3 5.85\"", "width": 792, "height": 272, "bpp": 2, "rotatebuffer": 0}, - 66: {"version": 1, "name": "M3 5.85\" BW", "width": 792, "height": 272, "bpp": 1, "rotatebuffer": 0}, - 67: {"version": 2, "name": "M3 1.3\" Peghook", "width": 144, "height": 200, "bpp": 2, "rotatebuffer": 0}, - 68: {"version": 2, "name": "M3 5.81\" BW", "width": 720, "height": 256, "bpp": 1, "rotatebuffer": 1}, - 69: {"version": 3, "name": "M3 2.2 Lite\"", "width": 250, "height": 128, "bpp": 2, "rotatebuffer": 3}, - 70: {"version": 1, "name": "M3 2.2\" BW", "width": 296, "height": 160, "bpp": 2, "rotatebuffer": 3}, - 71: {"version": 4, "name": "M3 2.7\"", "width": 300, "height": 200, "bpp": 2, "rotatebuffer": 3}, - 72: {"version": 1, "name": "M3 5.81\" BWR", "width": 720, "height": 256, "bpp": 2, "rotatebuffer": 1}, - 73: {"version": 2, "name": "M3 5.81\" V2 BWR", "width": 720, "height": 256, "bpp": 2, "rotatebuffer": 0}, - 74: {"version": 1, "name": "M3 1.6\" 200px BWRY", "width": 200, "height": 200, "bpp": 2, "rotatebuffer": 0}, - 75: {"version": 1, "name": "M3 2.2\" BWRY", "width": 296, "height": 160, "bpp": 2, "rotatebuffer": 3}, - 76: {"version": 1, "name": "M3 7.5\" BWRY", "width": 800, "height": 480, "bpp": 2, "rotatebuffer": 0}, - 77: {"version": 3, "name": "M3 11.6\" BWRY", "width": 960, "height": 640, "bpp": 2, "rotatebuffer": 0}, - 78: {"version": 2, "name": "M3 2.6\" BW", "width": 360, "height": 184, "bpp": 1, "rotatebuffer": 3}, - 80: {"version": 2, "name": "HD150 5.83\" BWR", "width": 648, "height": 480, "bpp": 2, "rotatebuffer": 0}, - 84: {"version": 4, "name": "HS BW 2.13\"", "width": 256, "height": 128, "bpp": 1, "rotatebuffer": 1}, - 85: {"version": 5, "name": "HS BWR 2.13\"", "width": 256, "height": 128, "bpp": 2, "rotatebuffer": 1}, - 86: {"version": 6, "name": "HS BWR 2.66\"", "width": 296, "height": 152, "bpp": 2, "rotatebuffer": 1}, - 87: {"version": 3, "name": "TLSR BWR 1.54\"", "width": 200, "height": 200, "bpp": 2, "rotatebuffer": 1}, - 88: {"version": 3, "name": "TLSR BW 2.13\"", "width": 256, "height": 128, "bpp": 1, "rotatebuffer": 1}, - 89: {"version": 3, "name": "TLSR BWR 2.13\"", "width": 264, "height": 136, "bpp": 2, "rotatebuffer": 1}, - 90: {"version": 1, "name": "HS BW 2.13\" LowRes", "width": 212, "height": 104, "bpp": 1, "rotatebuffer": 1}, - 96: {"version": 6, "name": "HS BWY 3.5\"", "width": 384, "height": 184, "bpp": 2, "rotatebuffer": 1}, - 97: {"version": 4, "name": "HS BWR 3.5\"", "width": 384, "height": 184, "bpp": 2, "rotatebuffer": 1}, - 98: {"version": 4, "name": "HS BW 3.5\"", "width": 384, "height": 184, "bpp": 1, "rotatebuffer": 1}, - 99: {"version": 6, "name": "TLSR BWR 4.2\"", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, - 102: {"version": 2, "name": "HS BWY 7,5\"", "width": 800, "height": 480, "bpp": 2, "rotatebuffer": 2}, - 103: {"version": 3, "name": "HS 2.00\" BWY", "width": 152, "height": 200, "bpp": 2, "rotatebuffer": 1}, - 104: {"version": 4, "name": "HS BWY 3.46\"", "width": 480, "height": 176, "bpp": 2, "rotatebuffer": 1}, - 105: {"version": 4, "name": "TLSR BW 2.13\"", "width": 250, "height": 136, "bpp": 1, "rotatebuffer": 1}, - 106: {"version": 1, "name": "HS BWR 5,83\"", "width": 648, "height": 480, "bpp": 2, "rotatebuffer": 0}, - 107: {"version": 3, "name": "HS BWRY 7,5\"", "width": 800, "height": 480, "bpp": 2, "rotatebuffer": 2}, - 108: {"version": 3, "name": "HS BWRY 2,00\"", "width": 152, "height": 200, "bpp": 2, "rotatebuffer": 1}, - 109: {"version": 3, "name": "HS BWRY 3,5\"", "width": 384, "height": 184, "bpp": 2, "rotatebuffer": 1}, - 110: {"version": 3, "name": "HS BWRY 2,9\"", "width": 296, "height": 128, "bpp": 2, "rotatebuffer": 1}, - 111: {"version": 2, "name": "HS BWRY 2,60\"", "width": 296, "height": 152, "bpp": 2, "rotatebuffer": 1}, - 128: {"version": 1, "name": "Chroma 7.4\"", "width": 640, "height": 384, "bpp": 2, "rotatebuffer": 0}, - 129: {"version": 2, "name": "Chroma Aeon 74 7.4\"", "width": 800, "height": 480, "bpp": 2, "rotatebuffer": 0}, - 130: {"version": 2, "name": "Chroma29 2.9\"", "width": 296, "height": 128, "bpp": 2, "rotatebuffer": 1}, - 131: {"version": 2, "name": "Chroma42 4.2\"", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, - 176: {"version": 5, "name": "Gicisky BLE EPD BW 2.13\"", "width": 250, "height": 128, "bpp": 1, "rotatebuffer": 3}, - 177: {"version": 5, "name": "Gicisky BLE EPD BWR 2.13\"", "width": 250, "height": 128, "bpp": 2, "rotatebuffer": 3}, - 178: {"version": 2, "name": "Gicisky BLE EPD BW 2.9\"", "width": 296, "height": 128, "bpp": 1, "rotatebuffer": 1}, - 179: {"version": 2, "name": "Gicisky BLE EPD BWR 2.9\"", "width": 296, "height": 128, "bpp": 2, "rotatebuffer": 1}, - 181: {"version": 2, "name": "Gicisky BLE EPD BWR 4.2\"", "width": 400, "height": 300, "bpp": 2, "rotatebuffer": 0}, - 186: {"version": 5, "name": "Gicisky BLE TFT 2.13\"", "width": 250, "height": 136, "bpp": 1, "rotatebuffer": 1}, - 189: {"version": 2, "name": "BLE EPD BWR 2.9\" Silabs", "width": 384, "height": 168, "bpp": 2, "rotatebuffer": 1}, - 190: {"version": 1, "name": "ATC MiThermometer BLE", "width": 6, "height": 8, "bpp": 1, "rotatebuffer": 1}, - 192: {"version": 2, "name": "BWRY example", "width": 360, "height": 184, "bpp": 2, "rotatebuffer": 1}, - 193: {"version": 1, "name": "ACeP 4.01", "width": 640, "height": 400, "bpp": 3, "rotatebuffer": 0}, - 194: {"version": 1, "name": "Spectra 7.3", "width": 800, "height": 480, "bpp": 4, "rotatebuffer": 0}, - 224: {"version": 2, "name": "TFT 320x172", "width": 320, "height": 172, "bpp": 16, "rotatebuffer": 0}, - 225: {"version": 2, "name": "TFT 160x80", "width": 160, "height": 80, "bpp": 16, "rotatebuffer": 1}, - 226: {"version": 1, "name": "LILYGO TPANEL 4\"", "width": 480, "height": 480, "bpp": 16, "rotatebuffer": 0}, - 227: {"version": 1, "name": "GDEM1085Z51 10.85\"", "width": 1360, "height": 480, "bpp": 2, "rotatebuffer": 0}, - 228: {"version": 1, "name": "BLE TFT 128x128", "width": 128, "height": 128, "bpp": 2, "rotatebuffer": 0}, - 229: {"version": 1, "name": "TFT 240x320", "width": 320, "height": 172, "bpp": 16, "rotatebuffer": 0}, - 240: {"version": 2, "name": "SLT‐EM007 Segmented", "width": 0, "height": 0, "bpp": 1, "rotatebuffer": 0}, - 250: {"version": 1, "name": "ConfigMode", "width": 0, "height": 0, "bpp": 1, "rotatebuffer": 0}, + 0: {"version": 4, "name": "M2 1.54\"", "width": 152, "height": 152}, + 1: {"version": 5, "name": "M2 2.9\"", "width": 296, "height": 128}, + 2: {"version": 5, "name": "M2 4.2\"", "width": 400, "height": 300}, + 3: {"version": 6, "name": "M2 2.2\"", "width": 212, "height": 104}, + 4: {"version": 4, "name": "M2 2.6\"", "width": 296, "height": 152}, + 5: {"version": 4, "name": "M2 7.4\"", "width": 640, "height": 384}, + 6: {"version": 4, "name": "Opticon 2.2\"", "width": 250, "height": 128}, + 7: {"version": 4, "name": "Opticon 2.9\"", "width": 296, "height": 128}, + 8: {"version": 2, "name": "Opticon 4.2\"", "width": 400, "height": 300}, + 9: {"version": 2, "name": "Opticon 7.5\"", "width": 640, "height": 384}, + 17: {"version": 3, "name": "M2 2.9\" (UC8151)", "width": 296, "height": 128}, + 18: {"version": 3, "name": "M2 4.2\" UC", "width": 400, "height": 300}, + 33: {"version": 2, "name": "ST‐GM29XXF 2.9\"", "width": 296, "height": 128}, + 34: {"version": 2, "name": "M2 2.7\"", "width": 264, "height": 176}, + 38: {"version": 1, "name": "M2 7.5\" BW", "width": 640, "height": 384}, + 39: {"version": 3, "name": "ST‐GM29MT1 2.9\"", "width": 296, "height": 128}, + 40: {"version": 2, "name": "M3 1.6\" BWRY", "width": 168, "height": 168}, + 41: {"version": 1, "name": "M3 2.4\" BWRY", "width": 296, "height": 168}, + 42: {"version": 1, "name": "M3 3.0\" BWRY", "width": 400, "height": 168}, + 43: {"version": 1, "name": "M3 2.9\" BWRY", "width": 384, "height": 168}, + 44: {"version": 1, "name": "M3 4.3\" BWRY", "width": 522, "height": 152}, + 45: {"version": 2, "name": "M3 12.2\"", "width": 960, "height": 768}, + 46: {"version": 5, "name": "M3 9.7\"", "width": 960, "height": 672}, + 47: {"version": 4, "name": "M3 4.3\"", "width": 522, "height": 152}, + 48: {"version": 2, "name": "M3 1.6\"", "width": 200, "height": 200}, + 49: {"version": 1, "name": "M3 2.2\"", "width": 296, "height": 160}, + 50: {"version": 1, "name": "M3 2.6\"", "width": 360, "height": 184}, + 51: {"version": 3, "name": "M3 2.9\"", "width": 384, "height": 168}, + 52: {"version": 2, "name": "M3 4.2\"", "width": 400, "height": 300}, + 53: {"version": 2, "name": "M3 6.0\"", "width": 600, "height": 448}, + 54: {"version": 5, "name": "M3 7.5\"", "width": 800, "height": 480}, + 55: {"version": 3, "name": "M3 11.6\"", "width": 960, "height": 640}, + 60: {"version": 3, "name": "M3 4.2\" BWY", "width": 400, "height": 300}, + 64: {"version": 1, "name": "M3 2.9\" BW", "width": 384, "height": 168}, + 65: {"version": 1, "name": "M3 5.85\"", "width": 792, "height": 272}, + 66: {"version": 1, "name": "M3 5.85\" BW", "width": 792, "height": 272}, + 67: {"version": 2, "name": "M3 1.3\" Peghook", "width": 144, "height": 200}, + 68: {"version": 2, "name": "M3 5.81\" BW", "width": 720, "height": 256}, + 69: {"version": 3, "name": "M3 2.2 Lite\"", "width": 250, "height": 128}, + 70: {"version": 1, "name": "M3 2.2\" BW", "width": 296, "height": 160}, + 71: {"version": 4, "name": "M3 2.7\"", "width": 300, "height": 200}, + 72: {"version": 1, "name": "M3 5.81\" BWR", "width": 720, "height": 256}, + 73: {"version": 2, "name": "M3 5.81\" V2 BWR", "width": 720, "height": 256}, + 74: {"version": 1, "name": "M3 1.6\" 200px BWRY", "width": 200, "height": 200}, + 75: {"version": 1, "name": "M3 2.2\" BWRY", "width": 296, "height": 160}, + 76: {"version": 1, "name": "M3 7.5\" BWRY", "width": 800, "height": 480}, + 77: {"version": 3, "name": "M3 11.6\" BWRY", "width": 960, "height": 640}, + 78: {"version": 2, "name": "M3 2.6\" BW", "width": 360, "height": 184}, + 80: {"version": 2, "name": "HD150 5.83\" BWR", "width": 648, "height": 480}, + 84: {"version": 4, "name": "HS BW 2.13\"", "width": 256, "height": 128}, + 85: {"version": 5, "name": "HS BWR 2.13\"", "width": 256, "height": 128}, + 86: {"version": 6, "name": "HS BWR 2.66\"", "width": 296, "height": 152}, + 87: {"version": 3, "name": "TLSR BWR 1.54\"", "width": 200, "height": 200}, + 88: {"version": 3, "name": "TLSR BW 2.13\"", "width": 256, "height": 128}, + 89: {"version": 3, "name": "TLSR BWR 2.13\"", "width": 264, "height": 136}, + 90: {"version": 1, "name": "HS BW 2.13\" LowRes", "width": 212, "height": 104}, + 96: {"version": 6, "name": "HS BWY 3.5\"", "width": 384, "height": 184}, + 97: {"version": 4, "name": "HS BWR 3.5\"", "width": 384, "height": 184}, + 98: {"version": 4, "name": "HS BW 3.5\"", "width": 384, "height": 184}, + 99: {"version": 6, "name": "TLSR BWR 4.2\"", "width": 400, "height": 300}, + 102: {"version": 2, "name": "HS BWY 7,5\"", "width": 800, "height": 480}, + 103: {"version": 3, "name": "HS 2.00\" BWY", "width": 152, "height": 200}, + 104: {"version": 4, "name": "HS BWY 3.46\"", "width": 480, "height": 176}, + 105: {"version": 4, "name": "TLSR BW 2.13\"", "width": 250, "height": 136}, + 106: {"version": 1, "name": "HS BWR 5,83\"", "width": 648, "height": 480}, + 107: {"version": 3, "name": "HS BWRY 7,5\"", "width": 800, "height": 480}, + 108: {"version": 3, "name": "HS BWRY 2,00\"", "width": 152, "height": 200}, + 109: {"version": 3, "name": "HS BWRY 3,5\"", "width": 384, "height": 184}, + 110: {"version": 3, "name": "HS BWRY 2,9\"", "width": 296, "height": 128}, + 111: {"version": 2, "name": "HS BWRY 2,60\"", "width": 296, "height": 152}, + 128: {"version": 1, "name": "Chroma 7.4\"", "width": 640, "height": 384}, + 129: {"version": 2, "name": "Chroma Aeon 74 7.4\"", "width": 800, "height": 480}, + 130: {"version": 2, "name": "Chroma29 2.9\"", "width": 296, "height": 128}, + 131: {"version": 2, "name": "Chroma42 4.2\"", "width": 400, "height": 300}, + 176: {"version": 5, "name": "Gicisky BLE EPD BW 2.13\"", "width": 250, "height": 128}, + 177: {"version": 5, "name": "Gicisky BLE EPD BWR 2.13\"", "width": 250, "height": 128}, + 178: {"version": 2, "name": "Gicisky BLE EPD BW 2.9\"", "width": 296, "height": 128}, + 179: {"version": 2, "name": "Gicisky BLE EPD BWR 2.9\"", "width": 296, "height": 128}, + 181: {"version": 2, "name": "Gicisky BLE EPD BWR 4.2\"", "width": 400, "height": 300}, + 186: {"version": 5, "name": "Gicisky BLE TFT 2.13\"", "width": 250, "height": 136}, + 189: {"version": 2, "name": "BLE EPD BWR 2.9\" Silabs", "width": 384, "height": 168}, + 190: {"version": 1, "name": "ATC MiThermometer BLE", "width": 6, "height": 8}, + 192: {"version": 2, "name": "BWRY example", "width": 360, "height": 184}, + 193: {"version": 1, "name": "ACeP 4.01", "width": 640, "height": 400}, + 194: {"version": 1, "name": "Spectra 7.3", "width": 800, "height": 480}, + 224: {"version": 2, "name": "TFT 320x172", "width": 320, "height": 172}, + 225: {"version": 2, "name": "TFT 160x80", "width": 160, "height": 80}, + 226: {"version": 1, "name": "LILYGO TPANEL 4\"", "width": 480, "height": 480}, + 227: {"version": 1, "name": "GDEM1085Z51 10.85\"", "width": 1360, "height": 480}, + 228: {"version": 1, "name": "BLE TFT 128x128", "width": 128, "height": 128}, + 229: {"version": 1, "name": "TFT 240x320", "width": 320, "height": 172}, + 240: {"version": 2, "name": "SLT‐EM007 Segmented", "width": 0, "height": 0}, + 250: {"version": 1, "name": "ConfigMode", "width": 0, "height": 0}, } self._tag_types = { type_id: TagType(type_id, data) for type_id, data in fallback_definitions.items() From e793090ac900f4f82fb3895407daf0a86d86ea38 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:46:42 +0000 Subject: [PATCH 5/5] Add workflow to sync tag type definitions weekly from OpenEPaperLink Co-authored-by: Misiu <1741838+Misiu@users.noreply.github.com> --- .github/workflows/sync-tag-definitions.yml | 233 +++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 .github/workflows/sync-tag-definitions.yml diff --git a/.github/workflows/sync-tag-definitions.yml b/.github/workflows/sync-tag-definitions.yml new file mode 100644 index 0000000..d48fef3 --- /dev/null +++ b/.github/workflows/sync-tag-definitions.yml @@ -0,0 +1,233 @@ +name: Sync Tag Type Definitions + +on: + # Run weekly on Monday at 00:00 UTC + schedule: + - cron: '0 0 * * 1' + + # Allow manual trigger + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + sync-tag-definitions: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Fetch tag type definitions from OpenEPaperLink + id: fetch + run: | + python3 << 'PYEOF' + import urllib.request + import json + import re + + print("Fetching tag type files from OpenEPaperLink repository...") + + # Fetch the directory listing + url = "https://github.com/OpenEPaperLink/OpenEPaperLink/tree/master/resources/tagtypes" + headers = {'User-Agent': 'Mozilla/5.0'} + req = urllib.request.Request(url, headers=headers) + + try: + with urllib.request.urlopen(req, timeout=30) as response: + html = response.read().decode('utf-8') + json_files = re.findall(r'([0-9a-fA-F]+\.json)', html) + json_files = sorted(set(json_files)) + print(f"Found {len(json_files)} tag type files") + except Exception as e: + print(f"Error fetching file list: {e}") + exit(1) + + # Fetch all tag type definitions + tag_types = {} + errors = [] + + for filename in json_files: + url = f"https://raw.githubusercontent.com/OpenEPaperLink/OpenEPaperLink/master/resources/tagtypes/{filename}" + try: + with urllib.request.urlopen(url, timeout=10) as response: + data = json.loads(response.read().decode('utf-8')) + type_id = int(filename.replace('.json', ''), 16) + + # Extract only required fields + tag_types[type_id] = { + 'version': data.get('version'), + 'name': data.get('name'), + 'width': data.get('width'), + 'height': data.get('height'), + } + except Exception as e: + errors.append(f"Error fetching {filename}: {e}") + + if errors: + for error in errors: + print(error) + + print(f"Successfully fetched {len(tag_types)} tag type definitions") + + # Save to file for next step + with open('new_tag_types.json', 'w') as f: + json.dump(tag_types, f, indent=2) + + print("Tag types saved to new_tag_types.json") + PYEOF + + - name: Generate updated tag_types.py + id: generate + run: | + python3 << 'PYEOF' + import json + import re + + # Load new tag types + with open('new_tag_types.json', 'r') as f: + new_tag_types = json.load(f) + + # Read current tag_types.py + with open('custom_components/opendisplay/tag_types.py', 'r') as f: + content = f.read() + + # Extract current fallback definitions + match = re.search(r'fallback_definitions = \{(.*?)\n \}', content, re.DOTALL) + if not match: + print("Error: Could not find fallback_definitions in tag_types.py") + exit(1) + + current_definitions = match.group(1) + + # Parse current definitions to dict + current_types = {} + for line in current_definitions.split('\n'): + match = re.match(r'\s+(\d+):', line) + if match: + type_id = int(match.group(1)) + current_types[type_id] = line.strip() + + print(f"Current definitions: {len(current_types)} types") + print(f"New definitions: {len(new_tag_types)} types") + + # Check if there are differences + changed = False + added = [] + removed = [] + modified = [] + + # Find added and modified + for type_id in sorted(new_tag_types.keys()): + if type_id not in current_types: + added.append(type_id) + changed = True + else: + # Compare values + new_line = f'{type_id}: {json.dumps(new_tag_types[str(type_id)])}' + if new_line not in current_types[type_id]: + modified.append(type_id) + changed = True + + # Find removed + for type_id in current_types: + if str(type_id) not in new_tag_types and type_id not in [int(k) for k in new_tag_types.keys()]: + removed.append(type_id) + changed = True + + # Generate new fallback_definitions content + lines = [] + for type_id in sorted([int(k) for k in new_tag_types.keys()]): + type_data = new_tag_types[str(type_id)] + line = f' {type_id}: {json.dumps(type_data)},' + lines.append(line) + + new_fallback = '\n'.join(lines) + + # Replace in content + new_content = re.sub( + r'(fallback_definitions = \{)\n.*?\n( \})', + r'\1\n' + new_fallback + '\n\2', + content, + flags=re.DOTALL + ) + + # Write updated file + with open('custom_components/opendisplay/tag_types.py', 'w') as f: + f.write(new_content) + + # Create summary + summary = [] + if added: + summary.append(f"Added: {len(added)} types ({', '.join(map(str, added[:5]))}{'...' if len(added) > 5 else ''})") + if removed: + summary.append(f"Removed: {len(removed)} types ({', '.join(map(str, removed[:5]))}{'...' if len(removed) > 5 else ''})") + if modified: + summary.append(f"Modified: {len(modified)} types ({', '.join(map(str, modified[:5]))}{'...' if len(modified) > 5 else ''})") + + if changed: + print("CHANGED=true") + print(f"SUMMARY={'|'.join(summary)}") + with open('CHANGES_SUMMARY.txt', 'w') as f: + f.write('\n'.join(summary)) + else: + print("CHANGED=false") + print("No changes detected") + + # Set output for GitHub Actions + import os + with open(os.environ['GITHUB_OUTPUT'], 'a') as f: + f.write(f"changed={'true' if changed else 'false'}\n") + if summary: + f.write(f"summary={'|'.join(summary)}\n") + PYEOF + + - name: Create Pull Request + if: steps.generate.outputs.changed == 'true' + uses: peter-evans/create-pull-request@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: 'Update tag type definitions from OpenEPaperLink' + title: 'chore: Update tag type definitions from OpenEPaperLink' + body: | + This PR automatically updates the fallback tag type definitions to match the latest definitions from the OpenEPaperLink repository. + + ## Changes + + ${{ steps.generate.outputs.summary }} + + ## Source + + Definitions fetched from: https://github.com/OpenEPaperLink/OpenEPaperLink/tree/master/resources/tagtypes + + ## Notes + + - Only required fields are included: `version`, `name`, `width`, `height` + - Optional fields (`bpp`, `rotatebuffer`) use defaults from TagType class + + --- + + *This PR was automatically created by the sync-tag-definitions workflow* + branch: 'automated/sync-tag-definitions' + delete-branch: true + labels: | + automated + dependencies + + - name: Summary + run: | + if [ "${{ steps.generate.outputs.changed }}" == "true" ]; then + echo "✅ Changes detected - PR created" + echo "${{ steps.generate.outputs.summary }}" + else + echo "✅ No changes detected - definitions are up to date" + fi