예제 #1
0
class Sim(ResourceMixin, db.Model):
    __tablename__ = 'sim'
    id = db.Column(db.Integer, primary_key=True)
    phone_number = db.Column(db.String(25), unique=True, index=True)
    sim_serial = db.Column(db.String(25), unique=True, index=True, default='')

    def __init__(self, **kwargs):
        # Call Flask-SQLAlchemy's constructor.
        super(Imei, self).__init__(**kwargs)

    def __str__(self):
        return str(self.phone_number) + " : " + str(self.sim_serial)

    @classmethod
    def find_by_identity(cls, identity):
        """
        Find a meter by its sequence_number or serial_number or phone_number.

        :param identity: sequence_number or serial_number or phone_number
        :type identity: str
        :return: Meter instance
        """
        return Imei.query.filter((Imei.phone_number == identity)
                                 | (Imei.sim_serial == identity)).first()

    @classmethod
    def search(cls, query):
        """
        Search a resource by 1 or more fields.

        :param query: Search query
        :type query: str
        :return: SQLAlchemy filter
        """
        if not query:
            return ''

        search_query = '%{0}%'.format(query)
        search_chain = (Imei.phone_number.ilike(search_query),
                        Imei.sim_serial.ilike(search_query))

        return or_(*search_chain)

    @property
    def serialize(self):
        return {
            'id': self.id,
            'phone_number': self.meter_identifier,
            'sim_serial': self.modem_imei,
            'created_on': self.created_on,
            'updated_on': self.updated_on,
        }
