Beispiel #1
0
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)
Beispiel #2
0
    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')
Beispiel #3
0
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')
Beispiel #4
0
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)
Beispiel #5
0
 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
Beispiel #6
0
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)
Beispiel #7
0
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')
Beispiel #8
0
 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
Beispiel #9
0
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)
Beispiel #10
0
    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
Beispiel #11
0
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)
Beispiel #13
0
 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'
Beispiel #14
0
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
Beispiel #15
0
    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}
Beispiel #16
0
 def __init__(self, api_key, site_id):
     self.__solarEdge = solaredge.Solaredge(api_key)
     self.__data = self.__solarEdge.get_overview(site_id)
Beispiel #17
0
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']