async def async_setup_entry(hass, entry, async_add_entities): """Add an solarEdge entry.""" # Add the needed sensors to hass api = solaredge.Solaredge(entry.data[CONF_API_KEY]) # Check if api can be reached and site is active try: response = await hass.async_add_executor_job(api.get_details, entry.data[CONF_SITE_ID]) if response["details"]["status"].lower() != "active": _LOGGER.error("SolarEdge site is not active") return _LOGGER.debug("Credentials correct and site is active") except KeyError as ex: _LOGGER.error("Missing details data in SolarEdge response") raise ConfigEntryNotReady from ex except (ConnectTimeout, HTTPError) as ex: _LOGGER.error("Could not retrieve details from SolarEdge API") raise ConfigEntryNotReady from ex sensor_factory = SolarEdgeSensorFactory(hass, entry.title, entry.data[CONF_SITE_ID], api) for service in sensor_factory.all_services: service.async_setup() await service.coordinator.async_refresh() entities = [] for sensor_key in SENSOR_TYPES: sensor = sensor_factory.create_sensor(sensor_key) if sensor is not None: entities.append(sensor) async_add_entities(entities)
def __init__(self, cfg, monitor_id, time_zone, activation_time): self.site_id = monitor_id self.activationTime = activation_time key = cfg.get("solaredge", "key") self.client = solaredge.Solaredge(key) # thus far, there appears to be no need to make use of this, but we at least ensure the field is there # in case this turns out not to be the case self.time_zone = time_zone self.query_period = pd.Timedelta(31, 'D')
def se(apikey,site_id,starttime,endtime): timestamp = int(round(time.time())) energy = float('nan') s = solaredge.Solaredge(apikey) try: r = s.get_energy_details(site_id, starttime, endtime) except: print("Unexpected error accessing SolarEdge portal:", sys.exc_info()[0]) raise for meter in r['energyDetails']['meters']: print(meter['type']) for value in meter['values']: timestamp = int(time.mktime(time.strptime(value["date"], time_pattern))) print('Update Graphite: {} {} {}'.format(meter['type'],value['value'],timestamp)) write_graphite('pv.solaredge',timestamp,value['value'],meter['type'],'raspy.fritz.box')
def se_hourly(apikey, site_id, ghost, prefix='pv.solaredge.production'): timestamp = int(round(time.time())) today = 0 s = solaredge.Solaredge(apikey) try: r = s.get_overview(site_id) except: print("Unexpected error accessing SolarEdge portal:", sys.exc_info()[0]) raise o = r["overview"] timestamp = int( time.mktime(time.strptime(o["lastUpdateTime"], time_pattern))) today = o['lastDayData']['energy'] write_graphite(prefix, timestamp, today, 'today', ghost)
def _check_site(self, site_id: str, api_key: str) -> bool: """Check if we can connect to the soleredge api service.""" api = solaredge.Solaredge(api_key) try: response = api.get_details(site_id) if response["details"]["status"].lower() != "active": self._errors[CONF_SITE_ID] = "site_not_active" return False except (ConnectTimeout, HTTPError): self._errors[CONF_SITE_ID] = "could_not_connect" return False except KeyError: self._errors[CONF_SITE_ID] = "invalid_api_key" return False return True
def se_daily(apikey, site_id, ghost, prefix='pv.solaredge.production'): timestamp = int(round(time.time())) energy = float('nan') s = solaredge.Solaredge(apikey) try: r = s.get_overview(site_id) except: print("Unexpected error accessing SolarEdge portal:", sys.exc_info()[0]) raise o = r["overview"] timestamp = int( time.mktime(time.strptime(o["lastUpdateTime"], time_pattern))) energy = o["lifeTimeData"]["energy"] #print("Lifetime: {} Wh".format(energy)) write_graphite(prefix, timestamp, energy, 'total', ghost)
def get_SE_values(): print('SE') timestamp = int(round(time.time())) energy = float('nan') power = 0 s = solaredge.Solaredge(apikey) try: r = s.get_overview(site_id) except: print("Unexpected error accessing SolarEdge portal:", sys.exc_info()[0]) raise o = r["overview"] timestamp = int(time.mktime(time.strptime(o["lastUpdateTime"], time_pattern))) energy = o["lifeTimeData"]["energy"] power = o["currentPower"]["power"] today = o['lastDayData']['energy'] print("Current: {} W, Today: {} Wh, Lifetime: {} Wh".format(power, today, energy)) write_graphite(timestamp,energy,'Produktion') write_graphite(timestamp,power,'Power') write_graphite(timestamp,today,'Today')
def is_valid(self): if not super().is_valid(): return False # when setting a SolarEdge equipment then API key and Site ID are required if self.cleaned_data['equipment_type'] == 'SOLAREDGE': se_err = False if 'solaredge_api_key' not in self.cleaned_data or not self.cleaned_data[ 'solaredge_api_key']: self.add_error('solaredge_api_key', 'Required') se_err = True if 'solaredge_site_id' not in self.cleaned_data or not self.cleaned_data[ 'solaredge_site_id']: self.add_error('solaredge_site_id', 'Required') se_err = True # make sure the API works try: se = solaredge.Solaredge( self.cleaned_data['solaredge_api_key']) se.get_overview(self.cleaned_data['solaredge_site_id']) except HTTPError as e: # Need to check its an 404, 503, 500, 403 etc. logger.exception(e) se_err = True status_code = e.response.status_code if status_code == 403: self.add_error('solaredge_api_key', 'Invalid API Key') if status_code == 400: self.add_error('solaredge_site_id', 'Invalid Site ID') except Exception as e: logger.exception(e) self.add_error('solaredge_api_key', 'Check API Key') self.add_error('solaredge_site_id', 'Check Site ID') self.add_error( None, 'SolarEdge {} check the API Key and Site ID are correct.'. format(e)) se_err = True if se_err: return False return True
def setup_platform(hass, config, add_entities, discovery_info=None): """Create the SolarEdge Monitoring API sensor.""" import solaredge api_key = config[CONF_API_KEY] site_id = config[CONF_SITE_ID] platform_name = config[CONF_NAME] # Create new SolarEdge object to retrieve data api = solaredge.Solaredge(api_key) # Check if api can be reached and site is active try: response = api.get_details(site_id) if response['details']['status'].lower() != 'active': _LOGGER.error("SolarEdge site is not active") return _LOGGER.debug("Credentials correct and site is active") except KeyError: _LOGGER.error("Missing details data in solaredge response") return except (ConnectTimeout, HTTPError): _LOGGER.error("Could not retrieve details from SolarEdge API") return # Create sensor factory that will create sensors based on sensor_key. sensor_factory = SolarEdgeSensorFactory(platform_name, site_id, api) # Create a new sensor for each sensor type. entities = [] for sensor_key in config[CONF_MONITORED_CONDITIONS]: sensor = sensor_factory.create_sensor(sensor_key) if sensor is not None: entities.append(sensor) add_entities(entities, True)
def is_valid(self): if not super().is_valid(): return False # when setting a SolarEdge equipment then API key and Site ID are required entity_id = self.cleaned_data['entity_id'] ses = SolarEdgeSetting.objects.get(entity_id=entity_id) api_key = self.cleaned_data['api_key'] site_id = self.cleaned_data['site_id'] logger.info('Got api_key %s and site_id %s', api_key, site_id) # because api_key is masked, compare it to the original if not api_key or MaskedTextInput.mask_value(ses.api_key) == api_key: logger.info('api_key was unchanged') api_key = ses.api_key # make sure the API works try: se = solaredge.Solaredge(api_key) se.get_overview(site_id) except HTTPError as e: # Need to check its an 404, 503, 500, 403 etc. logger.exception(e) status_code = e.response.status_code if status_code == 403: self.add_error('api_key', 'Invalid API Key') if status_code == 400: self.add_error('site_id', 'Invalid Site ID') return False except Exception as e: logger.exception(e) self.add_error('api_key', 'Check API Key') self.add_error('site_id', 'Check Site ID') self.add_error( None, 'SolarEdge {} check the API Key and Site ID are correct.'. format(e)) return False return True
if args.graphite_pre: graphite_pre = args.graphite_pre if args.graphite_port: graphite_port = args.graphite_port if args.apikey: apikey = args.apikey if args.site_id: site_id = args.site_id r = None if args.null: timestamp = int(round(time.time())) energy = float('nan') power = 0 else: s = solaredge.Solaredge(apikey) try: r = s.get_overview(site_id) cur = s.get_details(site_id) en = s.get_power(site_id, '2020-01-01 00:00:00', '2020-01-02 00:00:00') except: print("Unexpected error accessing SolarEdge portal:", sys.exc_info()[0]) raise o = r["overview"] timestamp = int( time.mktime(time.strptime(o["lastUpdateTime"], time_pattern))) energy = o["lifeTimeData"]["energy"] power = o["currentPower"]["power"] # DEBUG:
import solaredge as se from utilities import * # API access key = se.Solaredge("CS5RR480J372BS75DYBOWCX2JSIGEFKQ") # Choose data end date end_date = '2019-02-28' # List of all sites of interest site_ids = [ 655402, 655467, 410977, 605351, 672695, 520043, 558809, 644207, 852227, 295363, 460596, 322405, 424625, 417624, 658334, 598654 ] # Check what is already stored site_ids = check_data(site_ids, end_date) # Pull data and consolidate df = consolidate_data(key, site_ids, end_date) # Save data to disk save_data(df)
def setUp(self): self.s = solaredge.Solaredge(self.site_token) self.startDate = '2019-10-23 00:00:00' #self.startDate = '2019-10-28 16:30:00' self.endDate = '2019-11-22 18:45:00'
def fetch_solaredge_for_equipment(kwargs): progress_observer = kwargs.pop('progress_observer', None) entity_id = kwargs.get('entity_id') user = kwargs.get('user') description = kwargs.get('description') if progress_observer: progress_observer.set_progress( 1, 5, description='Connecting to SolarEdge ...') se = solaredge.Solaredge(kwargs['solaredge_api_key']) se_details = se.get_details(kwargs['solaredge_site_id']).get('details') if not description: description = se_details.get('name') # extract some fields we will need to display later se_uris = se_details.get('uris') if se_uris: se_img = se_uris.get('SITE_IMAGE') if se_img: # avoid cryptic errors on misconfiguration utils.check_boto_config() # note the image will require the api_key parameter img_url = 'https://monitoringapi.solaredge.com' + se_img url = img_url + '?api_key=' + kwargs['solaredge_api_key'] try: logger.info('Downloading image %s', url) if progress_observer: progress_observer.set_progress( 2, 5, description='Downloading data from SolarEdge ...') r = requests.get(url) with tempfile.TemporaryFile() as temp, tempfile.TemporaryFile( ) as temp2: if progress_observer: progress_observer.set_progress( 3, 5, description='Processing data from SolarEdge ...') ses = SolarEdgeSetting.objects.get(entity_id=entity_id) meter = Meter.objects.get(meter_id=entity_id) file_name = se_img.split('/')[-1] logger.info('Saving image %s', file_name) n = temp.write(r.content) logger.info('Saved temp %s', n) n = temp2.write(r.content) logger.info('Saving temp2 %s', n) file_obj = File(temp, name=file_name) site_image = FilerFile.objects.create( owner=user, original_filename=file_name, file=file_obj) # note: auto thumbnail would take twice as long to generate so do it here if progress_observer: progress_observer.set_progress( 4, 5, description= 'Generating thumbnail from SolarEdge ...') th = get_thumbnailer(temp2, relative_name=file_name) th_img = th.get_thumbnail({ 'size': (250, 250), 'crop': True }) file_obj2 = File(th_img, name=file_name) site_thumbnail = FilerFile.objects.create( owner=user, original_filename=file_name, file=file_obj2) ses.site_details = se_details ses.site_image = site_image ses.site_thumbnail = site_thumbnail ses.save() meter.description = 'SolarEdge: {}'.format( se_details.get('name')) meter.save() if progress_observer: progress_observer.set_progress(5, 5, description='Done.') except Exception as e: logger.exception(e) raise e return ses
def save(self, commit=True): meter = self.cleaned_data['meter'] time_unit = self.cleaned_data['time_unit'] from_date = self.cleaned_data['from_date'] to_date = self.cleaned_data['to_date'] import_errors = False count = 0 m = Meter.objects.get(meter_id=meter) se_setting = m.solaredgesetting_set.first() logger.info('Getting SolarEdge power details for site: %s', se_setting.site_id) se = solaredge.Solaredge(se_setting.api_key) start = from_date.strftime("%Y-%m-%d %H:%M:%S") end = to_date.strftime("%Y-%m-%d %H:%M:%S") logger.info( 'Getting SolarEdge power details for site: %s from %s to %s with time interval %s', se_setting.site_id, start, end, time_unit) # get the site timezone tz_str = None site_location = se_setting.site_details.get('location') if site_location and 'timeZone' in site_location: tz_str = site_location['timeZone'] tz = utils.parse_timezone(tz_str, 'UTC') from_date = from_date.replace(tzinfo=tz) to_date = to_date.replace(tzinfo=tz) res = se.get_energy_details(se_setting.site_id, start, end, time_unit=time_unit) logger.info('Got SolarEdge power details: %s', res) se_meters = res['energyDetails']['meters'] unit = res['energyDetails']['unit'] # find the proper UOM, this contains the code uom = UnitOfMeasure.objects.get(code=unit, type='energy') # duration is from the time time_unit = res['energyDetails']['timeUnit'] if time_unit == 'HOUR': duration = 3600 elif time_unit == 'QUARTER_OF_AN_HOUR': duration = 900 elif time_unit == 'DAY': duration = 86400 else: import_errors = 'Returned timeUnit not recognized: {}.'.format( time_unit) if not import_errors and len(se_meters) > 1: import_errors = 'Returned data has more than one SolarEdge meter, not sure what to do.' if not import_errors: # clear old values for the same period MeterHistory.objects.filter(meter=m, as_of_datetime__gte=from_date, as_of_datetime__lte=to_date).delete() se_values = se_meters[0]['values'] for item in se_values: value = item.get('value') if not value: value = 0 date_str = item.get('date') item_date = datetime.fromisoformat(date_str).replace(tzinfo=tz) MeterHistory.objects.create(meter=m, uom=uom, source='SolarEdge: {}'.format( se_setting.site_id), value=value, duration=duration, as_of_datetime=item_date, created_by_user=self.user) count = count + 1 if count == 0: import_errors = 'Nothing to Import' if import_errors: return {'import_errors': import_errors} else: return {'imported': count}
def __init__(self, api_key, site_id): self.__solarEdge = solaredge.Solaredge(api_key) self.__data = self.__solarEdge.get_overview(site_id)
import time from datetime import date, datetime, timedelta import dateutil.parser import threading from threading import Thread from solaredge_API import solaredge # Load Background Job Interval from Configuration. Else --> set to 3min bkgInterval = getattr(settings, 'BKG_INTERVAL', (3 * 60)) # Load SolarEdge API Key and API Site ID from Configuration. Else --> set to None APIKEY = getattr(settings, 'SEDGE_APIKEY', None) APIID = getattr(settings, 'SEDGE_SITEID', None) # Load SolarEdge API solE = solaredge.Solaredge(APIKEY) # TODO: Change weather API to OpenWeather API # Load worldweatheronline.com API Key and Configuration weatherAPIKEY = "cdb9121d690f43aca7a110709191801" weatherAPILocation = "Meilen" weatherAPIForecastDays = str(7) weatherAPIURL = "http://api.worldweatheronline.com/premium/v1/weather.ashx?key=" + weatherAPIKEY + "&q=" + weatherAPILocation + "&format=json&num_of_days=" + weatherAPIForecastDays # returns Solar Edge Overview def getSolEdgeOverview(): try: api_adr_site_overview = 'https://monitoringapi.solaredge.com/site/' + APIID + '/overview?api_key=' + APIKEY api_res_site_overview = requests.get(api_adr_site_overview).json() except:
light_ip = "192.168.20.78" # max power difference # value in kW that is considered max in terms of the colour scales # i.e if it's set to 4 then drawing 4kW from the grid is the top # of the scale, anything above that makes the light flame. # Likewise if we're putting 4kW from PV back into the grid then # that is considered max, anything above that is blizzard! max_pwr_diff = 4 # Value in kW that is considered the maximum power we draw in total # This value is used to set the brightness. e.g. if this is set to # 8 then when we're drawing 8kW or above the globe is at max brightness max_pwr_used = 8 s = solaredge.Solaredge(os.environ['SOLAREDGE_API_KEY']) data = s.get_current_power_flow(site_id) #print(data) # When there's no flow to or from the grid nothing comes # back in the 'connections' array so initialize here pwr_from_grid = 0 pwr_to_grid = 0 for c in data['siteCurrentPowerFlow']['connections']: # flow is from house --> grid if c['from'].lower() == 'load' and c['to'].lower() == 'grid': pwr_from_grid = 0 pwr_to_grid = data['siteCurrentPowerFlow']['GRID']['currentPower']