Disconnects
Set of two electrical connectors that has a predefined pinout, connector selection, and signals list.
How disconnect data is stored
The definition of a disconnect lives in a CSV file called a "Signals List".
Signals List
Interacting with Signals Lists
A Signals List is an exhaustive list of every signal is going into or out of a thing. Signals Lists are the primary way Harnice stores information about devices, and act as the source of truth for devices and disconnects.
Signals List Validation Checks:
(These are automatically validated when you render the device or disconnect that owns the list.)
General Signals List Rules
-
Every signal in the Signals List must be contained by a pre-defined channel type
Channel Types
Channel Types
How are channels mapped?
How to define a new channel type
- In a repository of your choice (or start with harnice_library_public on your own branch), navigate to
library_repo/channel_types/channel_types.csv - If you want channel definitions to be private and are therefore working in a private repository, ensure the repo's path is listed in file
library_locations.csv(located at root of your harnice source code repo). The first column is the URL or traceable path, and the second column is your local path. - If you find the channel_type you're looking for, temporarily note it as a touple in a notepad somewhere with format
(ch_type_id, universal_library_repository). - If you don't find it, make a new one. It's important to try and reduce the number of channel_types in here to reduce complexity, but it's also important that you adhere to strict and true rules about what is allowed to be mapped to what. Modifications and additions to this document should be taken and reviewed very seriously.
chtype.path(channel_type)Resolve the on-disk path to the
channel_types.tsvfile for a given channel type.Args
channel_type: Channel type identifier in standard tuple format(channel_type_id, lib_repo)or any string representation thatparsecan understand (for example"(5, 'https://github.com/harnice/harnice')").
Returns
str: Absolute path to thechannel_types/channel_types.tsvfile inside the library repository that owns the given channel type.
Notes
- This does not filter rows; it only locates the TSV file that defines
all channel types for the given
lib_repo.
chtype.parse(val)Convert stored string into a tuple (chid:int, lib_repo:str). Handles both single tuples and extracts first tuple from lists.
chtype.compatibles(channel_type)Look up other channel types that are declared as compatible with the given channel type.
Args
channel_type: Channel type identifier in standard tuple format(channel_type_id, lib_repo)or any string representation thatparsecan understand.
Returns
list[tuple[int, str]]: List of(channel_type_id, lib_repo)tuples taken directly from thecompatible_channel_typescolumn ofchannel_types.tsv. Returns an empty list if no compatibles are defined or if the channel type cannot be found.
Data format
- The
compatible_channel_typescolumn must be an AST-parseable Python value:- Single tuple:
(1, "library_repo") - List of tuples:
[(1, "library_repo"), (2, "library_repo")]
- Single tuple:
chtype.attribute(channel_type, attribute)Read any additional column from
channel_types.tsvfor a given channel type.Args
channel_type: Channel type identifier in standard tuple format(channel_type_id, lib_repo)or any string representation thatparsecan understand.attribute: Column header name inchannel_types.tsvfor the value you want to read (for example"description","notes","voltage_rating").
Returns
Any: Value stored in the requestedattributecolumn for the matchingchannel_type_id. Returns an empty list[]if the channel type cannot be found.
Notes
- Use this for any per-channel-type metadata you've added as extra columns
beyond the core ones like
channel_type_id,signals, andcompatible_channel_types.
chtype.signals(channel_type)Return the list of signal names associated with a specific channel type.
Args
channel_type: Channel type identifier in standard tuple format(channel_type_id, lib_repo)or any string representation thatparsecan understand.
Returns
list[str]: List of signal names from thesignalscolumn ofchannel_types.tsvfor the matchingchannel_type_id. If the column is blank or the channel type cannot be found, returns an empty list.
Data format
- The
signalscolumn is expected to be a comma-separated string, for example:"CAN_H, CAN_L, SHIELD".
chtype.is_or_is_compatible_with(channel_type)Return the given channel type plus all channel types declared as compatible with it.
Args
channel_type: Channel type identifier in standard tuple format(channel_type_id, lib_repo)or any string representation thatparsecan understand.
Returns
list[tuple[int, str]]: List of(channel_type_id, lib_repo)tuples where the first entry is the parsedchannel_typeitself and the remaining entries are the compatibles returned bycompatibles(channel_type).
Typical use
- Use this when validating or mapping channels and you want to treat a channel type as valid if it is either exactly the requested type or explicitly listed as compatible with it.
- In a repository of your choice (or start with harnice_library_public on your own branch), navigate to
-
Each signal in the signals list must have every other signal defined by its channel type also present in the list.
- you can't just define 'positive' if the channel type requires 'positive' and 'negative'
-
Each signal defined in the list is contained by one or more cavities of connectors.
- you can't "cap off" or not populate one of the signals within a channel because that changes the channel type.
-
Every combination of (channel_id, signal) must be unique within the signals list
- you can’t have two i.e. “ch1, pos” signals on the same device
- if you need to break one signal out onto multiple conductors, you'll need to change the channel type to one that defines multiple conductors (i.e. named "ch1, pos-1")
-
You can’t put signals of the same channel on different connectors
-
this is because doing so breaks a lot of internal assumptions Harnice is making while mapping channels.
-
the following two options are recommended work-arounds:
-
Most correct but confusing: Define one channel type per signal, then manually chmap your channels or write a macro for mapping the channels to their respective destinations.
-
Janky but easiest to understand: Define a connector part number that actually represents multiple connectors, while using cavities to reference each connector.
-
-
Configurable Device Signals List Rules
It is often useful to be able to change the signals list based on how you're using the device.
-
Each possible configuration of a device must define the same number of conductors throughout the device
- Changing a configuration must not alter physical build, form, fit, or function, and thus there shall be no conductors that are added or taken away. Maybe some signals are 'unused', but they have to at least be counted for across all configurations.
-
There can be an unlimited number of configuration variables
- Sometimes just one variable is useful: an SM58 microphone can produce output signals in either balanced vs unbalanced format, depending on how you want to use it.
- Sometimes there are many variables: suppose you have a mixing console with 32 inputs, and each input can accept either mic or line level inputs depending on the configuration, and each accept either in balanced or unbalanced format signals. Because there's a channel-type defined for each of those options, this would imply 64 configuration variables of the mixing console, each mapping to a unique configuration. This allows the auto channel mapper to find compatibles, and also helps the user track how to set up their device.
Disconnect Signals List Rules
-
“A” and “B” channels of the same disconnect must be compatible with each other
- this is to ensure when you actually mate the disconnect that the channels inside will be compatible.
Columns
Columns are automatically generated when signals_list.new() is called. Additional columns are not supported and may result in an error when parsing.
Columns of Signals Lists for Devices
| Column | Description |
|---|---|
channel_id |
Unique identifier for the channel. |
signal |
Name of the electrical function of that signal, as it pertains to its channel type defition. i.e. "positive" |
connector_name |
Unique identifier for the connector that this signal and channel is a part of. |
cavity |
Identifier of the pin, socket, stud, etc, that this signal is internally electrically routed to within its connector. |
connector_mpn |
MPN of the connector in this device (NOT the mating connector). |
channel_type |
The channel type of this signal. Touple (x, y) where x is the channel id within a library repo and y is the traceable name or url where that channel type library is defined |
config_variable |
Change header or add more headers as needed. Blank: row is true across all values of this field. Otherwise, row is only true when configuration matches the value of this field. |
Columns of Signals Lists for Disconnects
| Column | Description |
|---|---|
channel_id |
Unique identifier for the channel. |
signal |
Name of the electrical function of that signal, as it pertains to its channel type defition. i.e. "positive" |
A_cavity |
Identifier of the pin, socket, stud, etc, that this signal is internally electrically routed to within that side of the connector. ??? question "Why are A and B different here?" Sometimes it's possible to have connectors that have cavities that may mate electrically, but have different names. For example, suppose two connectors physically mate, but are made by different manufacturers. One manufacturer used lowercase (a, b, c) to reference the cavities but the other used uppercase (A, B, C), or numbers (1, 2, 3), or colors (red, green, blue), etc. |
B_cavity |
Identifier of the pin, socket, stud, etc, that this signal is internally electrically routed to within that side of the connector. ??? question "Why are A and B different here?" Sometimes it's possible to have connectors that have cavities that may mate electrically, but have different names. For example, suppose two connectors physically mate, but are made by different manufacturers. One manufacturer used lowercase (a, b, c) to reference the cavities but the other used uppercase (A, B, C), or numbers (1, 2, 3), or colors (red, green, blue), etc. |
A_connector_mpn |
MPN of the connector of the harness on this side of the disconnect |
A_channel_type |
The channel type of this side of the discconect. ??? question "Why are A and B different here?" It's important to keep track of which side has which channel type so that you cannot accidentally flip pins and sockets, for example, by mapping the wrong channel type to the wrong pin gender. Careful validation should be done when mapping channels through disconnects to ensure the disconnects have channels that pass through them in the correct direction. |
B_connector_mpn |
MPN of the connector of the harness on this side of the disconnect |
B_channel_type |
The channel type of this side of the discconect. ??? question "Why are A and B different here?" It's important to keep track of which side has which channel type so that you cannot accidentally flip pins and sockets, for example, by mapping the wrong channel type to the wrong pin gender. Careful validation should be done when mapping channels through disconnects to ensure the disconnects have channels that pass through them in the correct direction. |
Commands:
Use the following functions by first importing the module in your script like this: then use as written.
signals_list.set_list_type(x)
Documentation needed.
signals_list.new()
Creates a new signals TSV file at fileio.path("signals list") with only the header row. Overwrites any existing file.
signals_list.append(**kwargs)
Appends a new row to the signals TSV file. Missing optional fields will be written as empty strings. Raises ValueError if required fields are missing.
Required kwargs: For 'device': channel_id, signal, connector_name, cavity, connector_mpn, channel_type For 'disconnect': A_channel_id, A_signal, A_connector_name, A_cavity, A_connector_mpn, A_channel_type, B_channel_id, B_signal, B_connector_name, B_cavity, B_connector_mpn, B_channel_type
signals_list.cavity_of_signal(channel_id, signal, path_to_signals_list)
Documentation needed.
signals_list.connector_name_of_channel(channel_id, path_to_signals_list)
Documentation needed.
File Structure
Reference the files in your product by calling fileio.path("file key") from your script. They'll automatically use this structure:
fileio.dirpath("part_directory") |-- yourpn/
|-- earlier revs/
fileio.path("revision history") |-- revhistory.csv
fileio.dirpath("rev_directory") L-- your rev/
fileio.path("feature tree") |-- yourpn-revX-feature_tree.py
fileio.path("signals list") |-- yourpn-revX-signals_list.tsv
fileio.path("attributes") L-- yourpn-revX-attributes.json
Rendering a disconnect
When a disconnect is rendered in Harnice, here's what happens:
- Harnice runs the feature tree if it's found in the device directory.
- The signals list is validated and verified.
How to define a new disconnect
-
Ensure every channel going into or out of your disconnect has a type defined in a repo somewhere. Each connector of your disconnect will contain information about which side has which direction ("a" contains "inputs", "b" contains "outputs" with respect to the disconnect itself, i.e. inputting into the disconnect)
Channel Types
Channel Types
How are channels mapped?
How to define a new channel type
- In a repository of your choice (or start with harnice_library_public on your own branch), navigate to
library_repo/channel_types/channel_types.csv - If you want channel definitions to be private and are therefore working in a private repository, ensure the repo's path is listed in file
library_locations.csv(located at root of your harnice source code repo). The first column is the URL or traceable path, and the second column is your local path. - If you find the channel_type you're looking for, temporarily note it as a touple in a notepad somewhere with format
(ch_type_id, universal_library_repository). - If you don't find it, make a new one. It's important to try and reduce the number of channel_types in here to reduce complexity, but it's also important that you adhere to strict and true rules about what is allowed to be mapped to what. Modifications and additions to this document should be taken and reviewed very seriously.
chtype.path(channel_type)Resolve the on-disk path to the
channel_types.tsvfile for a given channel type.Args
channel_type: Channel type identifier in standard tuple format(channel_type_id, lib_repo)or any string representation thatparsecan understand (for example"(5, 'https://github.com/harnice/harnice')").
Returns
str: Absolute path to thechannel_types/channel_types.tsvfile inside the library repository that owns the given channel type.
Notes
- This does not filter rows; it only locates the TSV file that defines
all channel types for the given
lib_repo.
chtype.parse(val)Convert stored string into a tuple (chid:int, lib_repo:str). Handles both single tuples and extracts first tuple from lists.
chtype.compatibles(channel_type)Look up other channel types that are declared as compatible with the given channel type.
Args
channel_type: Channel type identifier in standard tuple format(channel_type_id, lib_repo)or any string representation thatparsecan understand.
Returns
list[tuple[int, str]]: List of(channel_type_id, lib_repo)tuples taken directly from thecompatible_channel_typescolumn ofchannel_types.tsv. Returns an empty list if no compatibles are defined or if the channel type cannot be found.
Data format
- The
compatible_channel_typescolumn must be an AST-parseable Python value:- Single tuple:
(1, "library_repo") - List of tuples:
[(1, "library_repo"), (2, "library_repo")]
- Single tuple:
chtype.attribute(channel_type, attribute)Read any additional column from
channel_types.tsvfor a given channel type.Args
channel_type: Channel type identifier in standard tuple format(channel_type_id, lib_repo)or any string representation thatparsecan understand.attribute: Column header name inchannel_types.tsvfor the value you want to read (for example"description","notes","voltage_rating").
Returns
Any: Value stored in the requestedattributecolumn for the matchingchannel_type_id. Returns an empty list[]if the channel type cannot be found.
Notes
- Use this for any per-channel-type metadata you've added as extra columns
beyond the core ones like
channel_type_id,signals, andcompatible_channel_types.
chtype.signals(channel_type)Return the list of signal names associated with a specific channel type.
Args
channel_type: Channel type identifier in standard tuple format(channel_type_id, lib_repo)or any string representation thatparsecan understand.
Returns
list[str]: List of signal names from thesignalscolumn ofchannel_types.tsvfor the matchingchannel_type_id. If the column is blank or the channel type cannot be found, returns an empty list.
Data format
- The
signalscolumn is expected to be a comma-separated string, for example:"CAN_H, CAN_L, SHIELD".
chtype.is_or_is_compatible_with(channel_type)Return the given channel type plus all channel types declared as compatible with it.
Args
channel_type: Channel type identifier in standard tuple format(channel_type_id, lib_repo)or any string representation thatparsecan understand.
Returns
list[tuple[int, str]]: List of(channel_type_id, lib_repo)tuples where the first entry is the parsedchannel_typeitself and the remaining entries are the compatibles returned bycompatibles(channel_type).
Typical use
- Use this when validating or mapping channels and you want to treat a channel type as valid if it is either exactly the requested type or explicitly listed as compatible with it.
- In a repository of your choice (or start with harnice_library_public on your own branch), navigate to
-
Make a folder for the part number of your disconnect somewhere on your computer. Run Harnice Render, which will generate an example disconnect that you can then edit.
Rendering a Product
-
Navigate to your device folder (
cdin command line). You don't need to make a rev folder yet, just make sure your command line is in a folder you want to represent the device you're working on. -
Harnice render it (
harnice -r). It should walk you through the following steps then render an example:-
No valid Harnice file structure detected in 'your_part_number'. Create new PN here? [y]:hit enter -
Enter revision number [1]:hit enter for rev1 or type "A" or whatever you want your first rev to be called -
What product type are you working on? (harness, system, device, etc.):type "device" -
Enter a description of this device [DEVICE, FUNCTION, ATTRIBUTES, etc.]:self-explanatory -
Enter a description for this revision [INITIAL RELEASE]:hit enter, otherwise type the goal of the first revision
-
You can also lightweight render if you want to bypass some of the checks.
Lightweight Rendering a Product
If you need to build a KiCad block diagram quickly, without specifying channels and signals, you can with --lightweight.
Run harnice -l device or harnice --lightweight device from your device directory.
This will follow the same flowchart as --render, but truncate the validation process.
You will not be able to map channels with --lightweight
-
-
Edit the attributes of your new disconnect.
Editing the Attributes of a Product
- Navigate to the device folder, find the new rev folder you just made, open
*-attributes.json. - Change the default reference designator here, as well as any other attributes you may want to record.
- In the command line, render it again after you
cdinto the rev folder.
- Navigate to the device folder, find the new rev folder you just made, open
-
Edit the signals list of your new disconnect.
Updating a Signals List
Harnice defines a signals list to be a table that keeps track of every single signal going into and out of a device, which connector or channel it's part of, which signal names it has, which connector contact number or part number it has.
- If your device is very simple (has only a small number of signals), you are free to edit
*-signals_list.tsvmanually. If you choose to do this, delete*-feature_tree.pybefore rerunning because by default, it will overwrite the signals list. However, it is recommended that you edit the python feature tree instead to produce a validated, reproduceable, and portable result. - To edit the feature tree python file, this quick-start guide should give you an idea of how the default feature tree is set up, and how you might be able to change it to suit your needs. The goal of this feature tree is to make a signals list. Do not be concerned with writing this efficiently, as it will only be ran while rendering the device.
- These are useful modules you'll want to reference. Leave them there.
from harnice.lists import signals_listfrom harnice.products import chtype - Copy your channel_type touples in from earlier notepad step. Again, these are relevant only to the device you're trying to make. The dictionary is used to store these here so that you can reference the touples in a human-readable format in this script only.
ch_type_ids = {"in": (1, "https://github.com/harnice/harnice"),"out": (4, "https://github.com/harnice/harnice"),"chassis": (5, "https://github.com/harnice/harnice")} -
- Define your connector part numbers. Default convention is this dictionary, where you can resolve the part number by finding the connector name.
mpn_for_connector(connector_name)will search your definition dictionary for a connector name and return its part number.connector_mpns = {"XLR3F": ["in1", "in2"],"XLR3M": ["out1", "out2"]}
Define your pinouts. Default convention is this dictionary, where if you reference something like
xlr_pinout.pos, this dictionary should return the cavity name. Reminder: channels do not contain information about pinouts or connectors so this has to be done at each device. If you use the same pinout across multiple devices, you may consider importing that definition from a python library elsewhere.xlr_pinout = {"pos": 2,"neg": 3,"chassis": 1}signals_list.new()will overwrite the existing signals list with a blank one, which will be repopulated while the rest of this script is executed.- Bespoke logic should be written in python for the remainder of this script, making use of patterns and naming conventions of this specific device. Read up on the documentation for the available commands in the
harnice.lists.signals_listandharnice.products.chtypemodules (NOT YET WRITTEN AT TIME OF WRITING THIS GUIDE) - I'd recommend you use a python editor on your screen at the same time as a csv editor that automatically refreshes (vscode, easycsveditor on the mac store) so that you can update your python, render the code frequently, and watch the updates in realtime on your csv
- Define your connector part numbers. Default convention is this dictionary, where you can resolve the part number by finding the connector name.
- These are useful modules you'll want to reference. Leave them there.
- If your device is very simple (has only a small number of signals), you are free to edit