예제 #2
0
class User(UserMixin, ResourceMixin, db.Model):
    ROLE = OrderedDict([
        ('member', 'Member'),
        ('admin', 'Admin')
    ])

    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)

    # Authentication.
    role = db.Column(db.Enum(*ROLE, name='role_types', native_enum=False),
                     index=True, nullable=False, server_default='member')
    active = db.Column('is_active', db.Boolean(), nullable=False,
                       server_default='1')
    username = db.Column(db.String(24), unique=True, index=True)
    email = db.Column(db.String(255), unique=True, index=True, nullable=False,
                      server_default='')
    password = db.Column(db.String(128), nullable=False, server_default='')

    # Activity tracking.
    sign_in_count = db.Column(db.Integer, nullable=False, default=0)
    current_sign_in_on = db.Column(db.TIMESTAMP)  # AwareDateTime())
    current_sign_in_ip = db.Column(db.String(45))
    last_sign_in_on = db.Column(db.TIMESTAMP)  #
    last_sign_in_ip = db.Column(db.String(45))

    def __init__(self, **kwargs):
        # Call Flask-SQLAlchemy's constructor.
        super(User, self).__init__(**kwargs)

        self.password = User.encrypt_password(kwargs.get('password', ''))

    @classmethod
    def find_by_identity(cls, identity):
        """
        Find a user by their e-mail or username.

        :param identity: Email or username
        :type identity: str
        :return: User instance
        """
        return User.query.filter(
            (User.email == identity) | (User.username == identity)).first()

    @classmethod
    def encrypt_password(cls, plaintext_password):
        """
        Hash a plaintext string using PBKDF2. This is good enough according
        to the NIST (National Institute of Standards and Technology).

        In other words while bcrypt might be superior in practice, if you use
        PBKDF2 properly (which we are), then your passwords are safe.

        :param plaintext_password: Password in plain text
        :type plaintext_password: str
        :return: str
        """
        if plaintext_password:
            return generate_password_hash(plaintext_password)

        return None

    @classmethod
    def deserialize_token(cls, token):
        """
        Obtain a user from de-serializing a signed token.

        :param token: Signed token.
        :type token: str
        :return: User instance or None
        """
        private_key = TimedJSONWebSignatureSerializer(
            current_app.config['SECRET_KEY'])
        try:
            decoded_payload = private_key.loads(token)

            return User.find_by_identity(decoded_payload.get('user_email'))
        except Exception:
            return None

    @classmethod
    def initialize_password_reset(cls, identity):
        """
        Generate a token to reset the password for a specific user.

        :param identity: User e-mail address or username
        :type identity: str
        :return: User instance
        """
        u = User.find_by_identity(identity)
        reset_token = u.serialize_token()

        # This prevents circular imports.
        from ami.blueprints.user.tasks import (
            deliver_password_reset_email)
        deliver_password_reset_email.delay(u.id, reset_token)

        return u

    @classmethod
    def search(cls, query):
        """
        Search a resource by 1 or more fields.

        :param query: Search query
        :type query: str
        :return: SQLAlchemy filter
        """
        if not query:
            return ''

        search_query = '%{0}%'.format(query)
        search_chain = (User.email.ilike(search_query),
                        User.username.ilike(search_query))

        return or_(*search_chain)

    @classmethod
    def is_last_admin(cls, user, new_role, new_active):
        """
        Determine whether or not this user is the last admin account.

        :param user: User being tested
        :type user: User
        :param new_role: New role being set
        :type new_role: str
        :param new_active: New active status being set
        :type new_active: bool
        :return: bool
        """
        is_changing_roles = user.role == 'admin' and new_role != 'admin'
        is_changing_active = user.active is True and new_active is None

        if is_changing_roles or is_changing_active:
            admin_count = User.query.filter(User.role == 'admin').count()
            active_count = User.query.filter(User.is_active is True).count()

            if admin_count == 1 or active_count == 1:
                return True

        return False

    def is_active(self):
        """
        Return whether or not the user account is active, this satisfies
        Flask-Login by overwriting the default value.

        :return: bool
        """
        return self.active

    def get_auth_token(self):
        """
        Return the user's auth token. Use their password as part of the token
        because if the user changes their password we will want to invalidate
        all of their logins across devices. It is completely fine to use
        md5 here as nothing leaks.

        This satisfies Flask-Login by providing a means to create a token.

        :return: str
        """
        private_key = current_app.config['SECRET_KEY']

        serializer = URLSafeTimedSerializer(private_key)
        data = [str(self.id), md5(self.password.encode('utf-8')).hexdigest()]

        return serializer.dumps(data)

    def authenticated(self, with_password=True, password=''):
        """
        Ensure a user is authenticated, and optionally check their password.

        :param with_password: Optionally check their password
        :type with_password: bool
        :param password: Optionally verify this as their password
        :type password: str
        :return: bool
        """
        if with_password:
            return check_password_hash(self.password, password)

        return True

    def serialize_token(self, expiration=3600):
        """
        Sign and create a token that can be used for things such as resetting
        a password or other tasks that involve a one off token.

        :param expiration: Seconds until it expires, defaults to 1 hour
        :type expiration: int
        :return: JSON
        """
        private_key = current_app.config['SECRET_KEY']

        serializer = TimedJSONWebSignatureSerializer(private_key, expiration)
        return serializer.dumps({'user_email': self.email}).decode('utf-8')

    def update_activity_tracking(self, ip_address):
        """
        Update various fields on the user that's related to meta data on their
        account, such as the sign in count and ip address, etc..

        :param ip_address: IP address
        :type ip_address: str
        :return: SQLAlchemy commit results
        """
        self.sign_in_count += 1

        self.last_sign_in_on = self.current_sign_in_on
        self.last_sign_in_ip = self.current_sign_in_ip

        self.current_sign_in_on = datetime.datetime.now()#pytz.utc
        self.current_sign_in_ip = ip_address

        return self.save()
예제 #3
0
class LoadDemand(db.Model):
    __bind_key__ = 'ami'
    __tablename__ = 'demand_data'
    id = db.Column(db.Integer, primary_key=True)
    amount = db.Column(db.DECIMAL)
    created_at = db.Column(db.TIMESTAMP)
    meter_id = db.Column(db.Integer)
    obis = db.Column(db.String(255))
    name = db.Column(db.String(255))
    scalar = db.Column(db.Integer)
    unit = db.Column(db.String(5))
    unit_value = db.Column(db.Integer)
    value = db.Column(db.DECIMAL)
    data = db.Column(db.String(45))

    def __init__(self, **kwargs):
        # Call Flask-SQLAlchemy's constructor.
        super(LoadDemand, self).__init__(**kwargs)
