Tesla is discontinuing MySolarCity.com - as message reads “Your MySolarCity.com account and MySolarCity mobile app are transitioning to Tesla.com account and Tesla mobile app on August 1, 2019”
Here is the script so far. In the light of above I’m not planing future work on it.
# Tesla is discontinuing MySolarCity.com as of August 1, 2019
# Enjoy until exists
#
# Download daily production data from mysolarcity.com at the beginning of the next day
# Download 15 min production data from mysolarcity.com and post to pvoutput.org
#
# The example installation is with 2 inverters, posts to 2 systems on pvoutput.org
#
# Requires:
# selenium for py
# Firefox (to be able to download files without UI pop-up questions)
#
# File name convention as for Windows host
#
# Task needs to be scheduled on Windows host for 15 min execution
#
# No debugging set
#
# Copyright 2019 Boby Borisov
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
import os
import time
from datetime import date, datetime, timedelta
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
import csv
import urllib.request, urllib.parse, urllib.error
# SolarCity
SC_USER = "<mysolarcity email>"
SC_PASSWORD = "<mysolarcity password>"
INSTALLATION_ID = "<mysolarcity installation id - visible when you "share" daily output>"
INVERTER={}
INVERTER[1] = "<inverter 1 id - visible in downloaded daily output file>"
INVERTER[2] = "<inverter 2 id - visible in downloaded daily output file>"
MSC_LINK1 = "https://mysolarcity.com/solarcity-api/powerguide/v1.0/installations/"
MSC_LINK2 = "/summary?StartTime="
MSC_LINK3 = ":00&EndTime="
MSC_LINK4 = ":59&Period=QuarterHour"
MSC_FILE = "\summary.csv"
# PVOutput
PVOUTPUT_ID={}
PVOUTPUT_ID[1] = "<pvoutput system ID for inverter1>"
PVOUTPUT_ID[2] = "<pvoutput system ID for inverter2>"
PVOUTPUT_KEY = "<pvoutput api write key>"
# Script Constants
SC_DATA = "C:\\solarcitydata"
SC_LOGOUT_TIMEOUT = 3
SC_LOGIN_TIMEOUT = 3
MSC_TIMEOUT = 12
PAGE_LOAD_TIMEOUT = 15
PV_STATUS = "\pv_status.csv"
# Firefox Options for downloading files
options = Options();
options.set_preference("browser.download.folderList",2)
options.set_preference("browser.download.dir", SC_DATA)
options.set_preference("browser.download.manager.showWhenStarting", False)
options.set_preference("browser.helperApps.neverAsk.saveToDisk", "text/csv")
options.headless = True
# Get 15min file from MySolarCity.com
def get_solarcity_data(time_b,time_e):
if os.path.isfile(SC_DATA+MSC_FILE):
os.remove(SC_DATA+MSC_FILE)
MSC_LINK = MSC_LINK1+INSTALLATION_ID+MSC_LINK2+time_b+MSC_LINK3+time_e+MSC_LINK4
print(MSC_LINK)
driver = webdriver.Firefox(options=options)
driver.set_page_load_timeout(PAGE_LOAD_TIMEOUT)
try:
driver.get('https://login.solarcity.com/logout')
time.sleep(SC_LOGOUT_TIMEOUT)
driver.get('https://login.solarcity.com/account/SignIn')
time.sleep(SC_LOGIN_TIMEOUT)
driver.find_element_by_id("username").clear()
driver.find_element_by_id("username").send_keys(SC_USER)
password = driver.find_element_by_id("password")
password.send_keys(SC_PASSWORD)
password.submit()
time.sleep(MSC_TIMEOUT)
driver.get(MSC_LINK)
except: pass
driver.quit()
if os.path.exists("geckodriver.log"): os.remove("geckodriver.log")
#Get Yesterday's 15min file from MySolarCity.com
yesterday = date.today() - timedelta(days=1)
if os.path.isfile(SC_DATA+"\solarcity "+yesterday.strftime("%Y%m%d")+".csv"): pass
else:
print("get yesterday's file")
get_solarcity_data(yesterday.strftime("%Y-%m-%d")+"T00:00",yesterday.strftime("%Y-%m-%d")+"T23:59")
if os.path.isfile(SC_DATA+MSC_FILE):
os.rename(SC_DATA+MSC_FILE,SC_DATA+"\solarcity "+yesterday.strftime("%Y%m%d")+".csv")
#Post live output to PVOutput.org
def post_pvoutput (d,t,v1,v6,apikey,sid):
headers = {}
headers["X-Pvoutput-Apikey"] = apikey
headers["X-Pvoutput-SystemId"] = sid
data = {}
data["d"] = d
data["t"] = t
data["v1"] = v1
data["v6"] = v6
data["c1"] = "1"
data = urllib.parse.urlencode(data).encode('utf-8')
request = urllib.request.Request('https://pvoutput.org/service/r2/addstatus.jsp', data, headers)
try:
response = urllib.request.urlopen(request)
print (sid,data,response.read())
return True
except:
print (sid,data,"Error")
return False
#Get/Post 15min production
datetimed = datetime.now() - timedelta(minutes=15)
dated = datetimed.strftime("%Y-%m-%d")
timee = datetimed.strftime("%H")+":"
minutes = int(datetimed.strftime("%M"))
if minutes < 15:
timee += "14"
else:
if minutes < 30:
timee += "29"
else:
if minutes < 45:
timee += "44"
else:
timee += "59"
timee = datetimed.strftime("%Y-%m-%d")+"T"+timee
with open(SC_DATA+PV_STATUS, 'r') as f:
csvread = csv.reader(f)
lastpvo = list(csvread)
j=1
while j < len(INVERTER)+1:
if datetimed > datetime.strptime(lastpvo[j][0]+lastpvo[j][1],"%Y%m%d%H:%M"):
datetimed = datetime.strptime(lastpvo[j][0]+lastpvo[j][1],"%Y%m%d%H:%M")
j += 1
datetimed = datetimed + timedelta(minutes=15)
timeb = datetimed.strftime("%H")+":"
minutes = int(datetimed.strftime("%M"))
if minutes < 15:
timeb += "00"
else:
if minutes < 30:
timeb += "15"
else:
if minutes < 45:
timeb += "30"
else:
timeb += "45"
timeb = datetimed.strftime("%Y-%m-%d")+"T"+timeb
if datetime.strptime(timeb,"%Y-%m-%dT%H:%M") < datetime.strptime(timee,"%Y-%m-%dT%H:%M"):
get_solarcity_data(timeb,timee)
if os.path.isfile(SC_DATA+MSC_FILE):
with open(SC_DATA+MSC_FILE, 'r') as f:
csvread = csv.reader(f)
sclist = list(csvread)
j=1
while j < len(INVERTER)+1:
i=1
while i < len(sclist):
if sclist[i][2] == INVERTER[j]:
if post_pvoutput(datetime.strftime(datetime.strptime(sclist[i][0],"%Y-%m-%dT%H:%M:%S"),"%Y%m%d"),datetime.strftime(datetime.strptime(sclist[i][0],"%Y-%m-%dT%H:%M:%S"),"%H:%M"),str(int(float(sclist[i][4])*1000)),str(int(float(sclist[2][6]))),PVOUTPUT_KEY,PVOUTPUT_ID[j]):
lastpvo[j][0] = datetime.strftime(datetime.strptime(sclist[i][0],"%Y-%m-%dT%H:%M:%S"),"%Y%m%d")
lastpvo[j][1] = datetime.strftime(datetime.strptime(sclist[i][0],"%Y-%m-%dT%H:%M:%S"),"%H:%M")
else:
i = len(sclist)
i += 1
print(INVERTER[j],lastpvo[j])
j += 1
else:
print ("no 15min file")
f = open(SC_DATA+PV_STATUS, 'w')
j=0
while j < len(INVERTER)+1:
f.write(lastpvo[j][0]+","+lastpvo[j][1]+"\n")
j += 1
f.close()
else:
print (timeb,timee, "15min not passed yet")