[Stencil_3D] New output

- KiKit's "stencil createprinted"
This commit is contained in:
Salvador E. Tropea 2022-12-01 11:15:12 -03:00
parent 5767a03868
commit 2a46ab1cff
13 changed files with 388 additions and 16 deletions

View File

@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `populate` to create step-by-step assembly instructions
With support for `pcbdraw` and `render_3d`.
- `panelize` to create a PCB panel containing N copies of the PCB.
- `stencil_3d` to create 3D self-registering printable stencils.
- generic filters: options to filter by PCB side
- BoM:
- Option to link to Mouser site.

View File

@ -97,6 +97,8 @@ For example, it's common that you might want for each board rev:
* PCB 3D model in STEP format
* PCB 3D render in PNG format
* Compare PCB/SCHs
* Panelization
* Stencil creation
You want to do this in a one-touch way, and make sure everything you need to
do so is securely saved in version control, not on the back of an old
@ -142,6 +144,9 @@ Notes:
- Show KiAuto installation information for `info` (v2.0.0)
- Print the page frame in GUI mode for `pcb_print` (v1.6.7)
[**KiKit**](https://github.com/yaqwsx/KiKit) [![Tool](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/llave-inglesa-22x22.png)](https://github.com/yaqwsx/KiKit) ![Auto-download](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/auto_download-22x22.png)
- Mandatory for: `panelize`, `stencil_3d`
[**LXML**](https://pypi.org/project/LXML/) [![Python module](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/Python-logo-notext-22x22.png)](https://pypi.org/project/LXML/) [![Debian](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/debian-openlogo-22x22.png)](https://packages.debian.org/bullseye/python3-lxml) ![Auto-download](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/auto_download-22x22.png)
- Mandatory for: `pcb_print`, `pcbdraw`
@ -158,12 +163,12 @@ Notes:
[**KiCad PCB/SCH Diff**](https://github.com/INTI-CMNB/KiDiff) v2.4.3 [![Tool](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/llave-inglesa-22x22.png)](https://github.com/INTI-CMNB/KiDiff) ![Auto-download](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/auto_download-22x22.png)
- Mandatory for `diff`
[**KiKit**](https://github.com/yaqwsx/KiKit) [![Tool](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/llave-inglesa-22x22.png)](https://github.com/yaqwsx/KiKit) ![Auto-download](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/auto_download-22x22.png)
- Mandatory for `panelize`
[**mistune**](https://pypi.org/project/mistune/) [![Python module](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/Python-logo-notext-22x22.png)](https://pypi.org/project/mistune/) [![Debian](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/debian-openlogo-22x22.png)](https://packages.debian.org/bullseye/python3-mistune)
- Mandatory for `populate`
[**OpenSCAD**](https://openscad.org/) [![Tool](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/llave-inglesa-22x22.png)](https://openscad.org/) [![Debian](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/debian-openlogo-22x22.png)](https://packages.debian.org/bullseye/openscad)
- Mandatory for `stencil_3d`
[**QRCodeGen**](https://pypi.org/project/QRCodeGen/) [![Python module](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/Python-logo-notext-22x22.png)](https://pypi.org/project/QRCodeGen/) [![PyPi dependency](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/PyPI_logo_simplified-22x22.png)](https://pypi.org/project/QRCodeGen/) [![Debian](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/debian-openlogo-22x22.png)](https://packages.debian.org/bullseye/python3-qrcodegen) ![Auto-download](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/auto_download-22x22.png)
- Mandatory for `qr_lib`
@ -3555,6 +3560,55 @@ Notes:
Internally we use 10 for low priority, 90 for high priority and 50 for most outputs.
- `run_by_default`: [boolean=true] When enabled this output will be created when no specific outputs are requested.
* 3D Printed Stencils
* Type: `stencil_3d`
* Description: Creates a 3D self-registering model of a stencil you can easily print on
SLA printer, you can use it to apply solder paste to your PCB.
These stencils are quick solution when you urgently need a stencil but probably
they don't last long and might come with imperfections.
It currently uses KiKit, so please read
[KiKit docs](https://github.com/yaqwsx/KiKit/blob/master/doc/stencil.md).
Note that we don't implement `--ignore` option, you should use a variant for this
* Valid keys:
- **`comment`**: [string=''] A comment for documentation purposes.
- **`dir`**: [string='./'] Output directory for the generated files.
If it starts with `+` the rest is concatenated to the default dir.
- **`name`**: [string=''] Used to identify this particular output definition.
- **`options`**: [dict] Options for the `Stencil_3D` output.
* Valid keys:
- **`output`**: [string='%f-%i%I%v.%x'] Filename for the output (%i='stencil_3d_top'|'stencil_3d_bottom'|'stencil_3d_edge',
%x='stl'|'scad'|'dxf'). Affected by global options.
- **`thickness`**: [number=0.15] Stencil thickness [mm]. Defines amount of paste dispensed.
- `cutout`: [string|list(string)] List of components to add a cutout based on the component courtyard.
This is useful when you have already pre-populated board and you want to populate more
components.
- `dnf_filter`: [string|list(string)='_none'] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
- *enlarge_holes*: Alias for enlarge_holes.
- `enlargeholes`: [number=0] Enlarge pad holes by x mm.
- *frame_clearance*: Alias for frameclearance.
- *frame_width*: Alias for framewidth.
- `frameclearance`: [number=0] Clearance for the stencil register [mm].
- `framewidth`: [number=1] Register frame width.
- `include_scad`: [boolean=true] Include the generated OpenSCAD files. Note that this also includes the DXF files.
- *pcb_thickness*: Alias for pcbthickness.
- `pcbthickness`: [number=0] PCB thickness [mm]. If 0 we will ask KiCad.
- `pre_transform`: [string|list(string)='_none'] Name of the filter to transform fields before applying other filters.
A short-cut to use for simple cases where a variant is an overkill.
- `side`: [string='auto'] [top,bottom,auto,both] Which side of the PCB we want. Using `auto` will detect which
side contains solder paste.
- `variant`: [string=''] Board variant to apply.
- `category`: [string|list(string)=''] The category for this output. If not specified an internally defined category is used.
Categories looks like file system paths, i.e. PCB/fabrication/gerber.
- `disable_run_by_default`: [string|boolean] Use it to disable the `run_by_default` status of other output.
Useful when this output extends another and you don't want to generate the original.
Use the boolean true value to disable the output you are extending.
- `extends`: [string=''] Copy the `options` section from the indicated output.
- `output_id`: [string=''] Text to use for the %I expansion content. To differentiate variations of this output.
- `priority`: [number=50] [0,100] Priority for this output. High priority outputs are created first.
Internally we use 10 for low priority, 90 for high priority and 50 for most outputs.
- `run_by_default`: [boolean=true] When enabled this output will be created when no specific outputs are requested.
* STEP (ISO 10303-21 Clear Text Encoding of the Exchange Structure)
* Type: `step`
* Description: Exports the PCB as a 3D model.

View File

@ -96,6 +96,8 @@ For example, it's common that you might want for each board rev:
* PCB 3D model in STEP format
* PCB 3D render in PNG format
* Compare PCB/SCHs
* Panelization
* Stencil creation
You want to do this in a one-touch way, and make sure everything you need to
do so is securely saved in version control, not on the back of an old

View File

@ -2460,6 +2460,52 @@ outputs:
title: ''
# [string=''] Board variant to apply
variant: ''
# 3D Printed Stencils:
# SLA printer, you can use it to apply solder paste to your PCB.
# These stencils are quick solution when you urgently need a stencil but probably
# they don't last long and might come with imperfections.
# It currently uses KiKit, so please read
# [KiKit docs](https://github.com/yaqwsx/KiKit/blob/master/doc/stencil.md).
# Note that we don't implement `--ignore` option, you should use a variant for this
- name: 'stencil_3d_example'
comment: 'Creates a 3D self-registering model of a stencil you can easily print on'
type: 'stencil_3d'
dir: 'Example/stencil_3d_dir'
options:
# [string|list(string)] List of components to add a cutout based on the component courtyard.
# This is useful when you have already pre-populated board and you want to populate more
# components
cutout: ''
# [string|list(string)='_none'] Name of the filter to mark components as not fitted.
# A short-cut to use for simple cases where a variant is an overkill
dnf_filter: '_none'
# `enlarge_holes` is an alias for `enlarge_holes`
# [number=0] Enlarge pad holes by x mm
enlargeholes: 0
# `frame_clearance` is an alias for `frameclearance`
# `frame_width` is an alias for `framewidth`
# [number=0] Clearance for the stencil register [mm]
frameclearance: 0
# [number=1] Register frame width
framewidth: 1
# [boolean=true] Include the generated OpenSCAD files. Note that this also includes the DXF files
include_scad: true
# [string='%f-%i%I%v.%x'] Filename for the output (%i='stencil_3d_top'|'stencil_3d_bottom'|'stencil_3d_edge',
# %x='stl'|'scad'|'dxf'). Affected by global options
output: '%f-%i%I%v.%x'
# `pcb_thickness` is an alias for `pcbthickness`
# [number=0] PCB thickness [mm]. If 0 we will ask KiCad
pcbthickness: 0
# [string|list(string)='_none'] Name of the filter to transform fields before applying other filters.
# A short-cut to use for simple cases where a variant is an overkill
pre_transform: '_none'
# [string='auto'] [top,bottom,auto,both] Which side of the PCB we want. Using `auto` will detect which
# side contains solder paste
side: 'auto'
# [number=0.15] Stencil thickness [mm]. Defines amount of paste dispensed
thickness: 0.15
# [string=''] Board variant to apply
variant: ''
# STEP (ISO 10303-21 Clear Text Encoding of the Exchange Structure):
# This is the most common 3D format for exchange purposes.
# This output is what you get from the 'File/Export/STEP' menu in pcbnew.

View File

@ -69,6 +69,10 @@ Dependencies:
debian: python3-lxml
arch: python-lxml
downloader: python
- name: KiKit
github: yaqwsx/KiKit
pypi: KiKit
downloader: pytool
"""
import importlib
import os
@ -559,6 +563,9 @@ def run_command(cmd, only_first_line=False, pre_ver_text=None, no_err_2=False):
return None
last_stderr = res_run.stderr.decode()
res = res_run.stdout.decode().strip()
if len(res) == 0 and len(last_stderr) != 0:
# Ok, yes, OpenSCAD prints its version to stderr!!!
res = last_stderr
if only_first_line:
res = res.split('\n')[0]
pre_vers = (cmd[0]+' version ', cmd[0]+' ', pre_ver_text)

View File

@ -377,6 +377,19 @@ class GS(object):
copy2(pro_name, pro_copy)
return pro_copy
@staticmethod
def get_pcb_and_pro_names(name):
if GS.ki5:
return [name, name.replace('kicad_pcb', 'pro')]
return [name, name.replace('kicad_pcb', 'kicad_pro'), name.replace('kicad_pcb', 'kicad_prl')]
@staticmethod
def remove_pcb_and_pro(name):
""" Used to remove temporal PCB and project files """
for fn in GS.get_pcb_and_pro_names(name):
if os.path.isfile(fn):
os.remove(fn)
@staticmethod
def load_board():
""" Will be repplaced by kiplot.py """

View File

@ -242,6 +242,7 @@ W_PCBDRAW = '(W103) '
W_NOCRTYD = '(W104) '
W_PANELEMPTY = '(W105) '
W_ONWIN = '(W106) '
W_AUTONONE = '(W106) '
# Somehow arbitrary, the colors are real, but can be different
PCB_MAT_COLORS = {'fr1': "937042", 'fr2': "949d70", 'fr3': "adacb4", 'fr4': "332B16", 'fr5': "6cc290"}
PCB_FINISH_COLORS = {'hal': "8b898c", 'hasl': "8b898c", 'imag': "8b898c", 'enig': "cfb96e", 'enepig': "cfb96e",

View File

@ -252,6 +252,11 @@ class VariantOptions(BaseOptions):
return []
return [c.ref for c in self._comps if not c.fitted or not c.included]
# Here just to avoid pulling pcbnew for this
@staticmethod
def to_mm(val):
return ToMM(val)
@staticmethod
def create_module_element(m):
if GS.ki6:
@ -334,6 +339,22 @@ class VariantOptions(BaseOptions):
for line in restore:
m.Remove(line)
def detect_solder_paste(self, board):
""" Detects if the top and/or bottom layer has solder paste """
fpaste = board.GetLayerID('F.Paste')
bpaste = board.GetLayerID('B.Paste')
top = bottom = False
for m in GS.get_modules_board(board):
for p in m.Pads():
pad_layers = p.GetLayerSet()
if not top and fpaste in pad_layers.Seq():
top = True
if not bottom and bpaste in pad_layers.Seq():
bottom = True
if top and bottom:
return top, bottom
return top, bottom
def remove_paste_and_glue(self, board, comps_hash):
""" Remove from solder paste layers the filtered components. """
if comps_hash is None or not (GS.global_remove_solder_paste_for_dnp or GS.global_remove_adhesive_for_dnp):

View File

@ -5,10 +5,7 @@
# Project: KiBot (formerly KiPlot)
"""
Dependencies:
- name: KiKit
github: yaqwsx/KiKit
pypi: KiKit
downloader: pytool
- from: KiKit
role: mandatory
"""
import collections
@ -708,10 +705,7 @@ class PanelizeOptions(VariantOptions):
fname = self.save_tmp_board()
self.unfilter_pcb_components(GS.board, do_3D=True)
self.restore_title()
to_remove.append(fname)
to_remove.append(fname.replace('kicad_pcb', 'kicad_pro'))
to_remove.append(fname.replace('kicad_pcb', 'kicad_prl'))
to_remove.append(fname.replace('kicad_pcb', 'pro'))
to_remove.extend(GS.get_pcb_and_pro_names(fname))
logger.debug('- Modified PCB: '+fname)
else:
fname = GS.pcb_file

180
kibot/out_stencil_3d.py Normal file
View File

@ -0,0 +1,180 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2022 Salvador E. Tropea
# Copyright (c) 2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
"""
Dependencies:
- from: KiKit
role: mandatory
- name: OpenSCAD
url: https://openscad.org/
url_down: https://openscad.org/downloads.html
command: openscad
debian: openscad
arch: openscad
role: mandatory
"""
import os
import shutil
import tempfile
from .error import PlotError
from .gs import GS
from .kiplot import run_command
from .out_base import VariantOptions
from .misc import W_AUTONONE
from .macros import macros, document, output_class # noqa: F401
from . import log
logger = log.get_logger()
class Stencil_3D_Options(VariantOptions):
def __init__(self):
with document:
self.output = GS.def_global_output
""" *Filename for the output (%i='stencil_3d_top'|'stencil_3d_bottom'|'stencil_3d_edge',
%x='stl'|'scad'|'dxf') """
self.side = 'auto'
""" [top,bottom,auto,both] Which side of the PCB we want. Using `auto` will detect which
side contains solder paste """
self.include_scad = True
""" Include the generated OpenSCAD files. Note that this also includes the DXF files """
self.cutout = ''
""" [string|list(string)] List of components to add a cutout based on the component courtyard.
This is useful when you have already pre-populated board and you want to populate more
components """
self.pcbthickness = 0
""" PCB thickness [mm]. If 0 we will ask KiCad """
self.pcb_thickness = None
""" {pcbthickness} """
self.thickness = 0.15
""" *Stencil thickness [mm]. Defines amount of paste dispensed """
self.framewidth = 1
""" Register frame width """
self.frame_width = None
""" {framewidth} """
self.frameclearance = 0
""" Clearance for the stencil register [mm] """
self.frame_clearance = None
""" {frameclearance} """
self.enlargeholes = 0
""" Enlarge pad holes by x mm """
self.enlarge_holes = None
""" {enlarge_holes} """
super().__init__()
def config(self, parent):
super().config(parent)
self.cutout = ','.join(self.force_list(self.cutout))
def move_output(self, src_dir, src_file, id, ext, replacement=None, patch=False):
self._expand_id = id
self._expand_ext = ext
dst_name = self._parent.expand_filename(self._parent.output_dir, self.output)
src_name = os.path.join(src_dir, src_file)
if not os.path.isfile(src_name):
raise PlotError('Missing output file {}'.format(src_name))
if patch:
# Adjust the names of the DXF files
with open(src_name, 'r') as f:
content = f.read()
for k, v in replacement.items():
content = content.replace(k, v)
with open(dst_name, 'w') as f:
f.write(content)
else:
shutil.move(src_name, dst_name)
if replacement is not None:
replacement[src_name] = os.path.basename(dst_name)
def get_targets(self, out_dir):
# TODO: auto side is tricky, needs variants applied
return [self._parent.expand_filename(out_dir, self.output)]
def run(self, output):
cmd_kikit = self.ensure_tool('KiKit')
self.ensure_tool('OpenSCAD')
super().run(output)
# Apply variants and filters
filtered = self.filter_pcb_components(GS.board)
if self.side == 'auto':
detected_top, detected_bottom = self.detect_solder_paste(GS.board)
fname = self.save_tmp_board() if filtered else GS.pcb_file
if filtered:
self.unfilter_pcb_components(GS.board)
# Avoid running the tool if we will generate useless models
if self.side == 'auto' and not detected_top and not detected_bottom:
logger.warning(W_AUTONONE+'No solder paste detected, skipping 3D stencil generation')
return
# If no PCB thickness indicated ask KiCad
if not self.pcbthickness:
ds = GS.board.GetDesignSettings()
self.pcbthickness = self.to_mm(ds.GetBoardThickness())
# Create the command line
cmd = [cmd_kikit, 'stencil', 'createprinted',
'--thickness', str(self.thickness),
'--framewidth', str(self.framewidth),
'--pcbthickness', str(self.pcbthickness)]
if self.cutout:
cmd.extend(['--coutout', self.cutout])
if self.frameclearance:
cmd.extend(['--frameclearance', str(self.frameclearance)])
if self.enlargeholes:
cmd.extend(['--enlargeholes', str(self.enlargeholes)])
with tempfile.TemporaryDirectory() as tmp:
cmd.append(fname)
cmd.append(tmp)
try:
run_command(cmd)
finally:
# Remove temporal variant
if filtered:
GS.remove_pcb_and_pro(fname)
# Now copy the files we want
# - Which side?
do_top = do_bottom = False
if self.side == 'top':
do_top = True
elif self.side == 'bottom':
do_bottom = True
elif self.side == 'both':
do_top = True
do_bottom = True
else: # auto
do_top = detected_top
do_bottom = detected_bottom
prj_name = os.path.splitext(os.path.basename(fname))[0]
replacements = {}
# The edge is needed by any of the OpenSCAD files
if (do_top or do_bottom) and self.include_scad:
self.move_output(tmp, prj_name+'-EdgeCuts.dxf', 'stencil_3d_edge', 'dxf', replacements)
# Top side
if do_top:
self.move_output(tmp, 'topStencil.stl', 'stencil_3d_top', 'stl')
if self.include_scad:
self.move_output(tmp, prj_name+'-PasteTop.dxf', 'stencil_3d_top', 'dxf', replacements)
self.move_output(tmp, 'topStencil.scad', 'stencil_3d_top', 'scad', replacements, patch=True)
# Bottom side
if do_bottom:
self.move_output(tmp, 'bottomStencil.stl', 'stencil_3d_bottom', 'stl')
if self.include_scad:
self.move_output(tmp, prj_name+'-PasteBottom.dxf', 'stencil_3d_bottom', 'dxf', replacements)
self.move_output(tmp, 'bottomStencil.scad', 'stencil_3d_bottom', 'scad', replacements, patch=True)
@output_class
class Stencil_3D(BaseOutput): # noqa: F821
""" 3D Printed Stencils
Creates a 3D self-registering model of a stencil you can easily print on
SLA printer, you can use it to apply solder paste to your PCB.
These stencils are quick solution when you urgently need a stencil but probably
they don't last long and might come with imperfections.
It currently uses KiKit, so please read
[KiKit docs](https://github.com/yaqwsx/KiKit/blob/master/doc/stencil.md).
Note that we don't implement `--ignore` option, you should use a variant for this """
def __init__(self):
super().__init__()
with document:
self.options = Stencil_3D_Options
""" *[dict] Options for the `Stencil_3D` output """

View File

@ -558,7 +558,7 @@ deps = '{\
"extra_arch": null,\
"extra_deb": null,\
"help_option": "--version",\
"importance": 10000,\
"importance": 20000,\
"in_debian": false,\
"is_kicad_plugin": false,\
"is_python": false,\
@ -575,6 +575,13 @@ deps = '{\
"max_version": null,\
"output": "panelize",\
"version": null\
},\
{\
"desc": null,\
"mandatory": true,\
"max_version": null,\
"output": "stencil_3d",\
"version": null\
}\
],\
"tests": [],\
@ -622,6 +629,39 @@ deps = '{\
"url": null,\
"url_down": null\
},\
"OpenSCAD": {\
"arch": "openscad",\
"command": "openscad",\
"comments": [],\
"deb_package": "openscad",\
"downloader": null,\
"downloader_str": null,\
"extra_arch": null,\
"extra_deb": null,\
"help_option": "--version",\
"importance": 10000,\
"in_debian": true,\
"is_kicad_plugin": false,\
"is_python": false,\
"name": "OpenSCAD",\
"no_cmd_line_version": false,\
"no_cmd_line_version_old": false,\
"output": "stencil_3d",\
"plugin_dirs": null,\
"pypi_name": "OpenSCAD",\
"roles": [\
{\
"desc": null,\
"mandatory": true,\
"max_version": null,\
"output": "stencil_3d",\
"version": null\
}\
],\
"tests": [],\
"url": "https://openscad.org/",\
"url_down": "https://openscad.org/downloads.html"\
},\
"Pandoc": {\
"arch": "pandoc",\
"command": "pandoc",\
@ -1027,7 +1067,7 @@ def run_command(cmd, only_first_line=False, pre_ver_text=None, no_err_2=False):
cmd[0] = cmd_full
last_cmd = None
try:
cmd_output = subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
res_run = subprocess.run(cmd, check=True, capture_output=True)
last_cmd = cmd[0]
except FileNotFoundError as e:
last_ok = False
@ -1039,7 +1079,9 @@ def run_command(cmd, only_first_line=False, pre_ver_text=None, no_err_2=False):
print('Output from command: '+e.output.decode())
last_ok = False
return UNKNOWN
res = cmd_output.decode().strip()
res = res_run.stdout.decode().strip()
if len(res) == 0:
res = res_run.stderr.decode().strip()
if only_first_line:
res = res.split('\n')[0]
pre_vers = (cmd[0]+' version ', cmd[0]+' ', pre_ver_text)

View File

@ -80,7 +80,7 @@ def run_command(cmd, only_first_line=False, pre_ver_text=None, no_err_2=False):
cmd[0] = cmd_full
last_cmd = None
try:
cmd_output = subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
res_run = subprocess.run(cmd, check=True, capture_output=True)
last_cmd = cmd[0]
except FileNotFoundError as e:
last_ok = False
@ -92,7 +92,9 @@ def run_command(cmd, only_first_line=False, pre_ver_text=None, no_err_2=False):
print('Output from command: '+e.output.decode())
last_ok = False
return UNKNOWN
res = cmd_output.decode().strip()
res = res_run.stdout.decode().strip()
if len(res) == 0:
res = res_run.stderr.decode().strip()
if only_first_line:
res = res.split('\n')[0]
pre_vers = (cmd[0]+' version ', cmd[0]+' ', pre_ver_text)

View File

@ -0,0 +1,9 @@
# Example KiBot config file for a basic 3D stencil
kibot:
version: 1
outputs:
- name: 'stencil'
comment: "Creates a 3D printable stencil"
type: stencil_3d
dir: stencil/3D