예제 #4
0
class Meter(ResourceMixin, db.Model):
    ROLE = OrderedDict([
        ('dev', 'Development'),
        ('pro', 'Production')
    ])
    __tablename__ = 'meters'
    id = db.Column(db.Integer, primary_key=True)
    sequence_number = db.Column(db.String(20), unique=True, index=True)
    serial_number = db.Column(db.String(20), unique=True, index=True, nullable=False,
                              server_default='')
    phone_number = db.Column(db.String(20), unique=True, index=True, nullable=False,
                             server_default='')
    customer_name = db.Column(db.String(255), nullable=False,
                              server_default='')
    ak_ek = db.Column(db.String(255), nullable=False,
                      server_default='30303030303030303030303030303030')
    branch = db.Column(db.String(10), nullable=False,
                       server_default='')
    zone = db.Column(db.String(10), nullable=False,
                     server_default='')
    initial_reading = db.Column(db.String(10), nullable=False,
                                server_default='')
    lat_long = db.Column(db.String(30), nullable=False,
                         server_default='')
    online = db.Column('is_online', db.Boolean(), nullable=False,
                       server_default='1')
    power = db.Column('power_on', db.Boolean(), nullable=False,
                      server_default='1')
    ct = db.Column('is_ct', db.Boolean(), nullable=False,
                   server_default='1')
    active = db.Column('is_active', db.Boolean(), nullable=False,
                       server_default='1')

    def __init__(self, **kwargs):
        # Call Flask-SQLAlchemy's constructor.
        super(Meter, self).__init__(**kwargs)

    @classmethod
    def find_by_identity(cls, identity):
        """
        Find a meter by its sequence_number or serial_number or phone_number.

        :param identity: sequence_number or serial_number or phone_number
        :type identity: str
        :return: Meter instance
        """
        return Meter.query.filter(
            (Meter.sequence_number == identity) | (Meter.phone_number == identity) | (
                Meter.serial_number == identity)).first()

    def is_active(self):
        """
        Return whether or not the user account is active, this satisfies
        Flask-Login by overwriting the default value.

        :return: bool
        """
        return self.active

    @classmethod
    def search(cls, query):
        """
        Search a resource by 1 or more fields.

        :param query: Search query
        :type query: str
        :return: SQLAlchemy filter
        """
        if not query:
            return ''

        search_query = '%{0}%'.format(query)
        search_chain = (Meter.sequence_number.ilike(search_query),
                        Meter.serial_number.ilike(search_query),
                        Meter.phone_number.ilike(search_query))

        return or_(*search_chain)

    @property
    def serialize(self):
        return {
            'id': self.id,
            'serial_number': self.serial_number,
            'sequence_number': self.sequence_number,
            'phone_number': self.phone_number,
            'customer_name': self.customer_name,
            'ak_ek': self.ak_ek,
            'active': self.active,
            'branch': self.branch,
            'zone': self.zone,
            'lat_long': self.lat_long,
            'initial_reading': self.initial_reading,
            'ct': self.ct,
            'power': self.power,
            'online': self.online,
            'created_on': self.created_on,
            'updated_on': self.updated_on,
        }
예제 #5
0
class LoadMeter(db.Model):
    __bind_key__ = 'ami'
    __tablename__ = 'meter'
    id = db.Column(db.Integer, primary_key=True)
    hes_id = db.Column(db.Integer, index=True, nullable=False)
    serial_no = db.Column(db.String(255))
    customer_seq_no = db.Column(db.String(255))
    phone_number = db.Column(db.String(255))
    customer_name = db.Column(db.String(255))
    branch = db.Column(db.String(10), nullable=False, server_default='')
    zone = db.Column(db.String(10), nullable=False, server_default='')
    online = db.Column('online',
                       db.Boolean(),
                       nullable=False,
                       server_default='1')
    power = db.Column('power',
                      db.Boolean(),
                      nullable=False,
                      server_default='1')
    ct = db.Column('ct', db.Boolean(), nullable=False, server_default='1')
    ak_ek = db.Column(db.String(255),
                      nullable=False,
                      server_default='30303030303030303030303030303030')
    initial = db.Column(db.String(10), nullable=False, server_default='')
    latlong = db.Column(db.String(30), nullable=False, server_default='')
    current_data = db.Column(db.String(30), nullable=False, server_default='')

    def __init__(self, **kwargs):
        # Call Flask-SQLAlchemy's constructor.
        super(LoadMeter, self).__init__(**kwargs)
