ShiboSoftwareDev/solar-battery-charger-module
This hardware setup integrates a solar panel, a lithium-ion battery, and a multi-rail buck converter with a battery charging IC, protection circuitry, and monitoring components, enabling solar power harvesting, battery charging, and power distribution in an embedded system.
- Version
- 1.0.4
- License
- unset
- Stars
- 0
scripts/generate-fabrication-csv.mts
import { readFileSync, writeFileSync } from "node:fs"
import { convertCircuitJsonToPickAndPlaceCsv } from "circuit-json-to-pnp-csv"
const circuit = JSON.parse(readFileSync("dist/index/circuit.json", "utf8"))
const components = circuit.filter((element: any) => element.type === "source_component")
const csvCell = (value: unknown) => {
const text = value == null ? "" : String(value)
return /[",\r\n]/.test(text) ? `"${text.replaceAll('"', '""')}"` : text
}
const valueOf = (component: any) =>
component.display_resistance ??
component.display_capacitance ??
component.display_inductance ??
component.manufacturer_part_number ??
component.name
const lcscOf = (component: any) => component.supplier_part_numbers?.jlcpcb?.[0] ?? ""
const assemblyOf = (component: any) =>
component.name === "J_SOLAR"
? "THT"
: "SMT"
const footprintByMpn: Record<string, string> = {
"KF127S-5.08-2P": "THT-TerminalBlock-2P-P5.08mm",
"B3B-PH-SM4-TB(LF)(SN)": "JST-PH-3P-SMT-P2.00mm",
SS54: "SMA",
GRM32ER7YA106KA12L: "1210",
FRC2512F2R00TS: "2512",
"1206W4F100JT5E": "1206",
CL21B105KBFNNNE: "0805",
BQ24650RVAR: "VQFN-16-EP-3.5x3.5mm-P0.5mm",
"SI7288DP-T1-GE3": "PowerPAK-SO-8",
"2N7002": "SOT-23",
MBR0540T1G: "SOD-123",
IHLP2525CZER100M01: "2525",
WSL1206R0200FEA: "1206",
"0402WGF0000TCE": "0402",
"0402WGF4993TCE": "0402",
"0402WGF3602TCE": "0402",
"0402WGF1003TCE": "0402",
"0402CG220J500NT": "0402",
"0402WGF7501TCE": "0402",
"0402WGF8202TCE": "0402",
"0402WGF1002TCE": "0402",
"0402WGF1001TCE": "0402",
"0402WGF1004TCE": "0402",
CL05B104KB5NNNC: "0402",
"1210B225K500NT": "1210",
"LTST-C190GKT": "0603",
"LTST-C190KRKT": "0603",
"HoLLR1206-1W-5mR-1%": "1206",
STC3115AIQT: "VFQFPN-10-2x3mm-P0.5mm",
GRM155Z71A105KE01D: "0402",
CC0402KRX7R6BB224: "0402",
TPS63031DSKR: "VSON-10-EP-2.5x2.5mm-P0.5mm",
"DFE252012P-1R5M=P2": "2520",
CL10B106MQ8NRNC: "0603",
}
const footprintOf = (component: any) =>
footprintByMpn[component.manufacturer_part_number] ?? ""
// PCB-only edge contacts have no purchased part and must not appear in a
// JLCPCB assembly BOM. Keep them in Circuit JSON, but only emit components
// carrying an actual JLCPCB/LCSC catalog code into manufacturing CSVs.
const assemblyComponents = components.filter((component: any) => lcscOf(component))
const perComponentRows = assemblyComponents.map((component: any) => [
component.name,
valueOf(component),
footprintOf(component),
component.manufacturer_part_number ?? "",
lcscOf(component),
assemblyOf(component),
])
const grouped = new Map<string, { designators: string[]; component: any }>()
for (const component of assemblyComponents) {
const key = [valueOf(component), footprintOf(component), component.manufacturer_part_number ?? "", lcscOf(component), assemblyOf(component)].join("\0")
const group = grouped.get(key) ?? { designators: [], component }
group.designators.push(component.name)
grouped.set(key, group)
}
const groupedRows = [...grouped.values()].map(({ designators, component }) => [
valueOf(component),
designators.join(","),
footprintOf(component),
lcscOf(component),
component.manufacturer_part_number ?? "",
designators.length,
assemblyOf(component),
])
const toCsv = (header: string[], rows: unknown[][]) =>
[header, ...rows].map((row) => row.map(csvCell).join(",")).join("\n") + "\n"
writeFileSync(
"fabrication/solar-battery-charger-tscircuit-bom.csv",
toCsv(["Designator", "Value", "Footprint", "Manufacturer Part Number", "LCSC", "Assembly"], perComponentRows),
)
writeFileSync(
"fabrication/solar-battery-charger-assembly-bom.csv",
toCsv(["Comment", "Designator", "Footprint", "LCSC Part #", "Manufacturer Part Number", "Quantity", "Assembly"], groupedRows),
)
const pnpCsv = convertCircuitJsonToPickAndPlaceCsv(circuit)
.split(/\r?\n/)
.filter((line, index) => index === 0 || (!line.startsWith("J_CTRL,") && !line.startsWith("J_IO,")))
.filter(Boolean)
.join("\n") + "\n"
writeFileSync("fabrication/solar-battery-charger-pick-and-place.csv", pnpCsv)
console.log(JSON.stringify({
componentCount: components.length,
assemblyComponentCount: assemblyComponents.length,
groupedBomRows: groupedRows.length,
uniqueLcscParts: new Set(assemblyComponents.map(lcscOf)).size,
}, null, 2))