Place/update footprint with Python

Hi all, first time poster here so apologies if I’m in the wrong place.

I’m having issues using the Python APIs to swap out a footprint for a pair of footprints - I want to replace a single footprint with two different footprints, and move/rotate the new footprints a bit to keep them in the correct spots. Here’s my code:

import pcbnew

# Initialize
board = pcbnew.LoadBoard("E:\\path\\to\\pcb.kicad_pcb")
modules = board.GetModules()

# Get relevant footprints
def GetFPID(lib, name):
    libpath = "E:\\KiCad\\share\\kicad\\modules\\" + lib
    src_type = pcbnew.IO_MGR.GuessPluginTypeFromLibPath(libpath);
    plugin = pcbnew.IO_MGR.PluginFind(src_type)
    fp = plugin.FootprintLoad(libpath, name)
    return fp.GetFPID()

new_keysw = GetFPID("Button_Switch_Keyboard.pretty", "SW_Cherry_MX_1.00u_PCB")
new_led = GetFPID("LED_THT.pretty", "LED_D1.8mm_W3.3mm_H2.4mm")

# Do the conversion
count = 0
for module in modules:
    if module.GetFPID().GetUniStringLibItemName() == "SW_Cherry_MX_1.00u_PCB_LED":
        print("Replacing " + module.GetReference())
        module.SetFPID(new_keysw)
        module.Move(pcbnew.wxPoint(2.54, -5))
        led = pcbnew.MODULE(board)
        led.SetFPID(new_led)
        led_pos = pcbnew.wxPoint(module.GetPosition().x - 3.81, module.GetPosition().y + 10.13)
        led.SetPosition(led_pos)
        led.SetOrientation(180)
        count = count + 1
        board.Save("pcb.kicad_pcb")
        break
print("Replaced " + count + " footprints")

I have to run this in a silly line-by-line fashion in the shell otherwise it executes the first line and nothing else (not sure what’s up there) but where the real problems start is the SetFPID call doesn’t seem to actually replace the footprint. I can see that the object in the PCB references the new footprint, but it is visually not that footprint. I have to go to ‘Update footprint’ from its properties for the change to take effect. Also, creating the LED module doesn’t seem to work at all, but I’m at a loss as to what to do with just the docs to guide me. Please let me know if there’s just a function I’m missing or if I’m going about this entirely the wrong way. Thanks.

SetFPID will not change footprint, it will just change the reference in existing footprint object to point to new footprint ID.
If you want to actually swap footprints you need to create new Module object probably by loading it from library, add it to board using board.Add() and remove old object.

4 Likes

Thanks for the reply, although board.Add(MODULE module) doesn’t seem to do anything, and I can’t find that method in the docs at all. Could there be something else I’m missing?

After making changes to board you need to call pcbnew.Refresh() or SaveBoard() to have the changes reflected in window/file respectively.

Docs for the add method:
https://docs.kicad-pcb.org/doxygen-python/classpcbnew_1_1BOARD__ITEM__CONTAINER.html#af18b28e893f59d19a3e06c3908f4a343
It’s inherited from BOARD_ITEM_CONTAINER

Refresh is great, thanks for that. I was using SaveBoard previously but I wasn’t seeing my new modules in the new file, and I still don’t see them after refreshing. Here’s my code now:

new_keysw = pcbnew.MODULE(board)
new_keysw.SetFPID(new_keysw_fp)
new_keysw_pos = (pcbnew.wxPoint(module.GetPosition().x + 2.54, module.GetPosition().y - 5))
new_keysw.SetPosition(new_keysw_pos)
new_keysw.SetOrientation(module.GetOrientation())
board.Add(new_keysw)
led = pcbnew.MODULE(board)
led.SetFPID(led_fp)
led_pos = pcbnew.wxPoint(module.GetPosition().x - 3.81, module.GetPosition().y + 10.13)
led.SetPosition(led_pos)
led.SetOrientation(180)
board.Add(led)
board.RemoveNative(module)
count = count + 1
pcbnew.Refresh()

I’ve tried calling IsPlaced() before and after the board.Add calls but they both return false. Am I missing a call that actually does the placement maybe?

Thanks

You don’t see them because you are adding empty module objects. Just because you set fpid to something will not make that object load the footprint from library, you need to create your MODULE objects using FootprintLoad(). After you loaded it once you can clone them using MODULE(anothermodule) which is a bit faster.

I tried just the following, but still no joy:

board = pcbnew.LoadBoard("E:\\Path\\To\\Board")
new_keysw = pcbnew.FootprintLoad("E:\\KiCad\\share\\kicad\\modules\\Button_Switch_Keyboard.pretty", "SW_Cherry_MX_1.00u_PCB")
board.Add(new_keysw)
pcbnew.Refresh()

Nothing changes in my open PCB window.

board = pcbnew.LoadBoard("E:\\Path\\To\\Board")
This creates new board object, it is not the same board object that pcbnew window has. That’s why changes to it will not reflect in pcbnew.
If you want to get the board object that pcbnew window has use pcbnew.GetBoard()

That was the last piece! It works! Thank you for the help. Some minor units issues but other than that I’m good!