class ResourceMixin(object):
    # Keep track when records are created and updated.
    created_on = db.Column(
        db.TIMESTAMP,  #
        default=tzware_datetime)
    updated_on = db.Column(
        db.TIMESTAMP,  # AwareDateTime(),
        default=tzware_datetime,
        onupdate=tzware_datetime)

    @classmethod
    def sort_by(cls, field, direction):
        """
        Validate the sort field and direction.

        :param field: Field name
        :type field: str
        :param direction: Direction
        :type direction: str
        :return: tuple
        """

        table_name = str(cls.__table__)

        if field not in cls.__table__.columns:
            field = 'created_on'

        if direction not in ('asc', 'desc'):
            direction = 'asc'

        if table_name not in field:
            field = table_name + "." + field
        print(field, direction)

        return field, direction

    @classmethod
    def get_bulk_action_ids(cls, scope, ids, omit_ids=[], query=''):
        """
        Determine which IDs are to be modified.

        :param scope: Affect all or only a subset of items
        :type scope: str
        :param ids: List of ids to be modified
        :type ids: list
        :param omit_ids: Remove 1 or more IDs from the list
        :type omit_ids: list
        :param query: Search query (if applicable)
        :type query: str
        :return: list
        """
        omit_ids = map(str, omit_ids)

        if scope == 'all_search_results':
            # Change the scope to go from selected ids to all search results.
            ids = cls.query.with_entities(cls.id).filter(cls.search(query))

            # SQLAlchemy returns back a list of tuples, we want a list of strs.
            ids = [str(item[0]) for item in ids]

        # Remove 1 or more items from the list, this could be useful in spots
        # where you may want to protect the current user from deleting themself
        # when bulk deleting user accounts.
        if omit_ids:
            ids = [id for id in ids if id not in omit_ids]

        return ids

    @classmethod
    def bulk_delete(cls, ids):
        """
        Delete 1 or more model instances.

        :param ids: List of ids to be deleted
        :type ids: list
        :return: Number of deleted instances
        """
        delete_count = cls.query.filter(
            cls.id.in_(ids)).delete(synchronize_session=False)
        db.session.commit()

        return delete_count

    def save(self):
        """
        Save a model instance.

        :return: Model instance
        """
        db.session.add(self)
        db.session.commit()

        return self

    def delete(self):
        """
        Delete a model instance.

        :return: db.session.commit()'s result
        """
        db.session.delete(self)
        return db.session.commit()

    def __str__(self):
        """
        Create a human readable version of a class instance.

        :return: self
        """
        obj_id = hex(id(self))
        columns = self.__table__.c.keys()

        values = ', '.join("%s=%r" % (n, getattr(self, n)) for n in columns)
        return '<%s %s(%s)>' % (obj_id, self.__class__.__name__, values)
예제 #7
0
class DailyData(ResourceMixin, db.Model):
    __tablename__ = 'daily_data_'
    id = db.Column(db.Integer, primary_key=True)
    meter_id = db.Column(db.Integer,
                         db.ForeignKey('meters.id',
                                       onupdate='CASCADE',
                                       ondelete='CASCADE'),
                         unique=True,
                         index=True,
                         nullable=False)
    meter = db.relationship(Meter,
                            uselist=False,
                            backref='daily_data_',
                            passive_deletes=True)
    capture_time = db.Column(db.TIMESTAMP,
                             default=tzware_datetime,
                             unique=True)
    active_increase = db.Column(db.String(25),
                                nullable=False,
                                server_default='')
    total_active = db.Column(db.String(25), nullable=False, server_default='')
    import_active = db.Column(db.String(25), nullable=False, server_default='')
    export_active = db.Column(db.String(25), nullable=False, server_default='')
    import_apparent = db.Column(db.String(25),
                                nullable=False,
                                server_default='')
    export_apparent = db.Column(db.String(25),
                                nullable=False,
                                server_default='')
    import_reactive = db.Column(db.String(25),
                                nullable=False,
                                server_default='')
    export_reactive = db.Column(db.String(25),
                                nullable=False,
                                server_default='')

    def __init__(self, **kwargs):
        # Call Flask-SQLAlchemy's constructor.
        super(DailyData, self).__init__(**kwargs)

    def set_value(self, obis, value):
        if obis == "1.0.15.8.0.255":
            # cumulative_total_active_energy
            self.total_active = value
        elif obis == "1.0.1.8.0.255":
            # cumulative_import_active_energy
            self.import_active = value
        elif obis == "1.0.2.8.0.255":
            # cumulative_export_active_energy
            self.export_active = value
        elif obis == "1.0.3.8.0.255":
            # cumulative_import_reactive_energy
            self.import_reactive = value
        elif obis == "1.0.4.8.0.255":
            # cumulative_import_reactive_energy
            self.export_reactive = value
        elif obis == "1.0.9.8.0.255":
            # cumulative_import_apparent_energy
            self.import_apparent = value
        elif obis == "1.0.10.8.0.255":
            # cumulative_export_apparent_energy
            self.export_apparent = value
        elif obis == "1.0.15.19.0.255":
            # current_day_active_energy_increase
            self.active_increase = value

    @classmethod
    def query_search(cls, query):
        """
        Search a resource by 1 or more fields.

        :param query: Search query
        :type query: str
        :return: SQLAlchemy filter
        """
        if query:
            search_query = '%{0}%'.format(query)
            query_chain = (DailyData.meter.property.mapper.class_.
                           sequence_number.ilike(search_query),
                           DailyData.meter.property.mapper.class_.
                           serial_number.ilike(search_query))
            return or_(*query_chain)
        return ''

    @classmethod
    def date_search(cls, start_date, end_date):
        """
        Search a resource by 1 or more fields.

        :param end_date:
        :param start_date:
        :return: SQLAlchemy filter
        """
        if start_date and end_date:
            date_chain = (DailyData.capture_time >= start_date,
                          DailyData.capture_time <= end_date)
            return and_(*date_chain)
        return ''

    @property
    def serialize(self):
        return {
            'id': self.id,
            'meter_id': self.meter_id,
            'active_increase': self.active_increase,
            'total_active': self.total_active,
            'import_active': self.import_active,
            'export_active': self.export_active,
            'sequence_number': self.meter.sequence_number,
            'capture_time': self.capture_time,
        }
