Well, it looks like the
Leviton Evr-Green EVSE isn't going to be available for Christmas this year after all.
They've pushed their release for the
EVB22-3PM back until January with the
EVB45-3PD (the 7.6kW unit, and the one I want)
hopefully out by April, but no guarantees doesn't look to be available for another year, well after I theoretically take possession of my
LEAF. But what Chris at Leviton explained to me with respect to the 2010 EVSE tax credit was even more distressing: simply wiring the home in 2010 would not qualify for the tax credit even if the EVSE wasn't available. Zounds! So I called my
Congressman and left a message with his office to please
please please do what he can to get the EVSE tax credit extended into 2011, when most J1772-compliant EVSE equipment will finally become available to the general consumer and when EVs will finally be made available to the general public. I also asked for him to confirm the wiring restriction with respect to the tax credit. Talk about catch-22: you can have the credit for an EVSE but no EVSEs will be available until that credit expires!? I repeat, Zounds!
And here I finally got my code together to scan the
Better Business Bureau website for all the local Electrical Contractors with A+ ratings after a couple hours hacking last night, as can be seen in
this Google Spreadsheet (Note: The month index is 0-based, meaning January is 0). The code to do this had to query every sub-page of the 276 registered contractors and thus took quite a while to run, but here's the simple Python script I used to compile my data:
#!/usr/bin/python
import urllib2, sgmllib, re
data = file('BBBData.csv', 'w')
data.write('Name,Address,Area,Phone,"Join Year","Join Month"'
+ ',Rating\n')
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul',
'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
phone_pat = re.compile(r'phone:\s+\((?P\d{3})\)\s+' +
r'(?P\d{3}-\d{4})')
join_pat = re.compile(r'BBB\s+Accredited:\s+(?P' +
r'|'.join(months) +
r')\s+(?P\d{4})')
rating_pat = re.compile(r'Based on BBB files, this business '
+
r'has a BBB Rating of ([A-F][-+]?)')
class SGMLParse(sgmllib.SGMLParser):
def __init__(self, verbose=False):
sgmllib.SGMLParser.__init__(self, verbose)
self.div_depth = 0
self.stores = []
self.inentry = False
self.inname = False
self.current_name = None
self.inaddr = False
self.current_addr = None
self.current = None
self.inphone = False
self.current_join = None
self.current_phone = None
self.last_href = None
self.current_rating = None
def parse(self, text):
self.feed(text)
self.close()
def start_div(self, attributes):
self.div_depth += 1
classes = [ ]
attr = dict(attributes)
if attr.has_key('class'):
classes = attr['class'].split(' ')
if 'StdList' in classes:
self.inentry = self.div_depth
elif 'StdListName' in classes:
self.inname = self.div_depth
self.current = ''
elif 'StdListAddr' in classes:
self.inaddr = self.div_depth
self.current = ''
elif 'StdListPhone' in classes:
self.inphone = self.div_depth
self.current = ''
def end_div(self):
if self.inentry == self.div_depth:
# Collect data and append
self.stores.append({'Name': self.current_name,
'Address': self.current_addr,
'Joined': self.current_join,
'Phone': self.current_phone,
'Rating': self.current_rating
})
data.write('"'+self.current_name+'",')
data.write('"'+self.current_addr+'",')
data.write('"'+self.current_phone[0]+'",')
data.write('"'+self.current_phone[1]+'",')
data.write(''+str(self.current_join[1])+',')
data.write(''+str(self.current_join[0])+',')
data.write('"'+str(self.current_rating)+'"\n')
self.current_name = None
self.current_address = None
self.current_join = None
self.current_phone = None
self.current_rating = None
self.inentry = False
elif self.inname == self.div_depth:
self.current_name = self.current
self.current = None
self.inname = False
elif self.inaddr == self.div_depth:
self.current_addr = self.current
self.current = None
self.inaddr = False
elif self.inphone == self.div_depth:
for line in self.current.split('\n'):
match = join_pat.match(line)
if match:
self.current_join = (months.index(match.
group('month')),
int(match.
group('year')))
else:
match = phone_pat.match(line)
if match:
if self.current_phone != None:
print 'Duplicate Phone Number'
self.current_phone = (match.
group(
'area'),
match.
group('num'))
self.current = None
self.inphone = False
self.div_depth -= 1
def start_a(self, attributes):
attr = dict(attributes)
if self.inentry:
self.last_href = 'http://dc-easternpa.bbb.org/' \
+ attr['href']
self.current = ''
def end_a(self):
if self.inentry and self.current == 'BBB report':
match = rating_pat.search(urllib2.urlopen(self.
last_href).read())
if match:
self.current_rating = match.group(1)
self.current = None
self.last_href = None
def handle_data(self, data):
if self.current is not None:
self.current += data
def start_br(self, attributes):
if self.current is not None:
self.current += '\n'
def handle_entityref(self, entity):
if entity.lower() == 'nbsp' and self.current is not \
None:
self.current += ' '
return self.convert_entityref(entity)
BBBListHTML = urllib2.urlopen('http://dc-easternpa.bbb.org/'
+ 'V2RosterByTob.asp?ID=10049')
p = SGMLParse()
p.parse(''.join(BBBListHTML.readlines()))
data.close()
# p.stores contains a list of dictionaries with each store's
# data
Note: Edited for line length