diff --git a/python/pcb.py b/python/pcb.py
index 52b1d8be5757146db7739b8f178f8f73c2f00587..c1b2ec4dfbefd97dfec4e738c4c77c6dfebdcfaf 100755
--- a/python/pcb.py
+++ b/python/pcb.py
@@ -20,8 +20,8 @@
 # uncomment for desired output:
 #
 
-output = "top, labels, and exterior"
-#output = "top, labels, holes, and exterior"
+#output = "top, labels, and exterior"
+output = "top, labels, holes, and exterior"
 #output = "top, bottom, labels, and exterior"
 #output = "top, bottom, labels, holes, and exterior"
 #output = "top traces"
@@ -1190,9 +1190,198 @@ class choke(part):
 # connectors
 #
 
-class header_serial_reverse(part):
+class ESP_WROOM_02D(part):
    #
-   # serial cable header, reverse for female connector
+   # ESP-WROOM-02D
+   #
+   def __init__(self,value=''):
+      self.value = value
+      self.pad = [point(0,0,0)]
+      self.labels = []
+      pad = cube(-1/25.4,1/25.4,-.45/25.4,.45/25.4,0,0)
+      width = 17.5/25.4
+      pitch = 1.5/25.4
+      #
+      # pin 1
+      #
+      self.shape = translate(pad,-width/2,4*pitch,0)
+      self.shape = add(self.shape,cylinder(-width/2-.75/25.4,4*pitch,0,0,.45/25.4))
+      self.pad.append(point(-width/2,4*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'3V3'))
+      #
+      # pin 2
+      #
+      self.shape = add(self.shape,translate(pad,-width/2,3*pitch,0))
+      self.pad.append(point(-width/2,3*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'EN'))
+      #
+      # pin 3
+      #
+      self.shape = add(self.shape,translate(pad,-width/2,2*pitch,0))
+      self.pad.append(point(-width/2,2*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'IO14'))
+      #
+      # pin 4
+      #
+      self.shape = add(self.shape,translate(pad,-width/2,1*pitch,0))
+      self.pad.append(point(-width/2,1*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'IO12'))
+      #
+      # pin 5
+      #
+      self.shape = add(self.shape,translate(pad,-width/2,0*pitch,0))
+      self.pad.append(point(-width/2,0*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'IO13'))
+      #
+      # pin 6
+      #
+      self.shape = add(self.shape,translate(pad,-width/2,-1*pitch,0))
+      self.pad.append(point(-width/2,-1*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'IO15'))
+      #
+      # pin 7
+      #
+      self.shape = add(self.shape,translate(pad,-width/2,-2*pitch,0))
+      self.pad.append(point(-width/2,-2*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'IO2'))
+      #
+      # pin 8
+      #
+      self.shape = add(self.shape,translate(pad,-width/2,-3*pitch,0))
+      self.pad.append(point(-width/2,-3*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'IO0'))
+      #
+      # pin 9
+      #
+      self.shape = add(self.shape,translate(pad,-width/2,-4*pitch,0))
+      self.pad.append(point(-width/2,-4*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'GND'))
+      #
+      # pin 10
+      #
+      self.shape = add(self.shape,translate(pad,width/2,-4*pitch,0))
+      self.pad.append(point(width/2,-4*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'IO4'))
+      #
+      # pin 11
+      #
+      self.shape = add(self.shape,translate(pad,width/2,-3*pitch,0))
+      self.pad.append(point(width/2,-3*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'RXD'))
+      #
+      # pin 12
+      #
+      self.shape = add(self.shape,translate(pad,width/2,-2*pitch,0))
+      self.pad.append(point(width/2,-2*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'TXD'))
+      #
+      # pin 13
+      #
+      self.shape = add(self.shape,translate(pad,width/2,-1*pitch,0))
+      self.pad.append(point(width/2,-1*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'GND'))
+      #
+      # pin 14
+      #
+      self.shape = add(self.shape,translate(pad,width/2,0*pitch,0))
+      self.pad.append(point(width/2,0*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'IO5'))
+      #
+      # pin 15
+      #
+      self.shape = add(self.shape,translate(pad,width/2,1*pitch,0))
+      self.pad.append(point(width/2,1*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'RST'))
+      #
+      # pin 16
+      #
+      self.shape = add(self.shape,translate(pad,width/2,2*pitch,0))
+      self.pad.append(point(width/2,2*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'TOUT'))
+      #
+      # pin 17
+      #
+      self.shape = add(self.shape,translate(pad,width/2,3*pitch,0))
+      self.pad.append(point(width/2,3*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'IO16'))
+      #
+      # pin 18
+      #
+      self.shape = add(self.shape,translate(pad,width/2,4*pitch,0))
+      self.pad.append(point(width/2,4*pitch,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'GND'))
+      #
+      # pin 19
+      #
+      padg = cube(-2/25.4,2/25.4,-2/25.4,2/25.4,0,0)
+      self.shape = add(self.shape,translate(padg,(1.5/2+7.1+2-17.5/2)/25.4,(4*1.5+7.1-20+4.29+2)/25.4,0))
+      self.pad.append(point((1.5/2+7.1+2-17.5/2)/25.4,(4*1.5+7.1-20+4.29+2)/25.4,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'GND'))
+
+class ESP_01(part):
+   #
+   # ESP-01 4x2 vertical
+   #    Sullins NPTC042KFMS-RC	
+   #
+   def __init__(self,value=''):
+      pad_header = cube(-.075/2,.075/2,-.04/2,.04/2,0,0)
+      d = .305/2-.07/2
+      self.value = value
+      self.pad = [point(0,0,0)]
+      self.labels = []
+      #
+      # pin 1
+      #
+      self.shape = translate(pad_header,d,.15,0)
+      self.shape = add(self.shape,cylinder(d+.061/2,.15,0,0,.039/2))
+      self.pad.append(point(d,.15,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'GND'))
+      #
+      # pin 2
+      #
+      self.shape = add(self.shape,translate(pad_header,-d,.15,0))
+      self.pad.append(point(-d,.15,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'Tx'))
+      #
+      # pin 3
+      #
+      self.shape = add(self.shape,translate(pad_header,d,.05,0))
+      self.pad.append(point(d,.05,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'IO2'))
+      #
+      # pin 4
+      #
+      self.shape = add(self.shape,translate(pad_header,-d,.05,0))
+      self.pad.append(point(-d,.05,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'EN'))
+      #
+      # pin 5
+      #
+      self.shape = add(self.shape,translate(pad_header,d,-.05,0))
+      self.pad.append(point(d,-.05,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'IO0'))
+      #
+      # pin 6
+      #
+      self.shape = add(self.shape,translate(pad_header,-d,-.05,0))
+      self.pad.append(point(-d,-.05,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'RST'))
+      #
+      # pin 7
+      #
+      self.shape = add(self.shape,translate(pad_header,d,-.15,0))
+      self.pad.append(point(d,-.15,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'Rx'))
+      #
+      # pin 8
+      #
+      self.shape = add(self.shape,translate(pad_header,-d,-.15,0))
+      self.pad.append(point(-d,-.15,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'VCC'))
+
+class header_serial_reverse_5V(part):
+   #
+   # serial cable header, reverse for female connector, 5V output
    #    GCT BG300-06-A-L-A	
    #
    def __init__(self,value=''):