예제 #8
0
class AlertData(ResourceMixin, db.Model):
    __tablename__ = 'alerts'
    id = db.Column(db.Integer, primary_key=True)
    # Relationships.
    meter_id = db.Column(db.Integer,
                         db.ForeignKey('meters.id',
                                       onupdate='CASCADE',
                                       ondelete='CASCADE'),
                         index=True,
                         nullable=False)
    meter = db.relationship(Meter,
                            uselist=False,
                            backref='alerts',
                            passive_deletes=True)

    capture_time = db.Column(db.TIMESTAMP,
                             default=tzware_datetime,
                             unique=True,
                             index=True)
    code = db.Column(db.Integer)
    name = db.Column(db.String(25), nullable=False, server_default='')

    def __init__(self, **kwargs):
        # Call Flask-SQLAlchemy's constructor.
        super(AlertData, self).__init__(**kwargs)

    @classmethod
    def query_search(cls, query):
        """
        Search a resource by 1 or more fields.

        :param query: Search query
        :type query: str
        :return: SQLAlchemy filter
        """
        if query:
            search_query = '%{0}%'.format(query)
            query_chain = (AlertData.meter.property.mapper.class_.
                           sequence_number.ilike(search_query),
                           AlertData.meter.property.mapper.class_.
                           serial_number.ilike(search_query))
            return or_(*query_chain)
        return ''

    @classmethod
    def date_search(cls, start_date, end_date):
        """
        Search a resource by 1 or more fields.

        :param end_date:
        :param start_date:
        :return: SQLAlchemy filter
        """
        if start_date and end_date:
            date_chain = (AlertData.capture_time >= start_date,
                          AlertData.capture_time <= end_date)
            return and_(*date_chain)
        return ''

    @property
    def serialize(self):
        return {
            'id': self.id,
            'meter_id': self.meter_id,
            'code': self.code,
            'name': self.name,
            'sequence_number': self.meter.sequence_number,
            'capture_time': self.capture_time,
        }
