Example #1
0
def migrateLegacyInverterTableToPony(configdbns, excerpt):
    if excerpt:
        sampleSize = 10
    else:
        sampleSize = 10000

    with PlantmonitorDB(configdbns) as db:
        curr = db._client.cursor()

        # fetch column names
        curr.execute('select * from sistema_inversor limit 1;')
        colNames = [c[0] for c in curr.description]

        insertSignature = [
            'time', 'inverter_name', 'location', '1HR', '1HR0', '2HR2', '3HR3',
            '4HR4', 'daily_energy_h', 'daily_energy_l', 'e_total_h',
            'e_total_l', 'h_total_h', 'h_total_l', 'pac_r', 'pac_s', 'pac_t',
            'powereactive_t', 'powerreactive_r', 'powerreactive_s',
            'probe1value', 'probe2value', 'probe3value', 'probe4value',
            'temp_inv'
        ]
        assert (insertSignature == colNames)

        curr = db._client.cursor("header")
        curr.execute(
            'select location from sistema_inversor group by location order by location asc;'
        )
        plantNames = [r[0] for r in curr.fetchall()]
        curr.close()

    for plantName in plantNames:
        logger.info("Migrating inverters from plant {}".format(plantName))
        with orm.db_session:
            plant = Plant.get(name=plantName)
            if not plant:
                plant = Plant(name=plantName, codename=plantName)
                logger.warning(
                    "Plant {} did not exist. We creted it.".format(plantName))

        with PlantmonitorDB(configdbns) as db:
            curr = db._client.cursor("header")
            curr.execute(
                "select inverter_name from sistema_inversor where location = '{}' group by inverter_name order by inverter_name asc;"
                .format(plantName))
            inverterNames = [r[0] for r in curr.fetchall()]
            curr.close()

        for inverterName in inverterNames:
            with PlantmonitorDB(configdbns) as db:
                migrateLegacyInverterToPony(db, inverterName, plantName,
                                            sampleSize, excerpt)

    logger.info("Inverters migrated")
Example #2
0
def migrateLegacyMeterTableToPony(configdbns, excerpt=False):

    # createPlants has to have been run
    with orm.db_session:
        if orm.count(p for p in Plant) == 0:
            print(
                "Database Doesn't have any plant to migrate to. Run createPlants()."
            )
            return

    if excerpt:
        sampleSize = 10
    else:
        sampleSize = 1000

    with PlantmonitorDB(configdbns) as db:
        curr = db._client.cursor()

        curr.execute(
            "select name from sistema_contador group by name order by name asc;"
        )
        deviceNames = [r[0] for r in curr.fetchall()]

    for deviceName in deviceNames:
        with PlantmonitorDB(configdbns) as db:
            # TODO normalize facility names
            facilities = [
                f for f, m in db.getFacilityMeter() if m == deviceName
            ]

            with orm.db_session:
                plants = [
                    Plant.get(codename=f) for f in facilities
                    if Plant.get(codename=f)
                ]

                if not plants:
                    print(
                        "Plant codename {} does not exist, assuming old record"
                        .format(facilities))
                    continue
                    #plant = Plant(name=plantName, codename=facilityName)
                elif len(plants) > 1:
                    print("[WARNING] Meter {} has several plants: {}".format(
                        deviceName, [plant.name for plant in plants]))

                plantName = plants[0].name

            migrateLegacyMeterToPony(db, deviceName, plantName, sampleSize,
                                     excerpt)
Example #3
0
def migrateLegacySensorTableToPony(configdbns,
                                   plantName,
                                   tableName,
                                   deviceType,
                                   dataColumnName,
                                   deviceName,
                                   excerpt=False):

    if excerpt:
        sampleSize = 10
    else:
        sampleSize = 1000

    with orm.db_session:
        plant = Plant.get(name=plantName)
        if not plant:
            plant = Plant(name=plantName, codename=plantName)

        if deviceType == 'SensorIrradiation':
            device = SensorIrradiation(name=deviceName, plant=plant)
        elif deviceType == 'SensorTemperature':
            device = SensorTemperatureAmbient(name=deviceName, plant=plant)
        else:
            raise PlantmonitorDBError(
                "Unknown device type {}".format(deviceType))

        with PlantmonitorDB(configdbns) as db:
            curr = db._client.cursor()
            curr.execute(
                "select distinct on (time) time, {} from {} limit {};".format(
                    dataColumnName, tableName, sampleSize))
            while True:
                records = curr.fetchmany(sampleSize)
                if not records:
                    break

                for r in records:
                    time, value = r
                    time = time.replace(tzinfo=dt.timezone.utc)
                    # TODO should we change to mw_m2 on the values to support decimals?
                    valueInt = round(value)
                    device.insertRegistry(valueInt, time=time)

                if excerpt:
                    break
