예제 #1
0
def report_yesterday(data):
    # Report on yesterdays mileage/efficiency
    t = datetime.date.today()
    today_ts = t.strftime("%Y%m%d")
    t = t + datetime.timedelta(days=-1)
    yesterday_ts = t.strftime("%Y%m%d")
    if today_ts not in data["daily_state_am"] or yesterday_ts not in data[
            "daily_state_am"]:
        logT.debug("Skipping yesterday tweet due to missing items")
        m = None
        pic = None
    else:
        miles_driven = data["daily_state_am"][today_ts]["odometer"] - data[
            "daily_state_am"][yesterday_ts]["odometer"]
        kw_used = data["daily_state_am"][today_ts]["charge_energy_added"]
        if miles_driven > 200:
            m = "Yesterday I drove my #Tesla %s miles on a road trip! " \
                "@Teslamotors #bot" % ("{:,}".format(int(miles_driven)))
        elif miles_driven == 0:
            mileage = data["daily_state_am"][today_ts]["odometer"]
            today_ym = datetime.date.today()
            start_ym = datetime.date(2014, 4, 21)
            ownership_months = int((today_ym - start_ym).days / 30)
            m = "Yesterday my #Tesla had a day off. Current mileage is %s miles after %d months " \
                "@Teslamotors #bot" % ("{:,}".format(int(mileage)), ownership_months)
        elif data["day_charges"] == 0 or data["day_charges"] > 1:
            # Need to skip efficiency stuff here if car didnt charge last night or we charged more than once
            # TODO: Could save prior efficiency from last charge and use that
            day = yesterday_ts
            time_value = time.mktime(
                time.strptime("%s2100" % day, "%Y%m%d%H%M"))
            w = get_daytime_weather_data(logT, time_value)
            m = "Yesterday I drove my #Tesla %s miles. Avg temp %.0fF. " \
                "@Teslamotors #bot" \
                % ("{:,}".format(int(miles_driven)), w["avg_temp"])
        else:
            # Drove a distance and charged exactly once since last report, we have enough data
            # to report efficiency.
            day = yesterday_ts
            time_value = time.mktime(
                time.strptime("%s2100" % day, "%Y%m%d%H%M"))
            w = get_daytime_weather_data(logT, time_value)
            efficiency = kw_used * 1000 / miles_driven
            # If efficiency isnt a reasonable number then don't report it.
            # Example, drive somewhere and don't charge -- efficiency is zero.
            # Or drive somewhere, charge at SC, then do normal charge - efficiency will look too high.
            if kw_used > 0 and efficiency > 200 and efficiency < 700:
                m = "Yesterday I drove my #Tesla %s miles using %.1f kWh with an effic. of %d Wh/mi. Avg temp %.0fF. " \
                    "@Teslamotors #bot" \
                    % ("{:,}".format(int(miles_driven)), kw_used, efficiency, w["avg_temp"])
            else:
                m = "Yesterday I drove my #Tesla %s miles. Avg temp %.0fF. " \
                    "@Teslamotors #bot" % ("{:,}".format(int(miles_driven)), w["avg_temp"])
        pic = os.path.abspath(random.choice(get_pics()))
    return m, pic
예제 #2
0
def analyze_weather(data):
    """
    SolarCity has had outages where they cant provide the cloud cover/weather information.
    This compares SolarCity reported weather data with other weather data.
    """
    for day in sorted(data['data']):
        d = data['data'][day]
        if "weather_api" not in d:
            time_value = time.mktime(time.strptime("%s2100" % day, "%Y%m%d%H%M"))
            w = get_daytime_weather_data(log, time_value)
            cloud_cover = w["cloud_cover"]
            daylight_hours = w["daylight"]
            if 'cloud' in d:
                ss_cloud = d['cloud']
            else:
                ss_cloud = 0
            if 'daylight' in d:
                ss_daylight = d['daylight']
            else:
                ss_daylight = 0

            print "%s Cloud: %d%% Daylight: %.1f (API Cloud: %d%%, Daylight: %.1f)" % (day, ss_cloud,
                                                                                       ss_daylight, cloud_cover,
                                                                                       daylight_hours)
        else:
            if 'cloud' in d:
                cloud_cover = d['cloud']
            else:
                cloud_cover = 0
            if 'daylight' in d:
                daylight_hours = d['daylight']
            else:
                daylight_hours = 0
            print "%s API Cloud: %d%% API Daylight: %.1f" % (day, cloud_cover, daylight_hours)
예제 #3
0
def get_solarguard_day_data(day=None):
    append = ''
    if day:
        append = '&ChartDate=%d_%d_%d' % (day.month, day.day, day.year)
    r = requests.get(SOLARGUARD_URL + append)
    soup = BeautifulSoup(r.text, features="html.parser")

    daylight_hours = 0
    cloud_cover = 0

    production = float(soup.find(id='ctl00_cphMain_lbProdTotalByChart').text)

    if not day and production == 0 and cloud_cover == 0 and daylight_hours == 0:
        raise Exception(
            "Problem getting current production level: %.1f, %d, %.1f" %
            (production, cloud_cover, daylight_hours))

    if daylight_hours == 0:
        """
        SolarCity has had outages where they cant provide the cloud cover/weather information.
        If the weather data appears empty here, we'll go get it from another source
        """
        if day:
            ts = datetime.datetime.combine(
                day, datetime.datetime.max.time()).strftime("%s")
        else:
            ts = time.time()
        w = get_daytime_weather_data(log, ts)
        cloud_cover = w["cloud_cover"]
        daylight_hours = w["daylight"]

    return daylight_hours, cloud_cover, production
예제 #4
0
def get_day_data(day=None):
    append = ''
    if day:
        append = '?date=%d-%02d-%02d' % (day.year, day.month, day.day)

    chrome_options = Options()
    chrome_options.add_argument("--headless")
    driver = webdriver.Chrome(options=chrome_options)
    driver.get(SOLARCITY_URL)
    time.sleep(10)
    driver.get(SOLARCITY_URL + append)
    time.sleep(10)
    data = driver.find_element(By.CSS_SELECTOR,
                               "div.consumption-production-panel").text
    if data and len(data.split()) > 0:
        production = float(data.split()[0])
    else:
        production = 0

    if day:
        ts = datetime.datetime.combine(
            day, datetime.datetime.max.time()).strftime("%s")
    else:
        ts = time.time()
    w = get_daytime_weather_data(log, ts)
    cloud_cover = w["cloud_cover"]
    daylight_hours = w["daylight"]

    # If we get here everything worked, shut down the browser
    driver.quit()

    if os.path.exists("geckodriver.log"):
        os.remove("geckodriver.log")

    return daylight_hours, cloud_cover, production
