Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c08e18ef9 |
@@ -17,42 +17,27 @@
|
||||
## Installation
|
||||
|
||||
### Official Installation
|
||||
Open the "Plugin and Content Manager" from the KiCad main menu and install the "<ins>Fabrication Toolkit</ins>" plugin from the selection list.
|
||||
Open the "Plugin and Content Manager" from the KiCad main menu an install the "<ins>Fabrication Toolkit</ins>" plugin from the selection list.
|
||||
|
||||
### Manual installation
|
||||
Download the latest ZIP file from https://github.com/bennymeg/JLC-Plugin-for-KiCad. Open the "Plugin and Content Manager" from the KiCads main window and install the ZIP file via "Install from File".
|
||||
|
||||
## Usage
|
||||
Click on the Fabrication Toolkit <img src="https://github.com/bennymeg/JLC-Plugin-for-KiCad/blob/master/resources/icon.png?raw=true" style="magin-bottom: 8px;" alt="Logo" height=24> button on the top tool box inside KiCad pcb editor (pcbnew).
|
||||
|
||||
## Options
|
||||
|
||||
### Include Component Part Number in Production Files
|
||||
Add an 'LCSC Part #'* field with the LCSC component part number to the symbol's fields property.
|
||||
Add an 'MPN'* field with the LCSC component part number to the symbol's fields property.
|
||||
|
||||
<img src="https://github.com/bennymeg/JLC-Plugin-for-KiCad/blob/master/assets/mpn.png?raw=true" height=420>
|
||||
|
||||
#### Primary Fields*:
|
||||
| 'LCSC Part #' | 'JLCPCB Part #' |
|
||||
| --- | --- |
|
||||
|
||||
_The fields will be query in the order denoted above._
|
||||
|
||||
#### Fallback Fields*:
|
||||
| 'LCSC' | 'JLC' | 'MPN' | 'Mpn' | 'mpn' |
|
||||
| --- | --- | --- | --- | --- |
|
||||
|
||||
_The fields will be query in the order denoted above._
|
||||
#### Similar Fields*:
|
||||
|'mpn' | 'Mpn' | 'MPN' | 'JLC_MPN' | 'LCSC_MPN' | 'LCSC Part #' | 'JLC' | 'LCSC'|
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
|
||||
### Ignore Footprint in Production Files
|
||||
Select 'Exclude from board' or 'Exclude from BOM' in the symbol's attributes property in order to ignore the footprint from the relevant file.
|
||||
Select 'Exclude from position files' or 'Exclude from BOM' in the symbol's attributes property in order to ignore the footprint from the relevant file.
|
||||
|
||||
<img src="https://github.com/bennymeg/JLC-Plugin-for-KiCad/blob/master/assets/attributes.png?raw=true" height=420>
|
||||
|
||||
Select 'Exclude from position files' or 'Exclude from BOM' in the footprint's fabrication attributes property in order to ignore the footprint from the relevant file.
|
||||
|
||||
<img src="https://github.com/bennymeg/JLC-Plugin-for-KiCad/blob/master/assets/fabrication.png?raw=true" height=505>
|
||||
|
||||
## Author
|
||||
|
||||
Benny Megidish
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 114 KiB |
+3
-3
@@ -2,7 +2,7 @@
|
||||
"$schema": "https://go.kicad.org/pcm/schemas/v1",
|
||||
"name": "Fabrication Toolkit",
|
||||
"description": "JLC PCB fabrication toolkit",
|
||||
"description_full": "Toolkit for automating PCB fabrication process with KiCad and JLC PCB. \n\n OPTIONS: \n\u2022 Include Component Part Number in Production Files \n Add an 'MPN' field with the LCSC component part number to the footprint component options. \n\n\u2022 Ignore Footprint in Production Files \n Select 'Exclude from position files' or 'Exclude from BOM' in the footprint properties fabrication attributes in order to ignore the footprint from the relevant file.",
|
||||
"description_full": "Toolkit for automating PCB fabrication process with KiCad and JLC PCB. \n\n OPTIONS: \n\u2022 Include Component Part Number in Production Files \n Add an 'MPN' field with the LCSC component part number to the footprint component options. \n\n\u2022 Ignore Footprint in Production Files \n Select 'Exclude from position files' or 'Exclude from BOM' in the footprint component options to in order ignore the footprint from the relevant file.",
|
||||
"identifier": "com.github.bennymeg.JLC-Plugin-for-KiCad",
|
||||
"type": "plugin",
|
||||
"author": {
|
||||
@@ -29,8 +29,8 @@
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"version": "1.2.0",
|
||||
"status": "stable",
|
||||
"version": "0.4.2",
|
||||
"status": "testing",
|
||||
"kicad_version": "6.00"
|
||||
}
|
||||
]
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ class KiCadToJLCForm(wx.Frame):
|
||||
pcbnew.Refresh()
|
||||
self.Destroy()
|
||||
else:
|
||||
self.m_gaugeStatus.SetValue(int(status.data))
|
||||
self.m_gaugeStatus.SetValue(status.data)
|
||||
|
||||
|
||||
# Plugin definition
|
||||
|
||||
+38
-36
@@ -1,3 +1,5 @@
|
||||
import json
|
||||
import requests
|
||||
import os
|
||||
import csv
|
||||
import shutil
|
||||
@@ -27,13 +29,11 @@ class ProcessManager:
|
||||
plot_options.SetScale(1)
|
||||
plot_options.SetMirror(False)
|
||||
plot_options.SetUseGerberAttributes(True)
|
||||
plot_options.SetExcludeEdgeLayer(True)
|
||||
plot_options.SetUseGerberProtelExtensions(False)
|
||||
plot_options.SetUseAuxOrigin(True)
|
||||
plot_options.SetSubtractMaskFromSilk(False)
|
||||
plot_options.SetDrillMarksType(0) # NO_DRILL_SHAPE
|
||||
|
||||
if hasattr(plot_options, "SetExcludeEdgeLayer"):
|
||||
plot_options.SetExcludeEdgeLayer(True)
|
||||
|
||||
for layer_info in plotPlan:
|
||||
if self.board.IsLayerEnabled(layer_info[1]):
|
||||
@@ -67,9 +67,6 @@ class ProcessManager:
|
||||
else:
|
||||
footprints = list(self.board.GetFootprints())
|
||||
|
||||
# sort footprint after designator
|
||||
footprints.sort(key=lambda x: x.GetReference())
|
||||
|
||||
# unique designator dictionary
|
||||
footprint_designators = defaultdict(int)
|
||||
for i, footprint in enumerate(footprints):
|
||||
@@ -109,7 +106,7 @@ class ProcessManager:
|
||||
'Designator': "{}{}{}".format(footprint.GetReference(), "" if unique_id == "" else "_", unique_id),
|
||||
'Mid X': (footprint.GetPosition()[0] - self.board.GetDesignSettings().GetAuxOrigin()[0]) / 1000000.0,
|
||||
'Mid Y': (footprint.GetPosition()[1] - self.board.GetDesignSettings().GetAuxOrigin()[1]) * -1.0 / 1000000.0,
|
||||
'Rotation': footprint.GetOrientation().AsDegrees() if hasattr(footprint.GetOrientation(), 'AsDegrees') else footprint.GetOrientation() / 10.0,
|
||||
'Rotation': footprint.GetOrientation() / 10.0,
|
||||
'Layer': layer,
|
||||
})
|
||||
|
||||
@@ -120,31 +117,27 @@ class ProcessManager:
|
||||
unique_id = str(bom_designators[footprint.GetReference()])
|
||||
bom_designators[footprint.GetReference()] -= 1
|
||||
|
||||
# merge similar parts into single entry
|
||||
insert = True
|
||||
for component in self.bom:
|
||||
if component['Footprint'].upper() == footprint_name.upper() and component['Value'].upper() == footprint.GetValue().upper():
|
||||
component['Designator'] += ", " + "{}{}{}".format(footprint.GetReference(), "" if unique_id == "" else "_", unique_id)
|
||||
component['Quantity'] += 1
|
||||
insert = False
|
||||
# todo: merge similar parts into single entry
|
||||
|
||||
# add component to BOM
|
||||
if insert:
|
||||
self.bom.append({
|
||||
'Designator': "{}{}{}".format(footprint.GetReference(), "" if unique_id == "" else "_", unique_id),
|
||||
'Footprint': footprint_name,
|
||||
'Quantity': 1,
|
||||
'Value': footprint.GetValue(),
|
||||
# 'Mount': mount_type,
|
||||
'LCSC Part #': self._getMpnFromFootprint(footprint),
|
||||
})
|
||||
self.bom.append({
|
||||
'Designator': "{}{}{}".format(footprint.GetReference(), "" if unique_id == "" else "_", unique_id),
|
||||
'Footprint': footprint_name,
|
||||
'Quantity': 1,
|
||||
'Value': footprint.GetValue(),
|
||||
# 'Mount': mount_type,
|
||||
'LCSC Part #': self._getMpnFromFootprint(footprint),
|
||||
})
|
||||
|
||||
with open((os.path.join(temp_dir, placementFileName)), 'w', newline='', encoding='utf-8') as outfile:
|
||||
header = True
|
||||
csv_writer = csv.writer(outfile)
|
||||
# writing headers of CSV file
|
||||
csv_writer.writerow(self.components[0].keys())
|
||||
|
||||
for component in self.components:
|
||||
if header:
|
||||
# writing headers of CSV file
|
||||
csv_writer.writerow(component.keys())
|
||||
header = False
|
||||
|
||||
# writing data of CSV file
|
||||
if ('**' not in component['Designator']):
|
||||
csv_writer.writerow(component.values())
|
||||
@@ -152,12 +145,15 @@ class ProcessManager:
|
||||
def generate_bom(self, temp_dir):
|
||||
|
||||
with open((os.path.join(temp_dir, bomFileName)), 'w', newline='', encoding='utf-8') as outfile:
|
||||
header = True
|
||||
csv_writer = csv.writer(outfile)
|
||||
# writing headers of CSV file
|
||||
csv_writer.writerow(self.bom[0].keys())
|
||||
|
||||
# Output all of the component information
|
||||
for component in self.bom:
|
||||
if header:
|
||||
# writing headers of CSV file
|
||||
csv_writer.writerow(component.keys())
|
||||
header = False
|
||||
|
||||
# writing data of CSV file
|
||||
if ('**' not in component['Designator']):
|
||||
csv_writer.writerow(component.values())
|
||||
@@ -173,14 +169,20 @@ class ProcessManager:
|
||||
|
||||
return temp_file
|
||||
|
||||
def _getMpnFromFootprint(self, footprint):
|
||||
keys = ['LCSC Part #', 'JLCPCB Part #']
|
||||
fallback_keys = ['LCSC', 'JLC', 'MPN', 'Mpn', 'mpn']
|
||||
def upload_archive(self, temp_file):
|
||||
boardWidth = pcbnew.Iu2Millimeter(self.board.GetBoardEdgesBoundingBox().GetWidth())
|
||||
boardHeight = pcbnew.Iu2Millimeter(self.board.GetBoardEdgesBoundingBox().GetHeight())
|
||||
boardLayer = self.board.GetCopperLayerCount()
|
||||
|
||||
files = { 'upload[file]': open(temp_file, 'rb') }
|
||||
data = { 'boardWidth': boardWidth, 'boardHeight': boardHeight, 'boardLayer': boardLayer }
|
||||
upload_url = baseUrl + '/Common/KiCadUpFile/'
|
||||
|
||||
response = requests.post(upload_url, files=files, data=data)
|
||||
urls = json.loads(response.content)
|
||||
|
||||
def _getMpnFromFootprint(self, footprint):
|
||||
keys = ['mpn', 'Mpn', 'MPN', 'JLC_MPN', 'LCSC_MPN', 'LCSC Part #', 'JLC', 'LCSC']
|
||||
for key in keys:
|
||||
if footprint.HasProperty(key):
|
||||
return footprint.GetProperty(key)
|
||||
|
||||
for key in fallback_keys:
|
||||
if footprint.HasProperty(key):
|
||||
return footprint.GetProperty(key)
|
||||
|
||||
@@ -50,6 +50,10 @@ class ProcessThread(Thread):
|
||||
self.report(75)
|
||||
temp_file = self.process_manager.generate_archive(temp_dir, temp_file)
|
||||
|
||||
# upload files
|
||||
#self.report(87.5)
|
||||
#self.process_manager.upload_archive(temp_file)
|
||||
|
||||
# progress bar done animation
|
||||
read_so_far = 0
|
||||
total_size = os.path.getsize(temp_file)
|
||||
|
||||
Reference in New Issue
Block a user