Example #4
0
def migrateLegacySensorIrradiationTableToPony(configdbns,
                                              plantName,
                                              deviceName,
                                              excerpt=False):

    if excerpt:
        sampleSize = 10
    else:
        sampleSize = 1000

    with orm.db_session:
        plant = Plant.get(name=plantName)
        if not plant:
            plant = Plant(name=plantName, codename=plantName)

        sensor = SensorIrradiation(name=deviceName, plant=plant)

        with PlantmonitorDB(configdbns) as db:
            curr = db._client.cursor()
            curr.execute(
                "select distinct on (time) time, irradiation_w_m2, temperature_celsius from sensors limit {};"
                .format(sampleSize))
            while True:
                records = curr.fetchmany(sampleSize)
                if not records:
                    break

                for r in records:
                    print(r)
                    time, irradiation_w_m2, temperature_celsius = r
                    time = time.replace(tzinfo=dt.timezone.utc)
                    # TODO should we change to mw_m2 on the values to support decimals?
                    irradiation_w_m2 = round(irradiation_w_m2)
                    temperature_dc = round(temperature_celsius * 10)
                    sensor.insertRegistry(irradiation_w_m2=irradiation_w_m2,
                                          temperature_dc=temperature_dc,
                                          time=time)

                if excerpt:
                    break
Example #5
0
def upload_meter_data(configdb, test_env=True):

    if test_env:
        target_wsdl = configdb['meteo_test_url']
        lastDateFile = 'lastDateFile-test.yaml'
    else:
        target_wsdl = configdb['meteo_url']
        lastDateFile = 'lastDateFile.yaml'

    params = dict(
        wsdl=target_wsdl,
        username=configdb['meteo_user'],
        password=configdb['meteo_password'],
        lastDateFile=lastDateFile,
        showResponses=False,
    )

    excludedFacilities = ['test_facility']

    responses = {}
    start = time.perf_counter()

    with MeteologicaApi(**params) as api:
        with PlantmonitorDB(configdb) as db:

            facilities = db.getFacilities()
            apifacilities = api.getAllFacilities()

            logger.info('Uploading data from {} facilities in db'.format(
                len(facilities)))

            if not facilities:
                logger.warning("No facilities in db {} at {}:{}".format(
                    configdb['psql_db'], configdb['psql_host'],
                    configdb['psql_port']))
                return

            for facility in facilities:
                if facility in excludedFacilities:
                    logger.info(
                        "Facility {} excluded manually".format(facility))
                    continue
                if facility not in apifacilities:
                    logger.warning(
                        "Facility {} in db is not known for the API, skipping."
                        .format(facility))
                    responses[facility] = "INVALID_FACILITY_ID: {}".format(
                        facility)
                    continue

                lastUploadDT = api.lastDateUploaded(facility)
                logger.debug("Facility {} last updated: {}".format(
                    facility, lastUploadDT))
                meterData = {}
                if not lastUploadDT:
                    meterData = db.getMeterData(facility)
                else:
                    toDate = dt.datetime.now(dt.timezone.utc)
                    # TODO refactor this undo the hour shift due to api understanding start-hours instead of end-hours (see below @101)
                    fromDate = lastUploadDT + dt.timedelta(hours=1)
                    meterData = db.getMeterData(facility, fromDate, toDate)

                if not meterData:
                    logger.warning(
                        "No meter readings for facility {} since {}".format(
                            facility, lastUploadDT))
                # if not meterData[facility]:
                if facility not in meterData:
                    logger.warning("Missing {} in db meter readings {}".format(
                        facility, meterData))
                    continue

                #Seems to be correct according to documentation (meteologica said the contrary):
                #Hour correction, meteologica expects start hour insted of end hour for readings
                #ERP has end hour. Verified with validated readings. Assumes horari type.
                #Uploaded are one hour behind validated
                meterDataShifted = shiftOneHour(meterData)

                # conversion from energy to power
                # (Not necessary for hourly values)
                logger.debug("Uploading {} data: {} ".format(
                    facility, meterDataShifted[facility]))
                response = api.uploadProduction(facility,
                                                meterDataShifted[facility])
                responses[facility] = response

                logger.info(
                    "Uploaded {} observations for facility {} : {}".format(
                        len(meterDataShifted[facility]), facility, response))

    elapsed = time.perf_counter() - start
    logger.info('Total elapsed time {:0.4}'.format(elapsed))

    return responses
 def createPlantmonitorDB(self):
     configdb = self.createConfig()
     return PlantmonitorDB(configdb)
