class Person(db.Entity): name = Required(unicode) addresses = Set("Address")
class Nagios(database.Entity): name = Required(unicode) plant = Required(Plant) description = Optional(str) registries = Set('NagiosRegistry', lazy=True)
class Room(db.Entity): id = PrimaryKey(UUID, auto=True) name = Required(str) stations = Set(Station)
class ForecastVariable(database.Entity): name = Required(unicode, unique=True) forecastMetadatas = Set('ForecastMetadata', lazy=True)
class ForecastMetadata(RegisterMixin, database.Entity): errorcode = Optional(str) plant = Required(Plant) variable = Optional(ForecastVariable) predictor = Optional(ForecastPredictor) forecastdate = Optional(datetime.datetime, sql_type='TIMESTAMP WITH TIME ZONE', default=datetime.datetime.now( datetime.timezone.utc)) granularity = Optional(int) registries = Set('Forecast', lazy=True) deviceColumnName = 'forecastmetadata' @classmethod def create(cls, plant, forecastdate, errorcode, variable='prod', predictor='aggregated', granularity='60'): if errorcode != 'OK': return ForecastMetadata( plant=plant, errorcode=errorcode, forecastdate=forecastdate, ) forecastPredictor = ForecastPredictor.get( name=predictor) or ForecastPredictor(name=predictor) forecastVariable = ForecastVariable.get( name=variable) or ForecastVariable(name=variable) return ForecastMetadata(plant=plant, predictor=forecastPredictor, variable=forecastVariable, forecastdate=forecastdate, granularity=granularity, errorcode=errorcode) def addForecasts(self, meterDataForecast): for forecast in meterDataForecast: time, p50 = forecast self.insertForecast(percentil10=None, percentil50=p50, percentil90=None, time=time) def insertForecast(self, percentil10, percentil50, percentil90, time=None): return Forecast(forecastMetadata=self, time=time or datetime.datetime.now(datetime.timezone.utc), percentil10=percentil10, percentil50=percentil50, percentil90=percentil90) # TODO remove and call directly getRegistries def getForecast(self, fromdate=None, todate=None): return self.getRegistries(fromdate=fromdate, todate=todate)
class PollutionType(db.Entity): id = PrimaryKey(int) type = Required(str) pollution = Set('Pollution') pollution_forecast = Set('PollutionForecast')
class Inverter(RegisterMixin, database.Entity): name = Required(unicode) plant = Required(Plant) brand = Optional(str, nullable=True) model = Optional(str, nullable=True) nominal_power_w = Optional(int) registries = Set('InverterRegistry', lazy=True) strings = Set('String') deviceColumnName = 'inverter' # inverter Strings are created via modmap the first time # and via parsing in registry insert # def __init__(self, plant, name): # super().__init__(plant=plant, name=name) # if classname == "String": # invertername, stringname = devicename.split('-') # inverter = Inverter.get(name=invertername) # if not inverter: # logger.warning("Unknown inverter {} for string {}".format(invertername, stringname)) # return None # return String(inverter=inverter, name=stringname) def insertRegistry( self, power_w, energy_wh, intensity_cc_mA, intensity_ca_mA, voltage_cc_mV, voltage_ca_mV, uptime_h, temperature_dc, time=None, ): return InverterRegistry( inverter=self, time=time or datetime.datetime.now(datetime.timezone.utc), power_w=power_w, energy_wh=energy_wh, intensity_cc_mA=intensity_cc_mA, intensity_ca_mA=intensity_ca_mA, voltage_cc_mV=voltage_cc_mV, voltage_ca_mV=voltage_ca_mV, uptime_h=uptime_h, temperature_dc=temperature_dc, ) # [{ # 'energy_wh': 100, # 'intensity_ca_mA': 1, # 'intensity_cc_mA': 1, # 'power_w': 100, # 'temperature_dc': 1, # 'time': time, # 'uptime_h': 1, # 'voltage_ca_mV': 1, # 'voltage_cc_mV': 1, # 'String_intensity_mA:string1': 100, # 'String_intensity_mA:string2': 200 # }] def insertDeviceData(self, devicedata, packettime=None): readings = devicedata['readings'] regs = [] for rg in readings: rg.setdefault('time', packettime) # TODO this modifies the entry dictionary, do we want to? # string_readings = {k:rg.pop(k) for k in list(rg) if k.startswith('String')} string_readings = { k: d for k, d in rg.items() if k.startswith('String') } inverter_readings = { k: d for k, d in rg.items() if not k.startswith('String') } inv_reg = self.insertRegistry(**inverter_readings) reg = [inv_reg] for sr, value in string_readings.items(): #TODO polymorfize this with sth like String.insertDeviceData(sr) devicetype, stringname, magnitude = sr.split(":") string = String.get(inverter=self, name=stringname) if not string: logger.warning("New device {}:{}".format( devicetype, stringname)) logger.warning("Creating {} named {} for {}".format( devicetype, stringname, self.name)) string = String(inverter=self, name=stringname) str_reg = string.insertRegistry(time=rg['time'], intensity_mA=value) reg.append(str_reg) regs.append(reg) return regs def plantData(self, fromdate=None, todate=None, skipEmpty=False): # TODO add strings' registries in inverter registries # select * from stringregistry where time = inverterregistry.time and stringregistry.string in self.inverter.strings # [sr for sr in StringRegistry.select()] # StringRegistry.select()) # [{**ir,**sr} for sr in StringRegistry.select() if sr.time = ir.time and sr.string in self.strings for ir in InverterRegistry.select()] # for r in self.registries: # for s in self.strings: # r.time == s.registries.time # {**r, "String_{}:{}".format(s)} # self.strings inverterPlantData = { "id": "Inverter:{}".format(self.name), "readings": self.getRegistries(fromdate, todate), } return inverterPlantData
class Shot(db.Entity): """Shot entity class.""" duration = Required(int) complexity = Optional(int) value = Optional(str) render = Optional(str) task = Set("Task", cascade_delete=False) project = Required(Project) createdAt = Required(datetime.datetime, default=datetime.datetime.utcnow, column="created_at") updatedAt = Required(datetime.datetime, default=datetime.datetime.utcnow, column="updated_at") deletedAt = Optional(datetime.datetime, nullable=True, column="deleted_at") @staticmethod def create_shot(duration, project, complexity=0, value='', render='', task=''): """Register shot in db :param int duration: duration :param projectObject project: project :param int complexity: complexity (opt) :param str value: value (opt) :param str render: render (opt) :param taskObject task: task (opt) :return: shot object created """ return Shot(duration=duration, complexity=complexity, value=value, render=render, task=task, project=project) @staticmethod def find_all_shots(): """find all shot, without deleted entities :return: lists of shot """ return Shot.select(lambda s: s.deletedAt is None)[:] @staticmethod def find_shot_by_id(shot_id): """find shot by id, without deleted entities :param int shot_id: shotId :return: (shot, string) shot object found and string for potential error """ shot = Shot.get(lambda s: s.id == shot_id and s.deletedAt is None) if shot is None: return shot, "Shot Not Found !" return shot, "" @staticmethod def update_shot_by_id(shot_id, shot_updated): """Update shot by id :param int shot_id: id of shot target :param shotObject shot_updated: new value :return: (shot, string) shot object updated and string for potential error """ # get shot target_shot = Shot.get( lambda s: s.id == shot_id and s.deletedAt is None) # shot exist? if target_shot is None: return target_shot, "Shot Not Found !" target_shot.duration = shot_updated.duration target_shot.complexity = shot_updated.complexity target_shot.value = shot_updated.value target_shot.render = shot_updated.render target_shot.task = shot_updated.task target_shot.project = shot_updated.project target_shot.updatedAt = datetime.datetime.utcnow() return target_shot, "" @staticmethod def remove_shot_by_id(shot_id): """Delete a shot :param int shot_id: id of shot :return: (id, string) id of shot deleted and string for potential error """ # get shot target_shot = Shot.get( lambda s: s.id == shot_id and s.deletedAt is None) # shot exist? if target_shot is None: return 0, "Shot Not Found !" target_shot.deletedAt = datetime.datetime.utcnow() return target_shot.id, ""
class Seller(db.Entity): _table_ = '%s_seller' % schema if DEBUG else (schema, 'seller') id = PrimaryKey(int, auto=True) title = Required(str) inn = Required(str, unique=True) sales = Set('FiscalNumber') @classmethod def add_sale(cls, fn, fd, fs): fn, fd, fs = fn.lstrip('0'), fd.lstrip('0'), fs.lstrip('0') if FiscalNumber.exists(sign=fs, drive=fn, document=fd): raise Exception('Receipt exists') url = '%s/v1/inns/*/kkts/*/fss/%s/tickets/%s' % (FNS_SERVER, fn, fd) for _ in range(2): q = get(url, params={ 'fiscalSign': fs, 'sendToEmail': 'no' }, auth=(USER_LOGIN, USER_PASSWORD), headers={ 'ClientVersion': CLIENT_VERSION, 'Version': PROTO_VERSION, 'Device-OS': DEVICE_OS, 'Device-Id': DEVICE_ID, 'User-Agent': USER_AGENT }) if q.status_code != 202: break sleep(3) if q.status_code != 200: raise Exception('Error (%d): %s' % (q.status_code, q.text)) data = q.json()['document']['receipt'] date = datetime.strptime(data['dateTime'], '%Y-%m-%dT%H:%M:%S') user = data.get('user') or 'No Name' inn = data['userInn'] if not data['items']: raise Exception('Empty receipt') items = {} for x in data['items']: key = (x['name'], Decimal(x['price'] / 100).quantize( Decimal('.01'), rounding=ROUND_HALF_UP)) if key in items: q, s = items[key] items[key] = (q + x['quantity'], s + Decimal(x['sum'] / 100)) else: items[key] = (x['quantity'], Decimal(x['sum'] / 100)) seller = cls.get(inn=inn) or cls(title=user, inn=inn) fiscal = FiscalNumber(sign=fs, drive=fn, document=fd, date=date, seller=seller) for (name, price), (quantity, _sum) in items.items(): Goods(title=name, price=price, quantity=quantity, sum=_sum, fiscal=fiscal) return Decimal(data['totalSum'] / 100).quantize( Decimal('.01'), rounding=ROUND_HALF_UP)
class Project(db.Entity): """Project Entity class.""" name = Required(str) short_name = Required(str) year_start = Required(int) year_end = Required(int) assets = Set("Asset") shots = Set("Shot") users = Set(User) createdAt = Required(datetime.datetime, default=datetime.datetime.utcnow, column="created_at") updatedAt = Required(datetime.datetime, default=datetime.datetime.utcnow, column="updated_at") deletedAt = Optional(datetime.datetime, nullable=True, column="deleted_at") @staticmethod def create_project(_name, _short_name, _year_start, _year_end): """Register project in db :param str _name: name :param str _short_name: short_name :param int _year_start: year_start :param int _year_end: year_end :return: project object created :rtype: projectObject """ return Project(name=_name, short_name=_short_name, year_start=_year_start, year_end=_year_end) @staticmethod def find_all_projects(): """find all project, without deleted entities :return: list of project :rtype: projectObjects """ return Project.select(lambda s: s.deletedAt is None)[:] @staticmethod def find_project_by_id(_project_id): """find project by id, without deleted entities :param int _project_id: project_id :return: project object found and string for potential error :rtype: (projectObject, str) """ _project = Project.get( lambda s: s.id == _project_id and s.deletedAt is None) if _project is None: return _project, "Project Not Found !" return _project, "" @staticmethod def update_project_by_id(_project_id, _project_updated): """Update project by id :param int _project_id: project_id :param projectObject _project_updated: new value :return: project object updated and string for potential error :rtype: (projectObject, str) """ # get project _targetProject = Project.get( lambda s: s.id == _project_id and s.deletedAt is None) # project exist? if _targetProject is None: return _targetProject, "Project Not Found !" _targetProject.name = _project_updated.name _targetProject.short_name = _project_updated.short_name _targetProject.year_start = _project_updated.year_start _targetProject.year_end = _project_updated.year_end _targetProject.users = _project_updated.users _targetProject.updatedAt = datetime.datetime.utcnow() return _targetProject, "" @staticmethod def remove_project_by_id(_project_id): """Delete a project :param int _project_id: project_id :return: id of project deleted and string for potential error :rtype: (int, str) """ # get project _targetProject = Project.get( lambda s: s.id == _project_id and s.deletedAt is None) # Project exist? if _targetProject is None: return 0, "Project Not Found !" _targetProject.deletedAt = datetime.datetime.utcnow() return _targetProject.id, ""
class Series(db.Entity): region = Required(Region) report = Required(Report) code = Required(str) name = Required(str) description = Optional(str) notes = Optional(str) units = Optional('Unit') scale = Optional('Scale') strvalues = Required(str) tags = Set('Tag') PrimaryKey(region, report, code) entity_type = 'series' def _splitStringValues(self): string_values = self.strvalues nvalues = list() for element in string_values.split('||'): year, value = element.split('|') value = float(value) if len(year) == 4: year = year + '-01-01' year = timetools.Timestamp(year) nvalues.append((year, value)) return nvalues @property def values(self): """ Returns list<Timestamp, float> """ if not hasattr(self, '_values_cache'): self._values_cache = self._splitStringValues() return self._values_cache @property def fvalues(self): if not hasattr(self, '_fvalues_cache'): self._fvalues_cache = [(i.toYear(), j) for i, j in self.values] return self._fvalues_cache @property def key(self): series_key = (self.region.key, self.report.key, self.code) return series_key @db_session def toDict(self, compact=False, **kwargs): to_json = kwargs.get('to_json', False) if compact: series_region = self.region.key series_report = self.report.key series_units = self.unit.key series_scale = self.scale.key else: series_region = self.region.toDict(True) series_report = self.report.toDict(True) series_units = self.unit.toDict(True) series_scale = self.scale.toDict(True) if to_json: series_values = self.fvalues else: series_values = self.values data = { 'entityType': 'series', 'entityKey': self.key, 'seriesRegion': series_region, 'seriesReport': series_report, 'seriesCode': self.code, 'seriesName': self.name, 'seriesDescription': self.description, 'seriesNotes': self.notes, 'seriesUnits': series_units, 'seriesScale': series_scale, 'seriesValues': series_values, 'seriesTags': list(), } return data
class Token(db.Entity): tok = Required(str, unique=True) doc_freq = Required(int) documents = Set("Document")
class GifHosts(db.Entity): name = PrimaryKey(str) origin_gifs = Set('Gif', reverse='origin_host') reversed_gifs = Set('Gif', reverse='reversed_host')
class Student(Human): klas = Optional('Klas') results = Set('Result')
class Complaint(db.Entity): id = PrimaryKey(int, auto=True) title = Required(str) state = Required(str, default='OPEN') approved = Required(bool, default=False) description = Required(str) created_at = Required(datetime.datetime, default=datetime.datetime.utcnow) complainer = Required('User') city = Required('City') labels = Set('Label') votes = Set('Vote') feedbacks = Set('ComplaintFeedback') subscribers = Set('User', reverse="subscribed_complaints") @db_session def to_dict_vote(self, vote): upvotes = select( count(c.votes) for c in Complaint if True in c.votes.is_upvote and c.id == self.id).first() downvotes = select( count(c.votes) for c in Complaint if False in c.votes.is_upvote and c.id == self.id).first() return { 'id': self.id, 'title': self.title, 'description': self.description, 'state': self.state, 'approved': self.approved, 'city': self.city.to_dict(), 'complainer': self.complainer.id, 'created_at': self.created_at.isoformat(), 'is_upvote': vote, 'upvotes': upvotes, 'downvotes': downvotes, 'feedback': list( map( lambda f: { 'feedback_id': f.id, 'text': f.text, 'user': f.user.id, 'created_at': f.created_at.isoformat() }, self.feedbacks)), 'labels': list(map(lambda x: x.to_dict(), self.labels)) } @db_session def to_dict_sums(self): upvotes = select( count(c.votes) for c in Complaint if True in c.votes.is_upvote and c.id == self.id).first() downvotes = select( count(c.votes) for c in Complaint if False in c.votes.is_upvote and c.id == self.id).first() return { 'id': self.id, 'title': self.title, 'description': self.description, 'state': self.state, 'approved': self.approved, 'city': self.city.to_dict(), 'complainer': self.complainer.id, 'created_at': self.created_at.isoformat(), 'upvotes': upvotes, 'downvotes': downvotes, 'feedback': list( map( lambda f: { 'feedback_id': f.id, 'text': f.text, 'user': f.user.id, 'created_at': self.created_at.isoformat() }, self.feedbacks)), 'labels': list(map(lambda x: x.to_dict(), self.labels)) }
class SourceFile(db.Entity): filename = Required(text_type, autostrip=False) lines = Set('Line')
class Role(db.Entity): name = Required(str, unique=True) description = Optional(str, nullable=True) users = Set(lambda: User)
class Line(db.Entity): sourcefile = Required(SourceFile) line = Optional(text_type, autostrip=False) line_number = Required(int) mutants = Set('Mutant')
class Plant(database.Entity): name = Required(unicode) codename = Required(unicode) #TODO make municipality required municipality = Optional(Municipality) location = Optional("PlantLocation") description = Optional(str) meters = Set('Meter') inverters = Set('Inverter', lazy=True) sensors = Set('Sensor', lazy=True) forecastMetadatas = Set('ForecastMetadata', lazy=True) inclinometers = Set('Inclinometer', lazy=True) anemometer = Set('Anemometer', lazy=True) omie = Set('Omie', lazy=True) marketRepresentative = Set('MarketRepresentative', lazy=True) simel = Set('Simel', lazy=True) nagios = Set('Nagios', lazy=True) solarEvents = Set('SolarEvent') plantParameters = Optional('PlantParameters') moduleParameters = Optional('PlantModuleParameters') plantMonthlyLegacy = Optional('PlantMonthlyLegacy') @classmethod def insertPlantsData(cls, plantsData): for plantData in plantsData: logger.debug("importing plant data for plant {}".format( plantData['plant'])) plant = Plant.get(name=plantData['plant']) if not plant: logger.error( "Plant {} is not known. Known plants: {}".format( plantData['plant'], [p.name for p in Plant.select()])) else: plant.insertPlantData(plantData) @classmethod def getFromMeteologica(cls, plant_code): return Plant.get(codename=plant_code) def lastForecastDownloaded(self): # TODO when the forecast was made doesn't represent the forecast dates, # we might prefer checking all forecasts and get the latest return orm.select( f.forecastdate for f in self.forecastMetadatas).order_by(-1).first() def importPlant(self, nsplant): plant = nsplant self.name = plant.name self.description = plant.description if 'municipality' in plant: m = Municipality.get(ineCode=plant['municipality']) if m: self.municipality = Municipality.get( ineCode=plant['municipality']) else: #TODO error or exception? logger.error("Error: municipality {} not found".format( plant['municipality'])) raise if 'meters' in plant: [ Meter(plant=self, name=meter['meter'].name) for meter in plant.meters ] if 'inverters' in plant: for inverter in plant.inverters: inv = Inverter(plant=self, name=inverter['inverter'].name) for string_name in inverter.inverter.get('strings', []): String(inverter=inv, name=string_name) if 'irradiationSensors' in plant: [ SensorIrradiation(plant=self, name=sensor['irradiationSensor'].name) for sensor in plant.irradiationSensors ] if 'temperatureAmbientSensors' in plant: [ SensorTemperatureAmbient( plant=self, name=sensor['temperatureAmbientSensor'].name) for sensor in plant.temperatureAmbientSensors ] if 'temperatureModuleSensors' in plant: [ SensorTemperatureModule( plant=self, name=sensor['temperatureModuleSensor'].name) for sensor in plant.temperatureModuleSensors ] if 'moduleParameters' in plant: self.setModuleParameters(**plant['moduleParameters']) return self def exportPlant(self, skipEmpty=False): # print([meter.to_dict() for meter in Meter.select(lambda m: m.plant == self)]) if not skipEmpty: plantns = ns( name=self.name, codename=self.codename, description=self.description, meters=[ ns(meter=ns(name=meter.name)) for meter in Meter.select(lambda m: m.plant == self) ], inverters=[ ns(inverter=ns( name=inverter.name ) if not inverter.strings else ns( name=inverter.name, strings=sorted([s.name for s in inverter.strings]))) for inverter in Inverter.select( lambda inv: inv.plant == self) ], irradiationSensors=[ ns(irradiationSensor=ns(name=sensor.name)) for sensor in SensorIrradiation.select( lambda inv: inv.plant == self) ], temperatureAmbientSensors=[ ns(temperatureAmbientSensor=ns(name=sensor.name)) for sensor in SensorTemperatureAmbient.select( lambda inv: inv.plant == self) ], temperatureModuleSensors=[ ns(temperatureModuleSensor=ns(name=sensor.name)) for sensor in SensorTemperatureModule.select( lambda inv: inv.plant == self) ], ) if self.moduleParameters: plantns.moduleParameters = self.moduleParameters.export() else: plantns = ns(name=self.name, codename=self.codename, description=self.description) meters = [ ns(meter=ns(name=meter.name)) for meter in Meter.select(lambda m: m.plant == self) ] inverters = [ ns(inverter=ns( name=inverter.name) if not inverter.strings else ns(name=inverter.name, strings=sorted([s.name for s in inverter.strings]))) for inverter in Inverter.select( lambda inv: inv.plant == self) ] irradiationSensors = [ ns(irradiationSensor=ns(name=sensor.name)) for sensor in SensorIrradiation.select(lambda inv: inv.plant == self) ] temperatureAmbientSensors = [ ns(temperatureAmbientSensor=ns(name=sensor.name)) for sensor in SensorTemperatureAmbient.select( lambda inv: inv.plant == self) ] temperatureModuleSensors = [ ns(temperatureModuleSensor=ns(name=sensor.name)) for sensor in SensorTemperatureModule.select( lambda inv: inv.plant == self) ] if meters: plantns['meters'] = meters if inverters: plantns['inverters'] = inverters if irradiationSensors: plantns['irradiationSensors'] = irradiationSensors if temperatureAmbientSensors: plantns[ 'temperatureAmbientSensors'] = temperatureAmbientSensors if temperatureModuleSensors: plantns[ 'temperatureModuleSensors'] = temperatureModuleSensors if self.moduleParameters: plantns['moduleParameters'] = self.moduleParameters.export( ) if self.municipality: plantns.municipality = self.municipality.ineCode logger.debug(plantns.dump()) return plantns def createPlantFixture(self): Meter(plant=self, name='Meter' + self.name) Inverter(plant=self, name='Plant' + self.name) SensorIrradiation(plant=self, name='Irrad' + self.name) SensorTemperatureAmbient(plant=self, name='TempAmb' + self.name) SensorTemperatureModule(plant=self, name='TempMod' + self.name) def plantData(self, fromdate=None, todate=None, skipEmpty=False): data = {"plant": self.name} #TODO generalize this meterList = [{ "id": "Meter:{}".format(m.name), "readings": m.getRegistries(fromdate, todate) } for m in orm.select(mc for mc in self.meters) if not skipEmpty or m.getRegistries(fromdate, todate)] inverterList = [ { "id": "Inverter:{}".format(i.name), "readings": i.getRegistries(fromdate, todate) } for i in orm.select(ic for ic in self.inverters) if not skipEmpty or i.getRegistries(fromdate, todate) ] # inverterList = [inverter.plantData() for inverter in self.inverters] sensorList = [ i.toDict(fromdate, todate) for i in orm.select(ic for ic in self.sensors) if not skipEmpty or i.getRegistries(fromdate, todate) ] forecastMetadatasList = [ { "id": "ForecastMetadatas:{}".format(i.name), "readings": i.getRegistries(fromdate, todate) } for i in orm.select(ic for ic in self.forecastMetadatas) if not skipEmpty or i.getRegistries(fromdate, todate) ] data[ "devices"] = inverterList + meterList + forecastMetadatasList + sensorList data["devices"].sort(key=lambda x: x['id']) return data def setModuleParameters(self, nominalPowerMWp, efficiency, nModules, degradation, Imp, Vmp, temperatureCoefficientI, temperatureCoefficientV, temperatureCoefficientPmax, irradiationSTC, temperatureSTC, Voc, Isc): self.moduleParameters = PlantModuleParameters( plant=self, nominal_power_wp=int(nominalPowerMWp * 1000000), efficency_cpercent=int(efficiency * 100), n_modules=nModules, degradation_cpercent=int(degradation * 100), max_power_current_ma=int(Imp * 1000), max_power_voltage_mv=int(Vmp * 1000), current_temperature_coefficient_mpercent_c=int( temperatureCoefficientI * 1000), voltage_temperature_coefficient_mpercent_c=int( temperatureCoefficientV * 1000), max_power_temperature_coefficient_mpercent_c=int( temperatureCoefficientPmax * 1000), standard_conditions_irradiation_w_m2=int(irradiationSTC), standard_conditions_temperature_dc=int(temperatureSTC * 10), opencircuit_voltage_mv=int(Voc * 1000), shortcircuit_current_ma=int(Isc * 1000), ) @staticmethod def str2device(plant, classname, devicename): #TODO generalize this #TODO distinguish between failure due to missing name and unknown class model = str2model(database, classname) if not model: logger.error("Model {} not found".format(classname)) return None device = model.get(plant=plant, name=devicename) if not device: logger.error("Device {} {} not found".format( classname, devicename)) return None return device def createDevice(self, classname, devicename): # TODO handle this better, String is in the list of supported_models, # but we don't do creation as a device but as part of an inverter registry if classname == 'String': logger.error("String creation is not supported") return None #TODO generalize this #TODO distinguish between failure due to missing name and unknown class Model = str2model(database, classname) if not Model: logger.error("Model {} not found".format(classname)) return None logger.debug("Create device from model {}".format(classname)) return Model(plant=self, name=devicename) def insertDeviceData(self, devicedata, packettime=None): devicetype, devicename = devicedata["id"].split(":") device = self.str2device(plant=self, classname=devicetype, devicename=devicename) if not device: logger.warning("New device {}:{}".format( devicetype, devicename)) logger.warning("Creating {} named {} for {}".format( devicetype, devicename, self.name)) device = self.createDevice(classname=devicetype, devicename=devicename) if not device: logger.warning("Unknown device type {}".format(devicetype)) return None return device.insertDeviceData(devicedata, packettime) def insertPlantData(self, plantdata): if self.name != plantdata["plant"]: return False packettime = plantdata.get("time") return [ self.insertDeviceData(d, packettime) for d in plantdata["devices"] ] def getMeter(self): # TODO a plant has more than one meter, how do we know which one is active? return orm.select( m for m in self.meters).order_by(lambda: orm.desc(m.id)).first()
class GitFile(db.Entity): _table_ = 'gitfile' id = PrimaryKey(int, auto=True) project_id = Required(str) file_name = Required(str) file_path = Required(str) ref = Optional(str) blob_id = Required(str) commit_id = Optional(str) last_commit_id = Required(str) content = Required(Json) create_at = Required(datetime.datetime, default=datetime.datetime.utcnow(), index=True) update_at = Required(datetime.datetime, default=datetime.datetime.utcnow(), index=True) delete_at = Optional(datetime.datetime, nullable=True) user = Required(str) info = Optional(Json) testcase = Set('TestCase') env = Set('Env') @classmethod @db_session def get_obj_by_project_id_and_file_path_and_update_content( cls, project_id, file_path, blob_id, commit_id, last_commit_id, content, user): obj = get(n for n in GitFile if n.project_id == project_id and n.delete_at == None and n.file_path == file_path) if obj: if obj.blob_id != blob_id: obj.blob_id = blob_id obj.commit_id = commit_id obj.last_commit_id = last_commit_id obj.content = content obj.user = user obj.update_at = datetime.datetime.utcnow() return obj.id else: raise IsNotExist(title='获取文件不存在', detail=f'项目{project_id}下的文件{file_path}不存在') @classmethod @db_session def get_obj_pk_by_project_id_and_file_path(cls, project_id, file_path): obj = get(n for n in GitFile if n.project_id == project_id and n.delete_at == None and n.file_path == file_path) if obj: return obj.id else: raise IsNotExist(title='获取文件不存在', detail=f'项目{project_id}下的文件{file_path}不存在') @classmethod @db_session def create_obj_by_project_id_and_file_path(cls, project_id, file_name, file_path, ref, blob_id, commit_id, last_commit_id, content, user): obj = get(n for n in GitFile if n.project_id == project_id and n.delete_at == None and n.file_path == file_path) if obj: raise IsExist( title='文件已经存在', detail=f'proejct_id为{blob_id}, file_path为{file_path}的文件已存在') else: obj = GitFile(file_name=file_name, file_path=file_path, ref=ref, blob_id=blob_id, commit_id=commit_id, last_commit_id=last_commit_id, content=content, user=user, project_id=project_id) commit() return obj.id @classmethod @db_session def get_file_list_by_project_id(cls, project_id): data = [] objs = select(n for n in GitFile if n.project_id == project_id and n.delete_at == None) for obj in objs: tmp_dict = {} tmp_dict['id'] = obj.id tmp_dict['file_name'] = obj.file_name tmp_dict['file_path'] = obj.file_path data.append(tmp_dict) return data
class Anemometer(database.Entity): name = Required(unicode) plant = Required(Plant) description = Optional(str) registries = Set('AnemometerRegistry', lazy=True)
class PDF(db.Entity): id = PrimaryKey(int, auto=True) paper_id = Required(str, unique=True, index=True) data = Optional(buffer, nullable=True) paper = Optional(Paper) thumbnails = Set('Thumbnail')
class ForecastPredictor(database.Entity): name = Required(unicode, unique=True) forecastMetadatas = Set('ForecastMetadata')
class User(db.Entity): id = PrimaryKey(int, auto=True) username = Optional(str) user_paper_status = Set('UserPaperStatus')
class MarketRepresentative(database.Entity): name = Required(unicode) plant = Required(Plant) description = Optional(str) registries = Set('MarketRepresentativeRegistry', lazy=True)
class Tag(db.Entity): tag_id = PrimaryKey(str) name = Required(str, unique=True) pretty_name_sv = Required(str) pretty_name_en = Required(str) song_tags = Set("SongToTag")
class Category(db.Entity): name = Required(str, unique=True) books = Set(lambda: Book, reverse='category')
class Address(DatabaseConfig.db.Entity): """ Model for storing address information in the DB """ geolocator = Nominatim() id = PrimaryKey(int, auto=True) street = Optional(str) city = Optional(str) state = Optional(str) zip_code = Optional(str) stations = Set(Station) telephone = Optional(str) email = Optional(str) latitude = Optional(float) longitude = Optional(float) def __init__(self, *args, **kwargs): """ Call the original __init__ method and then populate the lat/long values """ super(Address, self).__init__(*args, **kwargs) # Initialize the latitude and long for this address self.get_lat_long() @property def address(self): """ Return the address in single line format, used primarily for generating the string input for the GeoCoder """ return "{} {} {} {}".format(self.street, self.city, self.state, self.zip_code) def get_lat_long(self, update=False): """ Return a tuple with latitude and longitude geocoded from the address, this can be used for plotting checkin locations on a map """ if not (self.latitude and self.longitude) or update: # Only make a call to the GeoCoder if we don't already have the # lat_long information, or if we are forcing an update try: # The GeoCoder requires internet access, an exception will # occur (and is handled below) if it is not present location = self.geolocator.geocode(self.address) # @db_session self.latitude = location.latitude self.longitude = location.longitude DatabaseConfig.db.commit() return True except GeocoderServiceError: # Handle exception when no internet access by just returning # whatever may be already in lat_long, either nothing or the # old value return False # Just return the existing value by default return False
class Role(db.Entity): """admin, user, teacher""" id = PrimaryKey(UUID, auto=True) name = Required(str, unique=True) users = Set(User)
class Action(db.Entity): name = Required(str) command = Required(str) arguments = Set(Argument) menu = Required(lambda: Menu)