# Generated by Django 5.2.8 on 2026-02-19 00:42 import django.db.models.deletion import django.utils.timezone from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [] operations = [ migrations.CreateModel( name="Printer", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "name", models.CharField(help_text="Friendly device name", max_length=200), ), ( "model", models.CharField( help_text="Device model (e.g., X1C, P1S)", max_length=100 ), ), ( "manufacturer", models.CharField( default="Bambu Lab", help_text="e.g., Bambu Lab", max_length=100 ), ), ("description", models.TextField(blank=True, null=True)), ( "serial_number", models.CharField( blank=True, max_length=100, null=True, unique=True ), ), ("ip_address", models.GenericIPAddressField(blank=True, null=True)), ("is_active", models.BooleanField(default=True)), ( "location", models.CharField( blank=True, help_text="Physical location", max_length=200 ), ), ("first_seen", models.DateTimeField(auto_now_add=True)), ("last_updated", models.DateTimeField(auto_now=True)), ], options={ "verbose_name": "Printer", "verbose_name_plural": "Printers", "db_table": "infrastructure_device", "ordering": ["name"], }, ), migrations.CreateModel( name="FilamentType", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "type", models.CharField( help_text="Base material: PLA, PETG, ABS, etc.", max_length=50 ), ), ( "sub_type", models.CharField( blank=True, help_text="Sub-type: PLA Basic, PLA Matte, etc.", max_length=100, null=True, ), ), ( "brand", models.CharField( default="Bambu Lab", help_text="Manufacturer name", max_length=100, ), ), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ], options={ "verbose_name": "Filament Type", "verbose_name_plural": "Filament Types", "db_table": "infrastructure_filament_type", "ordering": ["type", "sub_type", "brand"], "unique_together": {("type", "sub_type", "brand")}, }, ), migrations.CreateModel( name="Filament", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "tray_uuid", models.CharField( blank=True, db_index=True, help_text="Spool serial number from MQTT", max_length=100, null=True, unique=True, ), ), ( "tag_uid", models.CharField( blank=True, db_index=True, help_text="RFID chip unique identifier", max_length=100, null=True, ), ), ( "tag_id", models.CharField( blank=True, help_text="User-defined unique identifier (barcode, label, etc.)", max_length=100, null=True, ), ), ( "created_by", models.CharField( choices=[ ("Auto Detection", "Auto Detection"), ("Manual", "Manual"), ], default="Manual", help_text="How this filament was added to inventory", max_length=20, ), ), ( "type", models.CharField( help_text="PLA, PETG, ABS, TPU, etc.", max_length=50 ), ), ( "sub_type", models.CharField( blank=True, help_text="Material sub-type from MQTT: 'PLA Matte', 'PLA Basic', etc.", max_length=100, null=True, ), ), ( "brand", models.CharField(help_text="Manufacturer name", max_length=100), ), ("color", models.CharField(help_text="Color name", max_length=50)), ( "color_hex", models.CharField( blank=True, help_text="Color hex code for display (#RRGGBB)", max_length=7, null=True, ), ), ( "diameter", models.DecimalField( decimal_places=2, default=1.75, help_text="Filament diameter in mm (1.75 or 2.85)", max_digits=4, ), ), ( "initial_weight_grams", models.IntegerField( blank=True, help_text="Spool weight when new (typically 1000g)", null=True, ), ), ( "remaining_percent", models.IntegerField( default=100, help_text="Estimated remaining filament (0-100%)" ), ), ( "remaining_weight_grams", models.IntegerField( blank=True, help_text="Calculated remaining weight", null=True ), ), ( "is_loaded_in_ams", models.BooleanField( default=False, help_text="Is this spool currently loaded in AMS?", ), ), ( "current_tray_id", models.IntegerField( blank=True, help_text="Which AMS slot (0-3) if loaded", null=True, ), ), ( "last_loaded_date", models.DateTimeField( blank=True, help_text="When was this spool loaded into AMS", null=True, ), ), ("purchase_date", models.DateField(blank=True, null=True)), ( "purchase_price", models.DecimalField( blank=True, decimal_places=2, max_digits=8, null=True ), ), ("supplier", models.CharField(blank=True, max_length=100, null=True)), ( "notes", models.TextField( blank=True, help_text="Custom notes about this spool" ), ), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ( "last_used", models.DateTimeField( blank=True, help_text="Last time this spool was used in a print", null=True, ), ), ( "filament_type", models.ForeignKey( blank=True, help_text="Link to FilamentType registry", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="filaments", to="bambu_run.filamenttype", ), ), ], options={ "verbose_name": "Filament Spool", "verbose_name_plural": "Filament Spools", "db_table": "infrastructure_filament", "ordering": ["type", "brand", "color", "-remaining_percent"], }, ), migrations.CreateModel( name="PrinterMetrics", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "timestamp", models.DateTimeField( db_index=True, default=django.utils.timezone.now, help_text="When this reading was taken", ), ), ( "nozzle_temp", models.DecimalField( blank=True, decimal_places=2, max_digits=5, null=True ), ), ( "nozzle_target_temp", models.DecimalField( blank=True, decimal_places=2, max_digits=5, null=True ), ), ( "bed_temp", models.DecimalField( blank=True, decimal_places=2, max_digits=5, null=True ), ), ( "bed_target_temp", models.DecimalField( blank=True, decimal_places=2, max_digits=5, null=True ), ), ( "chamber_temp", models.DecimalField( blank=True, decimal_places=2, max_digits=5, null=True ), ), ( "nozzle_diameter", models.DecimalField( blank=True, decimal_places=2, max_digits=3, null=True ), ), ("nozzle_type", models.CharField(blank=True, max_length=50, null=True)), ( "gcode_state", models.CharField( blank=True, help_text="FINISH, RUNNING, IDLE, etc.", max_length=50, null=True, ), ), ( "print_type", models.CharField( blank=True, help_text="idle, printing, etc.", max_length=50, null=True, ), ), ( "print_percent", models.IntegerField( blank=True, help_text="Print progress percentage", null=True ), ), ( "remaining_time_min", models.IntegerField( blank=True, help_text="Estimated remaining time in minutes", null=True, ), ), ( "layer_num", models.IntegerField( blank=True, help_text="Current layer number", null=True ), ), ( "total_layer_num", models.IntegerField( blank=True, help_text="Total layers in print", null=True ), ), ("print_line_number", models.IntegerField(blank=True, null=True)), ( "subtask_name", models.CharField(blank=True, max_length=200, null=True), ), ("gcode_file", models.CharField(blank=True, max_length=200, null=True)), ("cooling_fan_speed", models.IntegerField(blank=True, null=True)), ("heatbreak_fan_speed", models.IntegerField(blank=True, null=True)), ( "big_fan1_speed", models.IntegerField( blank=True, help_text="Auxiliary/chamber fan 1 speed", null=True ), ), ( "big_fan2_speed", models.IntegerField( blank=True, help_text="Auxiliary/chamber fan 2 speed", null=True ), ), ( "spd_lvl", models.IntegerField( blank=True, help_text="Speed level (1=silent, 2=standard, 3=sport, 4=ludicrous)", null=True, ), ), ( "spd_mag", models.IntegerField( blank=True, help_text="Speed magnitude percentage", null=True ), ), ("wifi_signal_dbm", models.IntegerField(blank=True, null=True)), ("print_error", models.IntegerField(default=0)), ("has_errors", models.BooleanField(default=False)), ( "chamber_light", models.CharField( blank=True, help_text="on/off", max_length=20, null=True ), ), ( "ipcam_record", models.CharField( blank=True, help_text="enable/disable", max_length=20, null=True ), ), ( "timelapse", models.CharField( blank=True, help_text="enable/disable", max_length=20, null=True ), ), ( "stg_cur", models.IntegerField( blank=True, help_text="Current print stage", null=True ), ), ( "sdcard", models.BooleanField( blank=True, help_text="SD card present", null=True ), ), ( "gcode_file_prepare_percent", models.CharField( blank=True, help_text="File preparation progress", max_length=10, null=True, ), ), ( "lifecycle", models.CharField( blank=True, help_text="Product lifecycle state", max_length=50, null=True, ), ), ( "hms", models.JSONField( default=list, help_text="Health management system messages (errors/warnings)", ), ), ("ams_unit_count", models.IntegerField(blank=True, null=True)), ("ams_status", models.IntegerField(blank=True, null=True)), ("ams_rfid_status", models.IntegerField(blank=True, null=True)), ( "ams_humidity", models.IntegerField( blank=True, help_text="AMS humidity level (processed)", null=True, ), ), ( "ams_humidity_raw", models.IntegerField( blank=True, help_text="AMS raw humidity reading", null=True ), ), ( "ams_temp", models.DecimalField( blank=True, decimal_places=2, max_digits=5, null=True ), ), ( "ams_version", models.IntegerField( blank=True, help_text="AMS firmware version", null=True ), ), ( "tray_is_bbl_bits", models.CharField( blank=True, help_text="Which trays have Bambu Lab (OEM) filament", max_length=20, null=True, ), ), ( "tray_read_done_bits", models.CharField( blank=True, help_text="RFID read completion status bits", max_length=20, null=True, ), ), ( "filaments", models.JSONField( default=list, help_text="List of filament info [{tray_id, slot, type, sub_type, color, remain_percent, k, ...}]", ), ), ( "ams_units", models.JSONField( default=list, help_text="AMS unit info [{unit_id, ams_id, chip_id, humidity, temp, ...}]", ), ), ( "external_spool", models.JSONField( default=dict, help_text="External spool info {type, color, remain}", ), ), ( "lights_report", models.JSONField( default=list, help_text="Light status report [{node, mode}]" ), ), ( "device", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="printer_metrics", to="bambu_run.printer", ), ), ], options={ "verbose_name": "Printer Metric", "verbose_name_plural": "Printer Metrics", "db_table": "infrastructure_printer_metrics", "ordering": ["-timestamp"], }, ), migrations.CreateModel( name="FilamentSnapshot", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("tray_id", models.IntegerField(help_text="AMS slot number (0-3)")), ( "slot_name", models.CharField( blank=True, help_text="Slot identifier like A00-W1", max_length=20, null=True, ), ), ("type", models.CharField(blank=True, max_length=50, null=True)), ( "sub_type", models.CharField( blank=True, help_text="Material sub-type from MQTT (PLA Basic, PLA Matte, etc.)", max_length=100, null=True, ), ), ( "brand", models.CharField( blank=True, help_text="Deprecated: MQTT doesn't provide brand. Use Filament.brand instead.", max_length=100, null=True, ), ), ("color", models.CharField(blank=True, max_length=50, null=True)), ("remain_percent", models.IntegerField(blank=True, null=True)), ( "k_value", models.DecimalField( blank=True, decimal_places=4, max_digits=6, null=True ), ), ( "tag_uid", models.CharField( blank=True, db_index=True, help_text="RFID chip unique identifier", max_length=100, null=True, ), ), ( "tray_uuid", models.CharField( blank=True, help_text="Tray UUID from MQTT", max_length=100, null=True, ), ), ( "state", models.IntegerField( blank=True, help_text="Tray state from MQTT", null=True ), ), ( "temp", models.DecimalField( blank=True, decimal_places=2, max_digits=5, null=True ), ), ("humidity", models.IntegerField(blank=True, null=True)), ( "auto_matched", models.BooleanField( default=True, help_text="Was this auto-matched to inventory or manually set?", ), ), ( "match_method", models.CharField( default="none", help_text="tag_id, lowest_remaining, manual, or none", max_length=20, ), ), ( "filament", models.ForeignKey( blank=True, help_text="Matched filament from inventory (null if no match)", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="usage_snapshots", to="bambu_run.filament", ), ), ( "printer_metric", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="filament_snapshots", to="bambu_run.printermetrics", ), ), ], options={ "verbose_name": "Filament Snapshot", "verbose_name_plural": "Filament Snapshots", "db_table": "infrastructure_filament_snapshot", "ordering": ["printer_metric", "tray_id"], }, ), migrations.CreateModel( name="PrintJob", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "project_name", models.CharField( help_text="From subtask_name field", max_length=200 ), ), ("gcode_file", models.CharField(blank=True, max_length=200, null=True)), ("start_time", models.DateTimeField(help_text="When print started")), ( "end_time", models.DateTimeField( blank=True, help_text="When print finished/failed", null=True ), ), ( "duration_minutes", models.IntegerField( blank=True, help_text="Total print duration", null=True ), ), ("total_layers", models.IntegerField(blank=True, null=True)), ( "final_status", models.CharField( blank=True, help_text="FINISH, FAILED, CANCELLED", max_length=50, null=True, ), ), ( "completion_percent", models.IntegerField( default=0, help_text="Final completion percentage" ), ), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ( "device", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="print_jobs", to="bambu_run.printer", ), ), ( "end_metric", models.ForeignKey( null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="ended_jobs", to="bambu_run.printermetrics", ), ), ( "start_metric", models.ForeignKey( null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="started_jobs", to="bambu_run.printermetrics", ), ), ], options={ "verbose_name": "Print Job", "verbose_name_plural": "Print Jobs", "db_table": "infrastructure_print_job", "ordering": ["-start_time"], }, ), migrations.CreateModel( name="FilamentUsage", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("tray_id", models.IntegerField(help_text="Which AMS slot was used")), ( "starting_percent", models.IntegerField(help_text="Filament remaining % at job start"), ), ( "ending_percent", models.IntegerField( blank=True, help_text="Filament remaining % at job end", null=True, ), ), ( "consumed_percent", models.IntegerField( blank=True, help_text="Amount consumed during print", null=True ), ), ( "consumed_grams", models.IntegerField( blank=True, help_text="Estimated grams consumed", null=True ), ), ( "is_primary", models.BooleanField( default=True, help_text="Primary filament vs multi-color" ), ), ( "filament", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="print_usages", to="bambu_run.filament", ), ), ( "print_job", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="filament_usages", to="bambu_run.printjob", ), ), ], options={ "verbose_name": "Filament Usage", "verbose_name_plural": "Filament Usages", "db_table": "infrastructure_filament_usage", "ordering": ["print_job", "tray_id"], }, ), migrations.CreateModel( name="FilamentColor", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "color_code", models.CharField( help_text="Hex color code without padding (e.g., '000000' not '000000FF')", max_length=6, ), ), ( "color_name", models.CharField( help_text="Human-readable color name (e.g., 'Black', 'Orange')", max_length=100, ), ), ( "filament_type", models.CharField( help_text="Base material type: PLA, PETG, ABS, TPU, etc.", max_length=50, ), ), ( "filament_sub_type", models.CharField( blank=True, help_text="Material sub-type: 'PLA Basic', 'PLA Matte', 'ABS GF', etc.", max_length=100, null=True, ), ), ( "brand", models.CharField( default="Bambu Lab", help_text="Manufacturer name", max_length=100, ), ), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ( "filament_type_fk", models.ForeignKey( blank=True, help_text="Link to FilamentType registry", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="colors", to="bambu_run.filamenttype", ), ), ], options={ "verbose_name": "Filament Color", "verbose_name_plural": "Filament Colors", "db_table": "infrastructure_filament_color", "ordering": ["filament_type", "filament_sub_type", "color_name"], "indexes": [ models.Index( fields=[ "color_code", "filament_type", "filament_sub_type", "brand", ], name="infrastruct_color_c_de04ed_idx", ), models.Index( fields=["filament_type"], name="infrastruct_filamen_0465c7_idx" ), ], "unique_together": { ("color_code", "filament_type", "filament_sub_type", "brand") }, }, ), migrations.AddIndex( model_name="filament", index=models.Index( fields=["type", "brand", "color"], name="infrastruct_type_42e074_idx" ), ), migrations.AddIndex( model_name="filament", index=models.Index( fields=["tray_uuid"], name="infrastruct_tray_uu_578cd9_idx" ), ), migrations.AddIndex( model_name="filament", index=models.Index( fields=["tag_uid"], name="infrastruct_tag_uid_4c70bd_idx" ), ), migrations.AddIndex( model_name="filament", index=models.Index(fields=["tag_id"], name="infrastruct_tag_id_d422f5_idx"), ), migrations.AddIndex( model_name="filament", index=models.Index( fields=["is_loaded_in_ams", "current_tray_id"], name="infrastruct_is_load_2a6d6a_idx", ), ), migrations.AddIndex( model_name="filament", index=models.Index( fields=["remaining_percent"], name="infrastruct_remaini_5a2b06_idx" ), ), migrations.AddIndex( model_name="filament", index=models.Index( fields=["created_by"], name="infrastruct_created_be984e_idx" ), ), migrations.AddIndex( model_name="printermetrics", index=models.Index( fields=["device", "-timestamp"], name="printer_dev_time_idx" ), ), migrations.AddIndex( model_name="printermetrics", index=models.Index(fields=["-timestamp"], name="printer_time_idx"), ), migrations.AddIndex( model_name="filamentsnapshot", index=models.Index( fields=["printer_metric", "tray_id"], name="infrastruct_printer_e9159d_idx", ), ), migrations.AddIndex( model_name="filamentsnapshot", index=models.Index( fields=["filament"], name="infrastruct_filamen_7fb827_idx" ), ), migrations.AddIndex( model_name="printjob", index=models.Index( fields=["device", "-start_time"], name="infrastruct_device__d4514f_idx" ), ), migrations.AddIndex( model_name="printjob", index=models.Index( fields=["project_name"], name="infrastruct_project_7aa127_idx" ), ), migrations.AddIndex( model_name="printjob", index=models.Index( fields=["-start_time"], name="infrastruct_start_t_a87ee3_idx" ), ), migrations.AddIndex( model_name="filamentusage", index=models.Index( fields=["print_job"], name="infrastruct_print_j_aaee76_idx" ), ), migrations.AddIndex( model_name="filamentusage", index=models.Index( fields=["filament"], name="infrastruct_filamen_2377d2_idx" ), ), ]