예제 #9
0
class DemandData(ResourceMixin, db.Model):
    __tablename__ = 'demand_data_'
    id = db.Column(db.Integer, primary_key=True)
    meter_id = db.Column(db.Integer,
                         db.ForeignKey('meters.id',
                                       onupdate='CASCADE',
                                       ondelete='CASCADE'),
                         unique=True,
                         index=True,
                         nullable=False)
    meter = db.relationship(Meter,
                            uselist=False,
                            backref='demand_data',
                            passive_deletes=True)

    capture_time = db.Column(db.TIMESTAMP,
                             default=tzware_datetime,
                             unique=True,
                             index=True)
    total_active = db.Column(db.String(25), nullable=False, server_default='')

    import_active = db.Column(db.String(25), nullable=False, server_default='')
    export_active = db.Column(db.String(25), nullable=False, server_default='')

    total_import_apparent = db.Column(db.String(25),
                                      nullable=False,
                                      server_default='')
    total_export_apparent = db.Column(db.String(25),
                                      nullable=False,
                                      server_default='')

    power_on_duration = db.Column(db.String(25),
                                  nullable=False,
                                  server_default='')

    current_x = db.Column(db.String(255), nullable=False, server_default='')
    current_y = db.Column(db.String(255), nullable=False, server_default='')
    current_z = db.Column(db.String(255), nullable=False, server_default='')

    current_neutral = db.Column(db.String(255),
                                nullable=False,
                                server_default='')
    voltage_x = db.Column(db.String(255), nullable=False, server_default='')
    voltage_y = db.Column(db.String(255), nullable=False, server_default='')
    voltage_z = db.Column(db.String(255), nullable=False, server_default='')

    reactive_power = db.Column(db.String(25),
                               nullable=False,
                               server_default='')
    apparent_power = db.Column(db.String(25),
                               nullable=False,
                               server_default='')
    active_power = db.Column(db.String(25), nullable=False, server_default='')

    billing_count = db.Column(db.String(25), nullable=False, server_default='')
    output_state = db.Column(db.String(25), nullable=False, server_default='')
    power_down_count = db.Column(db.String(25),
                                 nullable=False,
                                 server_default='')
    program_count = db.Column(db.String(25), nullable=False, server_default='')
    tamper_count = db.Column(db.String(25), nullable=False, server_default='')

    def __init__(self, **kwargs):
        # Call Flask-SQLAlchemy's constructor.
        super(DemandData, self).__init__(**kwargs)

    @classmethod
    def query_search(cls, query):
        """
        Search a resource by 1 or more fields.

        :param query: Search query
        :type query: str
        :return: SQLAlchemy filter
        """
        if query:
            search_query = '%{0}%'.format(query)
            query_chain = (DemandData.meter.property.mapper.class_.
                           sequence_number.ilike(search_query),
                           DemandData.meter.property.mapper.class_.
                           serial_number.ilike(search_query))
            return or_(*query_chain)
        return ''

    @classmethod
    def date_search(cls, start_date, end_date):
        """
        Search a resource by 1 or more fields.

        :param end_date:
        :param start_date:
        :return: SQLAlchemy filter
        """
        if start_date and end_date:
            date_chain = (DemandData.capture_time >= start_date,
                          DemandData.capture_time <= end_date)
            return and_(*date_chain)
        return ''

    def set_value(self, obis, value):
        if obis == "0.0.96.3.10.255":
            # OUTPUT_STATE:
            self.output_state = value
        elif obis == "1.0.0.1.0.255":
            # BILLING_COUNT
            self.billing_count = value
        elif obis == "0.0.96.7.0.255":
            # POWER_DOWN_COUNT
            self.power_down_count = value
        elif obis == "0.0.96.2.0.255":
            # PROGRAM_COUNT
            self.program_count = value
        elif obis == "0.0.96.91.0.255":
            # TAMPER_COUNT
            self.tamper_count = value
        elif obis == "1.0.32.7.0.255":
            # VOLTAGE_PHASE_ONE
            self.voltage_x = value
        elif obis == "1.0.31.7.0.255":
            # CURRENT_PHASE_ONE
            self.current_x = value
        elif obis == "1.0.91.7.0.255":
            # NEUTRAL
            self.current_neutral = value
        elif obis == "1.0.1.7.0.255":
            # ACTIVE_POWER
            self.active_power = value
        elif obis == "1.0.3.7.0.255":
            # REACTIVE_POWER
            self.reactive_power = value
        elif obis == "1.0.9.7.0.255":
            # APPARENT_POWER
            self.apparent_power = value
        elif obis == "0.0.96.91.14.255":
            # POWER_ON_DURATION
            self.power_on_duration = value
        elif obis == "1.0.13.7.0.255":
            # POWER_FACTOR
            self.power_factor = value
        elif obis == "1.0.14.7.0.255":
            # FREQUENCY
            self.frequency = value
        elif obis == "1.0.51.7.0.255":
            # CURRENT_PHASE_TWO
            self.current_y = value
        elif obis == "1.0.52.7.0.255":
            # VOLTAGE_PHASE_TWO
            self.voltage_y = value
        elif obis == "1.0.71.7.0.255":
            # CURRENT_PHASE_THREE
            self.current_z = value
        elif obis == "1.0.72.7.0.255":
            # VOLTAGE_PHASE_THREE
            self.voltage_z = value
        elif obis == "1.0.9.8.0.255":
            # TOTAL_IMPORT_APPARENT
            self.total_import_apparent = value
        elif obis == "1.0.1.8.0.255":
            # TOTAL_IMPORT_ACTIVE
            self.total_import_active = value
        elif obis == "1.0.10.8.0.255":
            # TOTAL_EXPORT_APPARENT
            self.total_export_apparent = value
        elif obis == "1.0.2.8.0.255":
            # EXPORT_ACTIVE
            self.total_export_active = value