예제 #5
0
파일: tesla.py 프로젝트: Ninotna/evtools
def report_yesterday(data):
    # Report on yesterdays mileage/efficiency
    t = datetime.date.today()
    today_ts = t.strftime("%Y%m%d")
    t = t + datetime.timedelta(days=-1)
    yesterday_ts = t.strftime("%Y%m%d")
    if today_ts not in data["daily_state_am"] or yesterday_ts not in data["daily_state_am"]:
        logT.debug("Skipping yesterday tweet due to missing items")
    else:
        miles_driven = data["daily_state_am"][today_ts]["odometer"] - data["daily_state_am"][yesterday_ts][
            "odometer"]
        kw_used = data["daily_state_am"][today_ts]["charge_energy_added"]
        if miles_driven > 200:
            m = "Yesterday I drove my #Tesla %s miles on a road trip! " \
                "@Teslamotors #bot" % ("{:,}".format(int(miles_driven)))
        elif miles_driven == 0:
            mileage = data["daily_state_am"][today_ts]["odometer"]
            today_ym = datetime.date.today()
            start_ym = datetime.date(2014, 4, 21)
            ownership_months = int((today_ym - start_ym).days / 30)
            m = "Yesterday my #Tesla had a day off. Current mileage is %s miles after %d months " \
                "@Teslamotors #bot" % ("{:,}".format(int(mileage)), ownership_months)
        elif False:  # not is_plugged_in(c, CAR_NAME):
            # Need to skip efficiency stuff here if car didnt charge last night
            day = yesterday_ts
            time_value = time.mktime(time.strptime("%s2100" % day, "%Y%m%d%H%M"))
            w = get_daytime_weather_data(logT, time_value)
            m = "Yesterday I drove my #Tesla %s miles. Avg temp %.1fF. " \
                "@Teslamotors #bot" \
                % ("{:,}".format(int(miles_driven)), w["avg_temp"])
        else:
            day = yesterday_ts
            time_value = time.mktime(time.strptime("%s2100" % day, "%Y%m%d%H%M"))
            w = get_daytime_weather_data(logT, time_value)
            m = "Yesterday I drove my #Tesla %s miles using %.1f kWh with an effic. of %d Wh/mi. Avg temp %.1fF. " \
                "@Teslamotors #bot" \
                % ("{:,}".format(int(miles_driven)), kw_used, kw_used * 1000 / miles_driven, w["avg_temp"])
        pic = os.path.abspath(random.choice(get_pics()))
    return m, pic
예제 #6
0
def upload_to_pvoutput(data, day):
    # Get pvoutput.org login information from environment
    if 'PVOUTPUT_ID' not in os.environ:
        raise Exception("PVOUTPUT_ID missing")
    else:
        pvoutput_id = os.environ['PVOUTPUT_ID']
    if 'PVOUTPUT_KEY' not in os.environ:
        raise Exception("PVOUTPUT_KEY missing")
    else:
        pvoutput_key = os.environ['PVOUTPUT_KEY']

    log.debug("Report weather info to pvoutput.org for %s", day)

    time_value = time.mktime(time.strptime("%s2100" % day, "%Y%m%d%H%M"))
    w = get_daytime_weather_data(log, time_value)

    short_description = "Not Sure"
    if "partly cloudy" in w["description"].lower():
        short_description = "Partly Cloudy"
    if "mostly cloudy" in w["description"].lower():
        short_description = "Mostly Cloudy"
    elif "snow" in w["description"].lower():
        short_description = "Snow"
    elif "rain" in w["description"].lower():
        short_description = "Showers"
    elif "clear" in w["description"].lower():
        short_description = "Fine"

    pvdata = {}
    pvdata["d"] = day
    pvdata["g"] = data["data"][day]["production"] * 1000
    pvdata["cd"] = short_description
    pvdata["tm"] = "%.1f" % ((w["low_temp"] - 32) * 5.0 / 9.0)
    pvdata["tx"] = "%.1f" % ((w["high_temp"] - 32) * 5.0 / 9.0)
    pvdata["cm"] = "Daylight hours: %.1f, Cloud cover: %d%%" % (
        data["data"][day]["daylight"], data["data"][day]["cloud"])
    data = urllib.parse.urlencode(pvdata)

    headers = {}
    headers["X-Pvoutput-Apikey"] = pvoutput_key
    headers["X-Pvoutput-SystemId"] = pvoutput_id

    req = urllib.request.Request(
        "http://pvoutput.org/service/r2/addoutput.jsp", data.encode('utf-8'),
        headers)
    response = urllib.request.urlopen(req)
    output = response.read()
    log.debug("   Upload response: %s", output)
예제 #7
0
def upload_to_pvoutput(data, day):
    # Get pvoutput.org login information from environment
    if 'PVOUTPUT_ID' not in os.environ:
        raise Exception("PVOUTPUT_ID missing")
    else:
        pvoutput_id = os.environ['PVOUTPUT_ID']
    if 'PVOUTPUT_KEY' not in os.environ:
        raise Exception("PVOUTPUT_KEY missing")
    else:
        pvoutput_key = os.environ['PVOUTPUT_KEY']

    log.debug("Report weather info to pvoutput.org for %s", day)

    time_value = time.mktime(time.strptime("%s2100" % day, "%Y%m%d%H%M"))
    w = get_daytime_weather_data(log, time_value)

    short_description = "Not Sure"
    if "partly cloudy" in w["description"].lower():
        short_description = "Partly Cloudy"
    if "mostly cloudy" in w["description"].lower():
        short_description = "Mostly Cloudy"
    elif "snow" in w["description"].lower():
        short_description = "Snow"
    elif "rain" in w["description"].lower():
        short_description = "Showers"
    elif "clear" in w["description"].lower():
        short_description = "Fine"

    pvdata = {}
    pvdata["d"] = day
    pvdata["g"] = data["data"][day]["production"] * 1000
    pvdata["cd"] = short_description
    pvdata["tm"] = "%.1f" % ((w["low_temp"] - 32) * 5.0 / 9.0)
    pvdata["tx"] = "%.1f" % ((w["high_temp"] - 32) * 5.0 / 9.0)
    pvdata["cm"] = "Daylight hours: %.1f, Cloud cover: %d%%" % (data["data"][day]["daylight"],
                                                                data["data"][day]["cloud"])
    data = urllib.urlencode(pvdata)

    headers = {}
    headers["X-Pvoutput-Apikey"] = pvoutput_key
    headers["X-Pvoutput-SystemId"] = pvoutput_id

    req = urllib2.Request("http://pvoutput.org/service/r2/addoutput.jsp", data, headers)
    response = urllib2.urlopen(req)
    output = response.read()
    log.debug("   Upload response: %s", output)
예제 #8
0
def main():
    parser = argparse.ArgumentParser(description='Show sunday weather start of current (or passed) year to today')
    parser.add_argument('--year', help='Starting year (YYYY)', required=False,
                        default=datetime.datetime.now().year, type=int)
    args = parser.parse_args()

    t = datetime.datetime.strptime("%04d01012100" % args.year, "%Y%m%d%H%M")
    current_year = t.year
    print "date,avg temp,low temp,cloud cover,precip type,precip probability"
    while t.year == current_year and t < datetime.datetime.now():
        ts = "%04d%02d%02d" % (t.year, t.month, t.day)
        if t.weekday() == 6:
            w = get_daytime_weather_data(logging, time.mktime(t.timetuple()))
            print "%s,%.1f,%.1f,%d%%,%s,%d%%" % (ts, w["avg_temp"], w["low_temp"], w["cloud_cover"],
                                                 w["precip_type"], w["precip_probability"])

        t = t + datetime.timedelta(days=1)