Example #7
0
 def tearDown(self):
     config = self.createConfig()
     PlantmonitorDB(config).dropDatabase(config)
     self.cleanLastDateFile()
Example #8
0
 def setUp(self):
     config = self.createConfig()
     PlantmonitorDB(config).demoDBsetup(config)
     self.cleanLastDateFile()
Example #9
0
 def createPlantmonitorDB(self):
     configdb = ns.load('conf/configdb_test.yaml')
     return PlantmonitorDB(configdb)
Example #10
0
 def tearDown(self):
     configdb = self.createConfig()
     PlantmonitorDB(configdb).dropDatabase(configdb)
Example #11
0
 def setUp(self):
     configdb = self.createConfig()
     PlantmonitorDB(configdb).demoDBsetup(configdb)
Example #12
0
def download_meter_data(configdb, test_env=True):

    if test_env:
        target_wsdl = configdb['meteo_test_url']
        lastDateFile = 'lastDateFile-test.yaml'
    else:
        target_wsdl = configdb['meteo_url']
        lastDateFile = 'lastDateFile.yaml'

    params = dict(
        wsdl=target_wsdl,
        username=configdb['meteo_user'],
        password=configdb['meteo_password'],
        lastDateFile='lastDateFile.yaml',
        lastDateDownloadFile='lastDateDownloadFile.yaml',
        showResponses=False,
    )

    start = time.perf_counter()

    downloadStatus = {}

    with MeteologicaApi(**params) as api:
        with PlantmonitorDB(configdb) as db:

            facilities = api.getAllFacilities()

            if not facilities:
                logger.info("No facilities in api {}".format(target_wsdl))
                return downloadStatus

            for facility in facilities:
                lastDownload = db.lastDateDownloaded(facility)

                now = dt.datetime.now(dt.timezone.utc)
                toDate = now

                if not lastDownload:
                    fromDate = now - dt.timedelta(days=14)
                elif now - lastDownload < dt.timedelta(hours=1):
                    logger.info("{} already up to date".format(facility))
                    downloadStatus[facility] = "UPTODATE"
                    continue
                else:
                    fromDate = lastDownload

                try:
                    meterDataForecast = api.getForecast(
                        facility, fromDate, toDate)
                    downloadStatus[facility] = "OK"
                except MeteologicaApiError as e:
                    logger.warning("Silenced exception: {}".format(e))
                    downloadStatus[facility] = str(e)
                    meterDataForecast = None

                if not meterDataForecast:
                    logger.info("No forecast data for {}".format(facility))
                    continue

                # TODO api uses start-hour, we should change to end-hour before inserting

                # conversion from energy to power
                # (Not necessary for hourly values)
                forecastDict = {facility: meterDataForecast}
                forecastDate = now
                db.addForecast(forecastDict, forecastDate)

                logger.info(
                    "Saved {} forecast records from {} to db - {} ".format(
                        len(meterDataForecast), facility,
                        downloadStatus[facility]))

    elapsed = time.perf_counter() - start
    logger.info('Total elapsed time {:0.4}'.format(elapsed))

    return downloadStatus