Guest User

extract_device_data.py

a guest
Jun 30th, 2025
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.87 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. """
  3. Garmin ConnectIQ Device Data Extractor
  4.  
  5. This utility extracts information from Garmin ConnectIQ device definitions
  6. and outputs it in a tabular format.
  7. """
  8.  
  9. import json
  10. import os
  11. import sys
  12. from pathlib import Path
  13. from typing import Dict, List, Optional, Any
  14. import argparse
  15.  
  16.  
  17. def extract_compiler_data(compiler_data: Dict[str, Any]) -> Dict[str, Any]:
  18.     """Extract relevant data from compiler.json"""
  19.     return {
  20.         'device_id': compiler_data.get('deviceId', ''),
  21.         'display_name': compiler_data.get('displayName', ''),
  22.         'display_type': compiler_data.get('displayType', ''),
  23.         'complication_icon_width': compiler_data.get('complicationIcon', {}).get('width', ''),
  24.         'complication_icon_height': compiler_data.get('complicationIcon', {}).get('height', ''),
  25.         'alpha_blending_support': compiler_data.get('alphaBlendingSupport', ''),
  26.         'enhanced_graphic_support': compiler_data.get('enhancedGraphicSupport', ''),
  27.         'screen_rotation_support': compiler_data.get('screenRotationSupport', ''),
  28.     }
  29.  
  30.  
  31. def extract_simulator_data(simulator_data: Dict[str, Any]) -> Dict[str, Any]:
  32.     """Extract relevant data from simulator.json"""
  33.     display_info = simulator_data.get('display', {})
  34.     menu2_info = simulator_data.get('layouts', [{}])[0].get('menu2', {}) if simulator_data.get('layouts') else {}
  35.     glance_info = simulator_data.get('glance', {})
  36.    
  37.     # Extract menu2 icon dimensions
  38.     menu2_icons = menu2_info.get('items', {}).get('icons', {})
  39.     menu2_left_location = menu2_icons.get('leftLocation', {})
  40.     menu2_right_location = menu2_icons.get('rightLocation', {})
  41.    
  42.     return {
  43.         'menu2_mode': menu2_info.get('mode', ''),
  44.         'menu2_title_height': menu2_info.get('title', {}).get('height', ''),
  45.         'menu2_title_width': menu2_info.get('title', {}).get('width', ''),
  46.         'menu2_icon_width': menu2_left_location.get('width', menu2_right_location.get('width', '')),
  47.         'menu2_icon_height': menu2_left_location.get('height', menu2_right_location.get('height', '')),
  48.         'glance_icon_width': glance_info.get('iconArea', {}).get('width', ''),
  49.         'glance_icon_height': glance_info.get('iconArea', {}).get('height', ''),
  50.         'glance_content_width': glance_info.get('contentArea', {}).get('width', ''),
  51.         'glance_content_height': glance_info.get('contentArea', {}).get('height', ''),
  52.         'app_storage_capacity': simulator_data.get('appStorageCapacity', ''),
  53.         'graphics_resource_pool_size': simulator_data.get('graphicsResourcePoolSize', ''),
  54.         'watchdog_count': simulator_data.get('watchdogCount', ''),
  55.     }
  56.  
  57.  
  58. def process_device_directory(device_dir: Path) -> Optional[Dict[str, Any]]:
  59.     """Process a single device directory and extract data"""
  60.     compiler_json = device_dir / 'compiler.json'
  61.     simulator_json = device_dir / 'simulator.json'
  62.    
  63.     if not compiler_json.exists() or not simulator_json.exists():
  64.         return None
  65.    
  66.     try:
  67.         with open(compiler_json, 'r') as f:
  68.             compiler_data = json.load(f)
  69.        
  70.         with open(simulator_json, 'r') as f:
  71.             simulator_data = json.load(f)
  72.        
  73.         device_info = {
  74.             **extract_compiler_data(compiler_data),
  75.             **extract_simulator_data(simulator_data)
  76.         }
  77.        
  78.         return device_info
  79.        
  80.     except (json.JSONDecodeError, FileNotFoundError, KeyError) as e:
  81.         print(f"Error processing {device_dir.name}: {e}", file=sys.stderr)
  82.         return None
  83.  
  84.  
  85. def format_table_output(devices: List[Dict[str, Any]], output_format: str = 'table') -> str:
  86.     """Format the device data as a table"""
  87.     if not devices:
  88.         return "No devices found."
  89.    
  90.     if output_format == 'csv':
  91.         import csv
  92.         import io
  93.        
  94.         output = io.StringIO()
  95.         writer = csv.DictWriter(output, fieldnames=devices[0].keys())
  96.         writer.writeheader()
  97.         writer.writerows(devices)
  98.         return output.getvalue()
  99.    
  100.     elif output_format == 'json':
  101.         return json.dumps(devices, indent=2)
  102.    
  103.     else:  # table format
  104.         # Get column headers
  105.         headers = list(devices[0].keys())
  106.        
  107.         # Calculate column widths
  108.         col_widths = {}
  109.         for header in headers:
  110.             col_widths[header] = max(
  111.                 len(header),
  112.                 max(len(str(device.get(header, ''))) for device in devices)
  113.             )
  114.        
  115.         # Create separator line
  116.         separator = '+' + '+'.join('-' * (col_widths[h] + 2) for h in headers) + '+'
  117.        
  118.         # Format header row
  119.         header_row = '|' + '|'.join(f" {h:<{col_widths[h]}} " for h in headers) + '|'
  120.        
  121.         # Format data rows
  122.         data_rows = []
  123.         for device in devices:
  124.             row = '|' + '|'.join(f" {str(device.get(h, '')):<{col_widths[h]}} " for h in headers) + '|'
  125.             data_rows.append(row)
  126.        
  127.         # Combine all parts
  128.         return '\n'.join([separator, header_row, separator] + data_rows + [separator])
  129.  
  130.  
  131. def main():
  132.     parser = argparse.ArgumentParser(description='Extract Garmin ConnectIQ device data')
  133.     parser.add_argument('devices_dir',
  134.                        help='Path to Garmin ConnectIQ Devices directory',
  135.                        default='.',
  136.                        nargs='?')
  137.     parser.add_argument('--format', '-f',
  138.                        choices=['table', 'csv', 'json'],
  139.                        default='table',
  140.                        help='Output format (default: table)')
  141.     parser.add_argument('--filter', '-F',
  142.                        help='Filter devices by name pattern (case-insensitive)')
  143.     parser.add_argument('--output', '-o',
  144.                        help='Output file (default: stdout)')
  145.    
  146.     args = parser.parse_args()
  147.    
  148.     devices_dir = Path(args.devices_dir)
  149.     if not devices_dir.exists():
  150.         print(f"Error: Directory {devices_dir} does not exist", file=sys.stderr)
  151.         sys.exit(1)
  152.    
  153.     devices = []
  154.    
  155.     # Process each device directory
  156.     for device_dir in sorted(devices_dir.iterdir()):
  157.         if device_dir.is_dir():
  158.             # Apply filter if specified
  159.             if args.filter and args.filter.lower() not in device_dir.name.lower():
  160.                 continue
  161.                
  162.             device_info = process_device_directory(device_dir)
  163.             if device_info:
  164.                 devices.append(device_info)
  165.    
  166.     if not devices:
  167.         print("No valid device directories found.", file=sys.stderr)
  168.         sys.exit(1)
  169.    
  170.     # Format and output the results
  171.     output = format_table_output(devices, args.format)
  172.    
  173.     if args.output:
  174.         with open(args.output, 'w') as f:
  175.             f.write(output)
  176.         print(f"Output written to {args.output}")
  177.     else:
  178.         print(output)
  179.  
  180.  
  181. if __name__ == '__main__':
  182.     main()
  183.  
Advertisement
Add Comment
Please, Sign In to add comment