예제 #9
0
def main():
    parser = argparse.ArgumentParser(
        description=
        'Show sunday weather start of current (or passed) year to today')
    parser.add_argument('--year',
                        help='Starting year (YYYY)',
                        required=False,
                        default=datetime.datetime.now().year,
                        type=int)
    args = parser.parse_args()

    t = datetime.datetime.strptime("%04d01012100" % args.year, "%Y%m%d%H%M")
    current_year = t.year
    print("date,avg temp,low temp,cloud cover,precip type,precip probability")
    while t.year == current_year and t < datetime.datetime.now():
        ts = "%04d%02d%02d" % (t.year, t.month, t.day)
        if t.weekday() == 6:
            w = get_daytime_weather_data(logging, time.mktime(t.timetuple()))
            print("%s,%.1f,%.1f,%d%%,%s,%d%%" %
                  (ts, w["avg_temp"], w["low_temp"], w["cloud_cover"],
                   w["precip_type"], w["precip_probability"]))

        t = t + datetime.timedelta(days=1)
예제 #10
0
def analyze_weather(data):
    """
    SolarCity has had outages where they cant provide the cloud cover/weather information.
    This compares SolarCity reported weather data with other weather data.
    """
    for day in sorted(data['data']):
        d = data['data'][day]
        if "weather_api" not in d:
            time_value = time.mktime(
                time.strptime("%s2100" % day, "%Y%m%d%H%M"))
            w = get_daytime_weather_data(log, time_value)
            cloud_cover = w["cloud_cover"]
            daylight_hours = w["daylight"]
            if 'cloud' in d:
                ss_cloud = d['cloud']
            else:
                ss_cloud = 0
            if 'daylight' in d:
                ss_daylight = d['daylight']
            else:
                ss_daylight = 0

            print(
                "%s Cloud: %d%% Daylight: %.1f (API Cloud: %d%%, Daylight: %.1f)"
                % (day, ss_cloud, ss_daylight, cloud_cover, daylight_hours))
        else:
            if 'cloud' in d:
                cloud_cover = d['cloud']
            else:
                cloud_cover = 0
            if 'daylight' in d:
                daylight_hours = d['daylight']
            else:
                daylight_hours = 0
            print("%s API Cloud: %d%% API Daylight: %.1f" %
                  (day, cloud_cover, daylight_hours))