@@ -1217,7 +1406,54 @@ class header_serial_reverse(part):
       #
       self.shape = add(self.shape,translate(pad_header,0,-.05,0))
       self.pad.append(point(0,-.05,0))
-      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'VCC'))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'5V'))
+      #
+      # pin 4
+      #
+      self.shape = add(self.shape,translate(pad_header,0,0.05,0))
+      self.pad.append(point(0,.05,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'Tx'))
+      #
+      # pin 5
+      #
+      self.shape = add(self.shape,translate(pad_header,0,.15,0))
+      self.pad.append(point(0,.15,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'Rx'))
+      #
+      # pin 6
+      #
+      self.shape = add(self.shape,translate(pad_header,0,.25,0))
+      self.pad.append(point(0,.25,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'RTS'))
+
+class header_serial_reverse_3V3(part):
+   #
+   # serial cable header, reverse for female connector, 3.3V output
+   #    GCT BG300-06-A-L-A	
+   #
+   def __init__(self,value=''):
+      self.value = value
+      self.pad = [point(0,0,0)]
+      self.labels = []
+      #
+      # pin 1
+      #
+      self.shape = translate(pad_header,0,-.25,0)
+      self.shape = add(self.shape,cylinder(-.05,-.25,0,0,.025))
+      self.pad.append(point(0,-.25,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'GND'))
+      #
+      # pin 2
+      #
+      self.shape = add(self.shape,translate(pad_header,0,-.15,0))
+      self.pad.append(point(0,-.15,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'CTS'))
+      #
+      # pin 3
+      #
+      self.shape = add(self.shape,translate(pad_header,0,-.05,0))
+      self.pad.append(point(0,-.05,0))
+      self.labels.append(self.text(self.pad[-1].x,self.pad[-1].y,self.pad[-1].z,'3.3V'))
       #
       # pin 4
       #