예제 #10
0
class HourlyData(ResourceMixin, db.Model):
    __tablename__ = 'hourly_data_'
    id = db.Column(db.Integer, primary_key=True)
    meter_id = db.Column(db.Integer,
                         db.ForeignKey('meters.id',
                                       onupdate='CASCADE',
                                       ondelete='CASCADE'),
                         unique=True,
                         index=True,
                         nullable=False)
    meter = db.relationship(Meter,
                            uselist=False,
                            backref='hourly_data',
                            passive_deletes=True)
    capture_time = db.Column(db.TIMESTAMP,
                             default=tzware_datetime,
                             unique=True,
                             index=True)
    block_import_active = db.Column(db.String(25),
                                    nullable=False,
                                    server_default='')
    block_export_active = db.Column(db.String(25),
                                    nullable=False,
                                    server_default='')
    block_import_apparent = db.Column(db.String(25),
                                      nullable=False,
                                      server_default='')
    block_export_apparent = db.Column(db.String(25),
                                      nullable=False,
                                      server_default='')
    block_import_reactive = db.Column(db.String(25),
                                      nullable=False,
                                      server_default='')
    block_export_reactive = db.Column(db.String(25),
                                      nullable=False,
                                      server_default='')
    profile_status = db.Column(db.String(25),
                               nullable=False,
                               server_default='')

    def __init__(self, **kwargs):
        # Call Flask-SQLAlchemy's constructor.
        super(HourlyData, self).__init__(**kwargs)

    def set_value(self, obis, value):
        if obis == "1.0.1.29.0.255":
            # BLOCK_IMPORT_ACTIVE = "1.0.1.29.0.255"
            self.block_import_active = value
        elif obis == "1.0.2.29.0.255":
            # BLOCK_EXPORT_ACTIVE = "1.0.2.29.0.255"
            self.block_export_active = value
        elif obis == "1.0.3.29.0.255":
            # BLOCK_IMPORT_REACTIVE = "1.0.3.29.0.255"
            self.block_export_reactive = value
        elif obis == "1.0.4.29.0.255":
            # BLOCK_EXPORT_REACTIVE = "1.0.4.29.0.255"
            self.block_export_reactive = value
        elif obis == "1.0.9.29.0.255":
            # BLOCK_IMPORT_APPARENT = "1.0.9.29.0.255"
            self.block_import_apparent = value
        elif obis == "1.0.10.29.0.255":
            # BLOCK_EXPORT_APPARENT = "1.0.10.29.0.255"
            self.block_export_apparent = value
        elif obis == "0.0.96.10.1.255":
            # PROFILE_STATUS = "0.0.96.10.1.255"
            self.profile_status = value

    @classmethod
    def query_search(cls, query):
        """
        Search a resource by 1 or more fields.

        :param query: Search query
        :type query: str
        :return: SQLAlchemy filter
        """
        if query:
            search_query = '%{0}%'.format(query)
            query_chain = (HourlyData.meter.property.mapper.class_.
                           sequence_number.ilike(search_query),
                           HourlyData.meter.property.mapper.class_.
                           serial_number.ilike(search_query))
            return or_(*query_chain)
        return ''

    @classmethod
    def date_search(cls, start_date, end_date):
        """
        Search a resource by 1 or more fields.

        :param end_date:
        :param start_date:
        :return: SQLAlchemy filter
        """
        if start_date and end_date:
            date_chain = (HourlyData.capture_time >= start_date,
                          HourlyData.capture_time <= end_date)
            return and_(*date_chain)
        return ''

    @property
    def serialize(self):
        return {
            'id': self.id,
            'meter_id': self.meter_id,
            'import_active': self.block_import_active,
            'export_active': self.block_export_active,
            'import_reactive': self.block_import_reactive,
            'export_reactive': self.block_export_reactive,
            'import_apparent': self.block_import_apparent,
            'bexport_apparent': self.block_export_apparent,
            'sequence_number': self.meter.sequence_number,
            'capture_time': self.capture_time,
        }