예제 #11
0
def main():
    parser = argparse.ArgumentParser(description='SolarCity Reporting')
    parser.add_argument('--no_email',
                        help='Dont send emails',
                        required=False,
                        action='store_true')
    parser.add_argument('--force',
                        help='Force update',
                        required=False,
                        action='store_true')
    parser.add_argument('--no_tweet',
                        help='Dont post tweets',
                        required=False,
                        action='store_true')
    parser.add_argument('--report',
                        help='Generate report',
                        required=False,
                        action='store_true')
    parser.add_argument('--blog',
                        help='Generate html report page',
                        required=False,
                        action='store_true')
    parser.add_argument('--daily',
                        help='Report on daily generation',
                        required=False,
                        action='store_true')
    parser.add_argument('--monthly',
                        help='Report on monthly generation',
                        required=False,
                        action='store_true')
    parser.add_argument('--yearly',
                        help='Report on yearly generation',
                        required=False,
                        action='store_true')
    parser.add_argument('--weather',
                        help='Report weather for given date (YYYYMMDD)',
                        required=False,
                        type=str)
    parser.add_argument('--pvoutput',
                        help="Send data for date (YYYYMMDD) to PVOutput.org",
                        required=False,
                        type=str)
    args = parser.parse_args()

    # Make sure we only run one instance at a time
    fp = open('/tmp/solarcity.lock', 'w')
    try:
        fcntl.flock(fp.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
    except:
        log.debug(
            "Sorry, someone else is running this tool right now. Please try again later"
        )
        return -1

    log.debug("--- solarcity.py start ---")

    data = load_data()
    data_changed = False

    data = load_historical_data(data)
    production_max, production_min, total_generation = analyze_data(data)

    if args.monthly:
        # First check if its last day of the month
        log.debug("Check for monthly update")
        now = datetime.datetime.now()
        dow, last_day = calendar.monthrange(now.year, now.month)
        log.debug("Last day of month: %d. Current day: %d", last_day, now.day)
        if last_day == now.day:
            log.debug("   Last day of month.")
            current_month = time.strftime("%Y%m")
            if 'lastmonthlytweet' not in data['config'] or data['config'][
                    'lastmonthlytweet'] != current_month:
                tweet_month(data)
                data['config']['lastmonthlytweet'] = current_month
                data_changed = True
        else:
            log.debug("   Not last day of month, skipping. ")

    if args.yearly:
        # First check if its last day of the year
        log.debug("Check for annual update")
        now = datetime.datetime.now()
        if now.month == 12:
            dow, last_day = calendar.monthrange(now.year, now.month)
            log.debug("Last day of month: %d. Current day: %d", last_day,
                      now.day)
            if last_day == now.day:
                log.debug("   Last day of year.")
                current_month = time.strftime("%Y%m")
                if 'lastyearlytweet' not in data['config'] or data['config'][
                        'lastyearlytweet'] != current_month:
                    tweet_year(data)
                    data['config']['lastyearlytweet'] = current_month
                    data_changed = True
            else:
                log.debug("   Not last day of year, skipping. ")

    if args.weather is not None:
        log.debug("Check weather data")
        if int(args.weather) == 0:
            time_value = int(time.time())
        else:
            time_value = time.mktime(
                time.strptime("%s2100" % args.weather, "%Y%m%d%H%M"))
        w = get_daytime_weather_data(log, time_value)
        print("Weather as of %s:" %
              datetime.datetime.fromtimestamp(time_value))
        print("   Average temperature: %.1fF" % w["avg_temp"])
        print("   Low temperature: %.1fF" % w["low_temp"])
        print("   Cloud Cover: %d%%" % w["cloud_cover"])
        print("   Daylight hours: %.1f" % w["daylight"])
        print("   Description: %s" % w["description"])
        print("   Precipitation type: %s" % w["precip_type"])
        print("   Precipitation Chance: %d%%" % w["precip_probability"])
        # analyze_weather(data)

    if args.daily:
        log.debug("Check for daily update")
        current_day = time.strftime("%Y%m%d")
        if data['config'][
                'lastdailytweet'] != current_day or DEBUG_MODE or args.force:
            daylight_hours, cloud_cover, production = get_current_day_data()
            data['data'][current_day] = {
                'daylight': daylight_hours,
                'cloud': cloud_cover,
                'production': production
            }
            special = None
            if production_max is None or production > data['data'][
                    production_max]['production']:
                special = "high"
            elif production_min is None or production < data['data'][
                    production_min]['production']:
                special = "low"
            if not args.no_tweet:
                tweet_production(daylight_hours, cloud_cover, production,
                                 special)
                data['config']['lastdailytweet'] = current_day
            data_changed = True
            if args.pvoutput is not None:
                # Now upload to pvoutput
                upload_to_pvoutput(data, current_day)

    elif args.pvoutput is not None:
        if int(args.pvoutput) == 0:
            print("Uploading historical data to pvoutput.org")
            for d in data["data"]:
                print("   Processing date %s" % d)
                try:
                    upload_to_pvoutput(data, d)
                except:
                    print("      problem with date %s" % d)
                print("      Sleeping")
                # You'll need longer sleeps if you didnt donate
                time.sleep(15)
        else:
            upload_to_pvoutput(data, args.pvoutput)

    if args.report:
        # Send/Run weekly solarcity summary report
        solarcity_report(data, args.no_email, args.no_tweet)

    if args.blog:
        # Export all entries found for posting to static page on blog: teslaliving.net/solarcity
        log.debug("Reporting on SolarCity generation for blog")
        print(
            '<a href="http://share.solarcity.com/teslaliving">@SolarCity</a> Solar Installation'
        )
        print('<h3>System Results</h3>')
        print("<b>%s total power generated via @SolarCity as of %s</b>" %
              (show_with_units(total_generation), time.strftime("%Y%m%d")))
        print("%s day max on %s" % (show_with_units(
            data['data'][production_max]['production']), production_max))
        print("%s day min on %s" % (show_with_units(
            data['data'][production_min]['production']), production_min))
        print("<b>%s daily average production</b>" %
              (show_with_units(total_generation / len(data['data']))))
        print('<h3>System Details</h3>')
        print("System size is 69 panels at 255W each = %.1fkW" % (69 * .255))
        r = relativedelta(datetime.datetime.now(),
                          datetime.datetime.strptime("2015-02-23", '%Y-%m-%d'))
        elapsed_months = r.years * 12 + r.months
        print("System was turned on February 23, 2015 (%d months ago)" %
              elapsed_months)
        print("Panel info: ")
        print("* Size: 1638 x 982 x 40mm (64.5 x 38.7 x 1.57in)")
        print(
            "* Vendor: <a href='http://www.canadiansolar.com/solar-panels/cs6p-p.html'>CanadianSolar CS6P-P</a>"
        )
        print("Inverter info: ")
        print(
            "* <a href='http://www.solaredge.com/sites/default/files/se-single-phase-us-inverter-datasheet.pdf'>SolarEdge SE6000A</a>"
        )
        print(" ")
        print(
            'Sign up for <a href="http://share.solarcity.com/teslaliving">SolarCity</a> and save on electric!'
        )

        print(
            '<h3>Chart via <a href="http://pvoutput.org/list.jsp?id=48753&sid=44393">PVOutput</a></h3>[hoops name="pvoutput"]'
        )
        print('<h3>Daily Log:</h3>')
        print("%s%s%s&nbsp;&nbsp;%s&nbsp;&nbsp;%s" %
              ("Date", "&nbsp;" * 11, "Production", "Daylight", "Cloud Cover"))
        d = data['data']
        for e in sorted(d, reverse=True):
            production = d[e]['production']
            if 'daylight' in d[e] and d[e]['daylight'] > 0:
                daylight = d[e]['daylight']
                if 'cloud' in d[e]:
                    cloud = d[e]['cloud']
                else:
                    cloud = 0
            else:
                w = get_daytime_weather_data(
                    log, time.mktime(time.strptime("%s2100" % e,
                                                   "%Y%m%d%H%M")))
                d[e]['daylight'] = w['daylight']
                daylight = w['daylight']
                d[e]['weather_api'] = True
                d[e]['cloud'] = w['cloud_cover']
                cloud = w['cloud_cover']
                d[e]['weather_api'] = True
                data_changed = True

            if production is not None and daylight is not None and cloud is not None:
                print('%s' % e, '&nbsp;&nbsp;&nbsp;&nbsp;%s&nbsp;%.1f hrs&nbsp;%d%%' % \
                                (show_with_units(production), daylight, cloud))
            else:
                print(
                    '%s' % e,
                    '&nbsp;&nbsp;&nbsp;&nbsp;%s' % show_with_units(production))

        print(
            '\nSign up for <a href="http://share.solarcity.com/teslaliving">SolarCity</a> and save on electric!'
        )
        print(
            '\nFollow <a href="https://twitter.com/teslaliving">@TeslaLiving</a>.'
        )
        print('\n<ul>')
        print(
            '<li><i>Note 1: Detailed generation tracking started 20150612.</i></li>'
        )
        print('<li><i>Note 2: Cloud/Daylight data <a href="http://forecast.io">Powered by Forecast</a> when ' \
              'SolarCity data missing.</i></li>')
        print(
            '<li><i>Note 3: System was degraded from 20170530 to 20170726. Up to 30 panels offline.</i></li>'
        )
        print('</ul>')

    if data_changed:
        save_data(data)

    log.debug("--- solarcity.py end ---")
예제 #12
0
def get_current_day_data():
    driver = webdriver.Chrome()
    driver.implicitly_wait(30)

    try:
        driver.get('https://login.solarcity.com/logout')
    except:
        pass

    time.sleep(10)
    driver.get(AUTH_URL)
    time.sleep(10)
    driver.find_element_by_id("username").send_keys(SOLARCITY_USER)
    password = driver.find_element_by_id("password")
    password.send_keys(SOLARCITY_PASSWORD)
    password.submit()
    time.sleep(10)
    driver.find_element_by_xpath(
        "//div[@id='HomeCtrlView']/div[2]/div/div/a").click()

    production = 0
    daylight_hours = 0
    cloud_cover = 0
    loops = 1

    while loops > 0:
        time.sleep(10)

        data = driver.find_element_by_css_selector(
            "div.consumption-production-panel").text
        data += driver.find_element_by_css_selector(
            "div.details-panel.pure-g").text
        log.debug("raw data: %r", data)

        fields = data.split("\n")

        for f in fields:
            if f.find("hrs") != -1:
                try:
                    daylight_hours = float(f.split()[0])
                    continue
                except:
                    pass
            if f.find(" %") != -1:
                try:
                    cloud_cover = int(f.split()[0])
                    continue
                except:
                    pass
            if f.find("kWh") != -1:
                try:
                    production = float(f.split()[0])
                    continue
                except:
                    pass

        if production != 0:
            break
        loops -= 1

    if float(production) == 0 and cloud_cover == 0 and daylight_hours == 0:
        raise Exception(
            "Problem getting current production level: %.1f, %d, %.1f" %
            (production, cloud_cover, daylight_hours))

    if daylight_hours == 0:
        """
        SolarCity has had outages where they cant provide the cloud cover/weather information.
        If the weather data appears empty here, we'll go get it from another source
        """
        w = get_daytime_weather_data(log, time.time())
        cloud_cover = w["cloud_cover"]
        daylight_hours = w["daylight"]

    try:
        driver.find_element_by_xpath(
            "//ul[@id='mysc-nav']/li[18]/a/span").click()
    except:
        pass
    time.sleep(2)

    # If we get here everything worked, shut down the browser
    driver.quit()

    if os.path.exists("geckodriver.log"):
        os.remove("geckodriver.log")

    return daylight_hours, cloud_cover, production
예제 #13
0
def main():
    parser = argparse.ArgumentParser(description='SolarCity Reporting')
    parser.add_argument('--no_email', help='Dont send emails', required=False, action='store_true')
    parser.add_argument('--force', help='Force update', required=False, action='store_true')
    parser.add_argument('--no_tweet', help='Dont post tweets', required=False, action='store_true')
    parser.add_argument('--report', help='Generate report', required=False, action='store_true')
    parser.add_argument('--blog', help='Generate html report page', required=False, action='store_true')
    parser.add_argument('--stocktweet', help='Tweet current SolarCity stock price', required=False, action='store_true')
    parser.add_argument('--daily', help='Report on daily generation', required=False, action='store_true')
    parser.add_argument('--monthly', help='Report on monthly generation', required=False, action='store_true')
    parser.add_argument('--yearly', help='Report on yearly generation', required=False, action='store_true')
    parser.add_argument('--weather', help='Report weather for given date (YYYYMMDD)', required=False, type=str)
    parser.add_argument('--pvoutput', help="Send data for date (YYYYMMDD) to PVOutput.org", required=False, type=str)
    args = parser.parse_args()

    if args.stocktweet:
        quote = get_stock_quote(stock='SCTY', log=log)
        if quote and not DEBUG_MODE:
            tweet_price(price=quote, log=log, stock='SCTY', extra='http://share.solarcity.com/teslaliving #GoSolar',
                        image="images/TeslalivingLogo.jpg")
        elif quote:
            print "Would tweet price: $%s" % quote
        return

    # Make sure we only run one instance at a time
    fp = open('/tmp/solarcity.lock', 'w')
    try:
        fcntl.flock(fp.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
    except:
        log.debug("Sorry, someone else is running this tool right now. Please try again later")
        return -1

    log.debug("--- solarcity.py start ---")

    data = load_data()
    data_changed = False

    data = load_historical_data(data)
    production_max, production_min, total_generation = analyze_data(data)

    if args.monthly:
        # First check if its last day of the month
        log.debug("Check for monthly update")
        now = datetime.datetime.now()
        dow, last_day = calendar.monthrange(now.year, now.month)
        log.debug("Last day of month: %d. Current day: %d", last_day, now.day)
        if last_day == now.day:
            log.debug("   Last day of month.")
            current_month = time.strftime("%Y%m")
            if 'lastmonthlytweet' not in data['config'] or data['config']['lastmonthlytweet'] != current_month:
                tweet_month(data)
                data['config']['lastmonthlytweet'] = current_month
                data_changed = True
        else:
            log.debug("   Not last day of month, skipping. ")

    if args.yearly:
        # First check if its last day of the year
        log.debug("Check for annual update")
        now = datetime.datetime.now()
        if now.month == 12:
            dow, last_day = calendar.monthrange(now.year, now.month)
            log.debug("Last day of month: %d. Current day: %d", last_day, now.day)
            if last_day == now.day:
                log.debug("   Last day of year.")
                current_month = time.strftime("%Y%m")
                if 'lastyearlytweet' not in data['config'] or data['config']['lastyearlytweet'] != current_month:
                    tweet_year(data)
                    data['config']['lastyearlytweet'] = current_month
                    data_changed = True
            else:
                log.debug("   Not last day of year, skipping. ")

    if args.weather is not None:
        log.debug("Check weather data")
        if int(args.weather) == 0:
            time_value = int(time.time())
        else:
            time_value = time.mktime(time.strptime("%s2100" % args.weather, "%Y%m%d%H%M"))
        w = get_daytime_weather_data(log, time_value)
        print "Weather as of %s:" % datetime.datetime.fromtimestamp(time_value)
        print "   Average temperature: %.1fF" % w["avg_temp"]
        print "   Low temperature: %.1fF" % w["low_temp"]
        print "   Cloud Cover: %d%%" % w["cloud_cover"]
        print "   Daylight hours: %.1f" % w["daylight"]
        print "   Description: %s" % w["description"]
        print "   Precipitation type: %s" % w["precip_type"]
        print "   Precipitation Chance: %d%%" % w["precip_probability"]
        # analyze_weather(data)

    if args.pvoutput is not None:
        if int(args.pvoutput) == 0:
            print "Uploading historical data to pvoutput.org"
            for d in data["data"]:
                print "   Processing date %s" % d
                try:
                    upload_to_pvoutput(data, d)
                except:
                    print "      problem with date %s" % d
                print "      Sleeping"
                # You'll need longer sleeps if you didnt donate
                time.sleep(15)
        else:
            upload_to_pvoutput(data, args.pvoutput)

    if args.daily:
        log.debug("Check for daily update")
        current_day = time.strftime("%Y%m%d")
        if data['config']['lastdailytweet'] != current_day or DEBUG_MODE or args.force:
            daylight_hours, cloud_cover, production = get_current_day_data()
            data['data'][current_day] = {'daylight': daylight_hours, 'cloud': cloud_cover, 'production': production}
            special = None
            if production > data['data'][production_max]['production']:
                special = "high"
            if production < data['data'][production_min]['production']:
                special = "low"
            tweet_production(daylight_hours, cloud_cover, production, special)
            data['config']['lastdailytweet'] = current_day
            data_changed = True
            # Now upload to pvoutput
            upload_to_pvoutput(data, current_day)

    if args.report:
        # Send/Run weekly solarcity summary report
        solarcity_report(data, args.no_email, args.no_tweet)

    if args.blog:
        # Export all entries found for posting to static page on blog: teslaliving.net/solarcity
        log.debug("Reporting on SolarCity generation for blog")
        print "@SolarCity system size is 69 panels at 255W each = %s" % show_with_units(69 * .255)
        print "%s total power generated via @SolarCity as of %s" % (show_with_units(total_generation),
                                                                    time.strftime("%Y%m%d"))
        print "%s day max on %s" % (show_with_units(data['data'][production_max]['production']), production_max)
        print "%s day min on %s" % (show_with_units(data['data'][production_min]['production']), production_min)
        print "%s average production" % (show_with_units(total_generation / len(data['data'])))
        print 'Sign up for <a href="http://share.solarcity.com/teslaliving">SolarCity</a> and save on electric!'

        print "\n"
        print "%s%s%s&nbsp;&nbsp;%s&nbsp;&nbsp;%s" % ("Date", "&nbsp;" * 11, "Production", "Daylight", "Cloud Cover")
        d = data['data']
        for e in sorted(d, reverse=True):
            production = d[e]['production']
            if 'daylight' in d[e] and d[e]['daylight'] > 0:
                daylight = d[e]['daylight']
                if 'cloud' in d[e]:
                    cloud = d[e]['cloud']
                else:
                    cloud = 0
            else:
                w = get_daytime_weather_data(log, time.mktime(time.strptime("%s2100" % e, "%Y%m%d%H%M")))
                d[e]['daylight'] = w['daylight']
                daylight = w['daylight']
                d[e]['weather_api'] = True
                d[e]['cloud'] = w['cloud_cover']
                cloud = w['cloud_cover']
                d[e]['weather_api'] = True
                data_changed = True

            if production is not None and daylight is not None and cloud is not None:
                print '%s' % e, '&nbsp;&nbsp;&nbsp;&nbsp;%s&nbsp;%.1f hrs&nbsp;%d%%' % \
                                (show_with_units(production), daylight, cloud)
            else:
                print '%s' % e, '&nbsp;&nbsp;&nbsp;&nbsp;%s' % show_with_units(production)

        print '\nSign up for <a href="http://share.solarcity.com/teslaliving">SolarCity</a> and save on electric!'
        print '\nFollow <a href="https://twitter.com/teslaliving">@TeslaLiving</a>.'
        print '\n<ul>'
        print '<li><i>Note 1: Detailed generation tracking started 20150612.</i></li>'
        print '<li><i>Note 2: Cloud/Daylight data <a href="http://forecast.io">Powered by Forecast</a> when ' \
              'SolarCity data missing.</i></li>'
        print '</ul>'
        print '<a href="https://gratipay.com/teslaliving/"><img src="//img.shields.io/gratipay/teslaliving.svg"></a>'

    if data_changed:
        save_data(data)

    log.debug("--- solarcity.py end ---")
예제 #14
0
def get_current_day_data():
    display = Display(visible=0, size=(800, 600))
    display.start()
#    options = Options()
#    options.set_headless(headless=True)
#    driver = webdriver.Firefox(firefox_options=options, executable_path='/usr/local/bin/geckodriver')
    #binary = FirefoxBinary('/usr/local/geckodriver')
    driver = webdriver.Firefox(executable_path='/usr/local/bin/geckodriver') 


    driver.implicitly_wait(30)
#    print("Invoked")
#    driver.get('http://google.com')
    try:
        driver.get('https://login.solarcity.com/logout')
    except:
        pass
   # print driver.title
    time.sleep(10)
    driver.get(AUTH_URL)
   # print driver.title
    time.sleep(10)
   # print os.environ["SOLARCITY_USER"]
   # print SOLARCITYUSER
    driver.find_element_by_id("username").send_keys(SOLARCITYUSER)
    password = driver.find_element_by_id("password")
    password.send_keys(SOLARCITYPASSWORD)
    password.submit()
    time.sleep(10)
    driver.find_element_by_xpath("//div[@id='HomeCtrlView']/div[2]/div/div/a").click()

    production = 0
    daylight_hours = 0
    cloud_cover = 0
    loops = 1
   # print driver.title
    while loops > 0:
        time.sleep(10)

        data = driver.find_element_by_css_selector("div.consumption-production-panel").text
        data += driver.find_element_by_css_selector("div.details-panel.pure-g").text
        log.debug("raw data: %r", data)

        fields = data.split("\n")

        for f in fields:
            if f.find("hrs") != -1:
                try:
                    daylight_hours = float(f.split()[0])
                    continue
                except:
                    pass
            if f.find(" %") != -1:
                try:
                    cloud_cover = int(f.split()[0])
                    continue
                except:
                    pass
            if f.find("kWh") != -1:
                try:
                    production = float(f.split()[0])
                    continue
                except:
                    pass

        if production != 0:
            break
        loops -= 1

    if float(production) == 0 and cloud_cover == 0 and daylight_hours == 0:
        raise Exception("Problem getting current production level: %.1f, %d, %.1f" % (production,
                                                                                      cloud_cover, daylight_hours))

    if daylight_hours == 0:
        """
        SolarCity has had outages where they cant provide the cloud cover/weather information.
        If the weather data appears empty here, we'll go get it from another source
        """
        w = get_daytime_weather_data(log, time.time())
        cloud_cover = w["cloud_cover"]
        daylight_hours = w["daylight"]

    try:
        driver.find_element_by_xpath("//ul[@id='mysc-nav']/li[18]/a/span").click()
    except:
        pass
    time.sleep(2)

    # If we get here everything worked, shut down the browser
    driver.quit()
    display.stop()
    #print 'Success'

    return daylight_hours, cloud_cover, production
예제 #15
0
def get_current_day_data():
    seleniumHost = 'localhost'
    seleniumPort = str(4444)
    browserStartCommand = "*firefox"
    browserURL = "https://*****:*****@id='HomeCtrlView']/div[2]/div/div/a")

    production = 0
    daylight_hours = 0
    cloud_cover = 0
    loops = 1

    while loops > 0:
        time.sleep(10)

        data = s.get_text("css=div.consumption-production-panel")
        data += s.get_text("css=div.details-panel.pure-g")  # hist-summary.pure-g"
        log.debug("raw data: %r", data)

        fields = data.split("\n\n")

        for f in fields:
            if f.find("daylight") != -1:
                for o in f.split():
                    try:
                        daylight_hours = float(o)
                        break
                    except:
                        pass
            if f.find("cloud cover") != -1:
                for o in f.split():
                    try:
                        cloud_cover = int(o)
                        break
                    except:
                        pass
            if f.find("produced") != -1:
                for o in f.split():
                    try:
                        production = float(o)
                        break
                    except:
                        pass

        if production != 0:
            break
        loops -= 1

    if float(production) == 0 and cloud_cover == 0 and daylight_hours == 0:
        raise Exception("Problem getting current production level")

    if daylight_hours == 0:
        """
        SolarCity has had outages where they cant provide the cloud cover/weather information.
        If the weather data appears empty here, we'll go get it from another source
        """
        w = get_daytime_weather_data(log, time.time())
        cloud_cover = w["cloud_cover"]
        daylight_hours = w["daylight"]

    try:
        s.click("//ul[@id='mysc-nav']/li[18]/a/span")
    except:
        pass
    time.sleep(2)

    # If we get here everything worked, shut down the browser
    s.stop()

    return daylight_hours, cloud_cover, production
예제 #16
0
파일: tesla.py 프로젝트: benlaurie/evtools
def main():
    parser = argparse.ArgumentParser(description='Tesla Control')
    parser.add_argument('--status', help='Get car status', required=False, action='store_true')
    parser.add_argument('--mileage', help='Check car mileage and tweet as it crosses 1,000 mile marks', required=False, action='store_true')
    parser.add_argument('--state', help='Record car state', required=False, action='store_true')
    parser.add_argument('--pluggedin', help='Check if car is plugged in', required=False, action='store_true')
    parser.add_argument('--dump', help='Dump all fields/data', required=False, action='store_true')
    parser.add_argument('--fields', help='Check for newly added API fields', required=False, action='store_true')
    parser.add_argument('--day', help='Show state data for given day', required=False, type=str)
    parser.add_argument('--yesterday', help='Report on yesterdays driving', required=False, action='store_true')
    parser.add_argument('--export', help='Export data', required=False, action='store_true')
    parser.add_argument('--report', help='Produce summary report', required=False, action='store_true')
    parser.add_argument('--garage', help='Trigger garage door (experimental)', required=False, action='store_true')
    parser.add_argument('--sunroof', help='Control sunroof (vent, open, close)', required=False, type=str)
    args = parser.parse_args()

    # Make sure we only run one instance at a time
    blocked = True
    while blocked:
        fp = open('/tmp/tesla.lock', 'w')
        try:
            fcntl.flock(fp.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
            blocked = False
        except:
            logT.debug("Someone else is running this tool right now. Sleeping")
            time.sleep(30)

    logT.debug("--- tesla.py start ---")

    data = load_data()
    data_changed = False

    # Get a connection to the car and manage access token
    if 'token' in data:
        token = data['token']
    else:
        token = None
    try:
        c = establish_connection(token)
    except:
        logT.debug("Problems establishing connection")
        c = establish_connection()

    if c.access_token:
        if not 'token' in data or data['token'] != c.access_token:
            data['token'] = c.access_token
            data_changed = True

    if args.status:
        # Dump current Tesla status
        print dump_current_tesla_status(c)

    elif args.dump:
        # Dump all of Tesla API state information to disk
        logT.debug("Dumping current Tesla state")
        t = datetime.date.today()
        ts = t.strftime("%Y%m%d")
        m = dump_current_tesla_status(c)
        open(os.path.join(DUMP_DIR, "tesla_state_%s.txt" % ts), "w").write(m)

    elif args.fields:
        # Check for new Tesla API fields and report if any found
        logT.debug("Checking Tesla API fields")
        data_changed, data = check_tesla_fields(c, data)

    elif args.mileage:
        # Tweet mileage as it crosses 1,000 mile marks
        m = get_odometer(c, CAR_NAME)
        if "mileage_tweet" not in data:
            data["mileage_tweet"] = 0
        if int(m / 1000) > int(data["mileage_tweet"] / 1000):
            tweet_major_mileage(int(m / 1000) * 1000)
            data["mileage_tweet"] = m
            data_changed = True

    elif args.state:
        # Save current Tesla state information
        logT.debug("Saving Tesla state")
        s = get_current_state(c, CAR_NAME)
        t = datetime.date.today()
        ts = t.strftime("%Y%m%d")
        hour = datetime.datetime.now().hour
        if hour < 12:
            ampm = "am"
        else:
            ampm = "pm"
        data["daily_state_%s" % ampm][ts] = s
        data_changed = True

    elif args.day:
        # Show Tesla state information from a given day
        ts = args.day
        if ts in data["daily_state_am"]:
            print "Data for %s am:" % ts
            for i in ("odometer", "soc", "ideal_range", "rated_range", "estimated_range", "charge_energy_added",
                      "charge_miles_added_ideal", "charge_miles_added_rated"):
                print "%s: %s" % (i, data["daily_state_am"][ts][i])

    elif args.report:
        # Show total and average energy added
        total_energy_added = 0
        for ts in data["daily_state_am"]:
            if ts < "20151030":
                continue
            total_energy_added += data["daily_state_am"][ts]["charge_energy_added"]
        print "Total Energy Added: %s kW" % "{:,.2f}".format(total_energy_added)
        print "Average Energy Added: %s kW" % "{:,.2f}".format((total_energy_added / len(data["daily_state_am"])))

    elif args.export:
        # Export all saved Tesla state information
        for ts in sorted(data["daily_state_am"]):
            if ts < "20151030":
                continue
            print "%s," % ts,
            for i in ("odometer", "soc", "ideal_range", "rated_range", "estimated_range", "charge_energy_added",
                      "charge_miles_added_ideal", "charge_miles_added_rated"):
                print "%s," % data["daily_state_am"][ts][i],
            print ""

    elif args.pluggedin:
        # Check if the Tesla is plugged in and alert if not
        logT.debug("Checking if Tesla is plugged in")
        if not is_plugged_in(c, CAR_NAME):
            s = get_current_state(c, CAR_NAME, include_temps=False)
            message = "Your car is not plugged in.\n\n"
            message += "Current battery level is %d%%. (%d estimated miles)" % (s["soc"], int(s["estimated_range"]))
            message += "\n\nRegards,\nRob"
            email(email=TESLA_EMAIL, message=message, subject="Your Tesla isn't plugged in")

    elif args.yesterday:
        # Report on yesterdays mileage/efficiency
        t = datetime.date.today()
        today_ts = t.strftime("%Y%m%d")
        t = t + datetime.timedelta(days=-1)
        yesterday_ts = t.strftime("%Y%m%d")
        if today_ts not in data["daily_state_am"] or yesterday_ts not in data["daily_state_am"]:
            logT.debug("Skipping yesterday tweet due to missing items")
        else:
            miles_driven = data["daily_state_am"][today_ts]["odometer"] - data["daily_state_am"][yesterday_ts][
                "odometer"]
            kw_used = data["daily_state_am"][today_ts]["charge_energy_added"]
            if miles_driven > 200:
                m = "Yesterday I drove my #Tesla %s miles on a road trip! " \
                    "@Teslamotors #bot" % ("{:,}".format(int(miles_driven)))
            elif miles_driven == 0:
                mileage = data["daily_state_am"][today_ts]["odometer"]
                today_ym = datetime.date.today()
                start_ym = datetime.date(2014, 4, 21)
                ownership_months = int((today_ym - start_ym).days / 30)
                m = "Yesterday my #Tesla had a day off. Current mileage is %s miles after %d months " \
                    "@Teslamotors #bot" % ("{:,}".format(int(mileage)), ownership_months)
            else:
                day = yesterday_ts
                time_value = time.mktime(time.strptime("%s2100" % day, "%Y%m%d%H%M"))
                w = get_daytime_weather_data(logT, time_value)
                m = "Yesterday I drove my #Tesla %s miles using %.1f kW with an effic. of %d Wh/mi. Avg temp %.1fF. " \
                    "@Teslamotors #bot" \
                    % ("{:,}".format(int(miles_driven)), kw_used, kw_used * 1000 / miles_driven, w["avg_temp"])
            pic = random.choice(get_pics())
            if DEBUG_MODE:
                print "Would tweet:\n%s with pic: %s" % (m, pic)
                logT.debug("DEBUG mode, not tweeting: %s with pic: %s", m, pic)
            else:
                logT.info("Tweeting: %s with pic: %s", m, pic)
                tweet_string(message=m, log=logT, media=pic)

    elif args.garage:
        # Open garage door (experimental as I dont have an AP car)
        trigger_garage_door(c, CAR_NAME)

    elif args.sunroof:
        # Change sunroof state
        trigger_sunroof(c, CAR_NAME, args.sunroof)

    if data_changed:
        save_data(data)
    logT.debug("--- tesla.py end ---")
예제 #17
0
def main():
    parser = argparse.ArgumentParser(description='SolarCity Reporting')
    parser.add_argument('--no_email', help='Dont send emails', required=False, action='store_true')
    parser.add_argument('--force', help='Force update', required=False, action='store_true')
    parser.add_argument('--no_tweet', help='Dont post tweets', required=False, action='store_true')
    parser.add_argument('--report', help='Generate report', required=False, action='store_true')
    parser.add_argument('--blog', help='Generate html report page', required=False, action='store_true')
    parser.add_argument('--stocktweet', help='Tweet current SolarCity stock price', required=False, action='store_true')
    parser.add_argument('--daily', help='Report on daily generation', required=False, action='store_true')
    parser.add_argument('--monthly', help='Report on monthly generation', required=False, action='store_true')
    parser.add_argument('--yearly', help='Report on yearly generation', required=False, action='store_true')
    parser.add_argument('--weather', help='Report weather for given date (YYYYMMDD)', required=False, type=str)
    parser.add_argument('--pvoutput', help="Send data for date (YYYYMMDD) to PVOutput.org", required=False, type=str)
    args = parser.parse_args()
    dbconnecting()
    if args.stocktweet:
        quote = get_stock_quote(stock='SCTY', log=log)
        if quote and not DEBUG_MODE:
            tweet_price(price=quote, log=log, stock='SCTY', extra='http://share.solarcity.com/teslaliving #GoSolar',
                        image="images/TeslalivingLogo.jpg")
        elif quote:
            print "Would tweet price: $%s" % quote
        return

    # Make sure we only run one instance at a time
    fp = open('/tmp/solarcity.lock', 'w')
    try:
        fcntl.flock(fp.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
    except:
        log.debug("Sorry, someone else is running this tool right now. Please try again later")
        return -1

    log.debug("--- solarcity.py start ---")

    data = load_data()
    data_changed = False

    data = load_historical_data(data)
    production_max, production_min, total_generation = analyze_data(data)

    if args.monthly:
        # First check if its last day of the month
        log.debug("Check for monthly update")
        now = datetime.datetime.now()
        dow, last_day = calendar.monthrange(now.year, now.month)
        log.debug("Last day of month: %d. Current day: %d", last_day, now.day)
        if last_day == now.day:
            log.debug("   Last day of month.")
            current_month = time.strftime("%Y%m")
            if 'lastmonthlytweet' not in data['config'] or data['config']['lastmonthlytweet'] != current_month:
                tweet_month(data)
                data['config']['lastmonthlytweet'] = current_month
                data_changed = True
        else:
            log.debug("   Not last day of month, skipping. ")

    if args.yearly:
        # First check if its last day of the year
        log.debug("Check for annual update")
        now = datetime.datetime.now()
        if now.month == 12:
            dow, last_day = calendar.monthrange(now.year, now.month)
            log.debug("Last day of month: %d. Current day: %d", last_day, now.day)
            if last_day == now.day:
                log.debug("   Last day of year.")
                current_month = time.strftime("%Y%m")
                if 'lastyearlytweet' not in data['config'] or data['config']['lastyearlytweet'] != current_month:
                    tweet_year(data)
                    data['config']['lastyearlytweet'] = current_month
                    data_changed = True
            else:
                log.debug("   Not last day of year, skipping. ")

    if args.weather is not None:
        log.debug("Check weather data")
        if int(args.weather) == 0:
            time_value = int(time.time())
        else:
            time_value = time.mktime(time.strptime("%s2100" % args.weather, "%Y%m%d%H%M"))
        w = get_daytime_weather_data(log, time_value)
        print "Weather as of %s:" % datetime.datetime.fromtimestamp(time_value)
        print "   Average temperature: %.1fF" % w["avg_temp"]
        print "   Low temperature: %.1fF" % w["low_temp"]
        print "   Cloud Cover: %d%%" % w["cloud_cover"]
        print "   Daylight hours: %.1f" % w["daylight"]
        print "   Description: %s" % w["description"]
        print "   Precipitation type: %s" % w["precip_type"]
        print "   Precipitation Chance: %d%%" % w["precip_probability"]
        # analyze_weather(data)

    if args.pvoutput is not None:
        if int(args.pvoutput) == 0:
            print "Uploading historical data to pvoutput.org"
            for d in data["data"]:
                print "   Processing date %s" % d
                try:
                    upload_to_pvoutput(data, d)
                except:
                    print "      problem with date %s" % d
                print "      Sleeping"
                # You'll need longer sleeps if you didnt donate
                time.sleep(15)
        else:
            upload_to_pvoutput(data, args.pvoutput)

    if args.daily:
        log.debug("Check for daily update")
        current_day = time.strftime("%Y%m%d")
        if data['config']['lastdailytweet'] != current_day or DEBUG_MODE or args.force:
            daylight_hours, cloud_cover, production = get_current_day_data()
            data['data'][current_day] = {'daylight': daylight_hours, 'cloud': cloud_cover, 'production': production}
            try:
                curs.execute ("INSERT INTO production values("+current_day+","+str(production)+","+str(daylight_hours)+","+str(cloud_cover)+")")
                db.commit()
                log.debug("Sent daily production to database")
            except Exception as exp:
                log.debug(str(exp))
                db.rollback()
            special = None
            if production > data['data'][production_max]['production']:
                special = "high"
            if production < data['data'][production_min]['production']:
                special = "low"
#            tweet_production(daylight_hours, cloud_cover, production, special)
            data['config']['lastdailytweet'] = current_day
            data_changed = True
            # Now upload to pvoutput
#            upload_to_pvoutput(data, current_day)

    if args.report:
        # Send/Run weekly solarcity summary report
        solarcity_report(data, args.no_email, args.no_tweet)
	print data[0]
    if args.blog:
        # Export all entries found for posting to static page on blog: teslaliving.net/solarcity
        log.debug("Reporting on SolarCity generation for blog")
        print '<a href="http://share.solarcity.com/teslaliving">@SolarCity</a> Solar Installation'
        print '<h3>System Results</h3>'
        print "<b>%s total power generated via @SolarCity as of %s</b>" % (show_with_units(total_generation),
                                                                    time.strftime("%Y%m%d"))
        print "%s day max on %s" % (show_with_units(data['data'][production_max]['production']), production_max)
        print "%s day min on %s" % (show_with_units(data['data'][production_min]['production']), production_min)
        print "<b>%s daily average production</b>" % (show_with_units(total_generation / len(data['data'])))
        print '<h3>System Details</h3>'
        print "System size is 69 panels at 255W each = %.1fkW" % (69 * .255)
        r = relativedelta(datetime.datetime.now(), datetime.datetime.strptime("2015-02-23", '%Y-%m-%d'))
        elapsed_months = r.years * 12 + r.months
        print "System was turned on February 23, 2015 (%d months ago)" % elapsed_months
        print "Panel info: "
        print "* Size: 1638 x 982 x 40mm (64.5 x 38.7 x 1.57in)"
        print "* Vendor: <a href='http://www.canadiansolar.com/solar-panels/cs6p-p.html'>CanadianSolar CS6P-P</a>"
        print "Inverter info: "
        print "* <a href='http://www.solaredge.com/sites/default/files/se-single-phase-us-inverter-datasheet.pdf'>SolarEdge SE6000A</a>"
        print " "
        print 'Sign up for <a href="http://share.solarcity.com/teslaliving">SolarCity</a> and save on electric!'

        print '<h3>Chart via <a href="http://pvoutput.org/list.jsp?id=48753&sid=44393">PVOutput</a></h3>[hoops name="pvoutput"]'
        print '<h3>Daily Log:</h3>'
        print "%s%s%s&nbsp;&nbsp;%s&nbsp;&nbsp;%s" % ("Date", "&nbsp;" * 11, "Production", "Daylight", "Cloud Cover")
        d = data['data']
        for e in sorted(d, reverse=True):
            production = d[e]['production']
            if 'daylight' in d[e] and d[e]['daylight'] > 0:
                daylight = d[e]['daylight']
                if 'cloud' in d[e]:
                    cloud = d[e]['cloud']
                else:
                    cloud = 0
            else:
                w = get_daytime_weather_data(log, time.mktime(time.strptime("%s2100" % e, "%Y%m%d%H%M")))
                d[e]['daylight'] = w['daylight']
                daylight = w['daylight']
                d[e]['weather_api'] = True
                d[e]['cloud'] = w['cloud_cover']
                cloud = w['cloud_cover']
                d[e]['weather_api'] = True
                data_changed = True

            if production is not None and daylight is not None and cloud is not None:
                print '%s' % e, '&nbsp;&nbsp;&nbsp;&nbsp;%s&nbsp;%.1f hrs&nbsp;%d%%' % \
                                (show_with_units(production), daylight, cloud)
            else:
                print '%s' % e, '&nbsp;&nbsp;&nbsp;&nbsp;%s' % show_with_units(production)

        print '\nSign up for <a href="http://share.solarcity.com/teslaliving">SolarCity</a> and save on electric!'
        print '\nFollow <a href="https://twitter.com/teslaliving">@TeslaLiving</a>.'
        print '\n<ul>'
        print '<li><i>Note 1: Detailed generation tracking started 20150612.</i></li>'
        print '<li><i>Note 2: Cloud/Daylight data <a href="http://forecast.io">Powered by Forecast</a> when ' \
              'SolarCity data missing.</i></li>'
        print '<li><i>Note 3: System was degraded from 20170530 to 20170726. Up to 30 panels offline.</i></li>'
        print '</ul>'

    if data_changed:
        save_data(data)

    log.debug("--- solarcity.py end ---")