class Conditional(CRUDMixin, db.Model): __tablename__ = "conditional" id = db.Column(db.Integer, unique=True, primary_key=True) name = db.Column(db.Text, default='Conditional Name') conditional_type = db.Column(db.Text, default=None) is_activated = db.Column(db.Boolean, default=False) sensor_id = db.Column(db.Integer, db.ForeignKey('sensor.id'), default=None) # Which sensor does this belong? # Relay options if_relay_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) # Watch this relay for action if_relay_state = db.Column(db.Text, default='') # What action to watch relay for if_relay_duration = db.Column(db.Float, default=0.0) # Sensor options if_sensor_period = db.Column(db.Float, default=60.0) if_sensor_measurement = db.Column( db.Text, default='') # which measurement to monitor if_sensor_edge_select = db.Column( db.Text, default='edge') # monitor Rising, Falling, or Both switch edges if_sensor_edge_detected = db.Column(db.Text, default='rising') if_sensor_gpio_state = db.Column(db.Boolean, default=True) if_sensor_direction = db.Column(db.Text, default='') # 'above' or 'below' setpoint if_sensor_setpoint = db.Column(db.Float, default=0.0)
class ConditionalActions(CRUDMixin, db.Model): __tablename__ = "conditional_data" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) conditional_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) # Actions do_action = db.Column( db.Text, default='' ) # what action, such as 'email', 'execute command', 'flash LCD' do_action_string = db.Column( db.Text, default='') # string, such as the email address or command do_relay_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) do_relay_state = db.Column(db.Text, default='') # 'on' or 'off' do_relay_duration = db.Column(db.Float, default=0.0) do_camera_id = db.Column(db.Integer, db.ForeignKey('lcd.id'), default=None) do_camera_duration = db.Column(db.Float, default=0.0) do_lcd_id = db.Column(db.Integer, db.ForeignKey('lcd.id'), default=None) do_pid_id = db.Column(db.Integer, db.ForeignKey('pid.id'), default=None) def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class PID(CRUDMixin, db.Model): __tablename__ = "pid" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) # ID for influxdb entries name = db.Column(db.Text, default='PID') # PID Controller is_activated = db.Column(db.Boolean, default=False) is_held = db.Column(db.Boolean, default=False) is_paused = db.Column(db.Boolean, default=False) is_preset = db.Column(db.Boolean, default=False) # Is config saved as a preset? preset_name = db.Column(db.Text, default='') # Name for preset period = db.Column(db.Float, default=30.0) max_measure_age = db.Column(db.Float, default=120.0) measurement = db.Column( db.Text, default='') # What condition is the controller regulating? direction = db.Column( db.Text, default='raise') # Direction of regulation (raise, lower, both) setpoint = db.Column(db.Float, default=30.0) # PID setpoint band = db.Column(db.Float, default=0) # PID hysteresis band p = db.Column(db.Float, default=1.0) # Kp gain i = db.Column(db.Float, default=0.0) # Ki gain d = db.Column(db.Float, default=0.0) # Kd gain integrator_min = db.Column(db.Float, default=-100.0) integrator_max = db.Column(db.Float, default=100.0) raise_output_id = db.Column(db.String, db.ForeignKey('output.unique_id'), default=None) # Output to raise the condition raise_min_duration = db.Column(db.Float, default=0.0) raise_max_duration = db.Column(db.Float, default=0.0) raise_min_off_duration = db.Column(db.Float, default=0.0) lower_output_id = db.Column(db.String, db.ForeignKey('output.unique_id'), default=None) # Output to lower the condition lower_min_duration = db.Column(db.Float, default=0.0) lower_max_duration = db.Column(db.Float, default=0.0) lower_min_off_duration = db.Column(db.Float, default=0.0) store_lower_as_negative = db.Column(db.Boolean, default=True) # Setpoint tracking method_id = db.Column(db.String, db.ForeignKey('method.unique_id'), default='') method_start_time = db.Column(db.Text, default=None) method_end_time = db.Column(db.Text, default=None) # Autotune autotune_activated = db.Column(db.Boolean, default=False) autotune_noiseband = db.Column(db.Float, default=0.5) autotune_outstep = db.Column(db.Float, default=10.0) def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class MethodData(CRUDMixin, db.Model): __tablename__ = "method_data" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) method_id = db.Column(db.String, db.ForeignKey('method.unique_id'), default=None) time_start = db.Column(db.Text, default=None) time_end = db.Column(db.Text, default=None) duration_sec = db.Column(db.Float, default=None) duration_end = db.Column(db.Float, default=None) output_id = db.Column(db.String, db.ForeignKey('output.unique_id'), default=None) output_state = db.Column(db.Text, default=None) output_duration = db.Column(db.Float, default=None) setpoint_start = db.Column(db.Float, default=None) setpoint_end = db.Column(db.Float, default=None) amplitude = db.Column(db.Float, default=None) frequency = db.Column(db.Float, default=None) shift_angle = db.Column(db.Float, default=None) shift_y = db.Column(db.Float, default=None) x0 = db.Column(db.Float, default=None) y0 = db.Column(db.Float, default=None) x1 = db.Column(db.Float, default=None) y1 = db.Column(db.Float, default=None) x2 = db.Column(db.Float, default=None) y2 = db.Column(db.Float, default=None) x3 = db.Column(db.Float, default=None) y3 = db.Column(db.Float, default=None) linked_method_id = db.Column(db.String, db.ForeignKey('method.unique_id'), default=None) def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class Conditional(CRUDMixin, db.Model): __tablename__ = "conditional" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) name = db.Column(db.Text, default='Conditional Name') conditional_type = db.Column(db.Text, default=None) is_activated = db.Column(db.Boolean, default=False) # TODO: Make one variable 'unique_id' instead of non-unique ID, in next major version sensor_id = db.Column(db.Integer, db.ForeignKey('sensor.id'), default=None) # Which sensor does this belong? math_id = db.Column(db.Integer, db.ForeignKey('math.id'), default=None) # Which sensor does this belong? # Relay options if_relay_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) # Watch this relay for action if_relay_state = db.Column(db.Text, default='') # What action to watch relay for if_relay_duration = db.Column(db.Float, default=0.0) # Sensor/Math options # TODO: Make variable names more generic in next major version change sensor->measurement if_sensor_period = db.Column(db.Float, default=60.0) if_sensor_refractory_period = db.Column(db.Float, default=0.0) if_sensor_measurement = db.Column(db.Text, default='') # which measurement to monitor if_sensor_max_age = db.Column(db.Integer, default=120.0) # max age of the measurement if_sensor_edge_detected = db.Column(db.Text, default='') if_sensor_direction = db.Column(db.Text, default='') # 'above' or 'below' setpoint if_sensor_setpoint = db.Column(db.Float, default=0.0) def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class MethodData(CRUDMixin, db.Model): __tablename__ = "method_data" id = db.Column(db.Integer, unique=True, primary_key=True) method_id = db.Column(db.Integer, db.ForeignKey('method.id'), default=None) time_start = db.Column(db.Text, default=None) time_end = db.Column(db.Text, default=None) duration_sec = db.Column(db.Float, default=None) relay_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) relay_state = db.Column(db.Text, default=None) relay_duration = db.Column(db.Float, default=None) setpoint_start = db.Column(db.Float, default=None) setpoint_end = db.Column(db.Float, default=None) amplitude = db.Column(db.Float, default=None) frequency = db.Column(db.Float, default=None) shift_angle = db.Column(db.Float, default=None) shift_y = db.Column(db.Float, default=None) x0 = db.Column(db.Float, default=None) y0 = db.Column(db.Float, default=None) x1 = db.Column(db.Float, default=None) y1 = db.Column(db.Float, default=None) x2 = db.Column(db.Float, default=None) y2 = db.Column(db.Float, default=None) x3 = db.Column(db.Float, default=None) y3 = db.Column(db.Float, default=None) def __reper__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class LCDData(CRUDMixin, db.Model): __tablename__ = "lcd_data" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) lcd_id = db.Column(db.Integer, db.ForeignKey('lcd.id'), default=None) line_1_id = db.Column(db.Text, default='') line_1_type = db.Column(db.Text, default='') line_1_measurement = db.Column(db.Text, default='') line_1_max_age = db.Column(db.Integer, default=360) line_1_decimal_places = db.Column(db.Integer, default=2) line_2_id = db.Column(db.Text, default='') line_2_type = db.Column(db.Text, default='') line_2_measurement = db.Column(db.Text, default='') line_2_max_age = db.Column(db.Integer, default=360) line_2_decimal_places = db.Column(db.Integer, default=2) line_3_id = db.Column(db.Text, default='') line_3_type = db.Column(db.Text, default='') line_3_measurement = db.Column(db.Text, default='') line_3_max_age = db.Column(db.Integer, default=360) line_3_decimal_places = db.Column(db.Integer, default=2) line_4_id = db.Column(db.Text, default='') line_4_type = db.Column(db.Text, default='') line_4_measurement = db.Column(db.Text, default='') line_4_max_age = db.Column(db.Integer, default=360) line_4_decimal_places = db.Column(db.Integer, default=2) def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class User(UserMixin, CRUDMixin, db.Model): __tablename__ = "users" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.VARCHAR(64), unique=True, index=True) password_hash = db.Column(db.VARCHAR(255)) email = db.Column(db.VARCHAR(64), unique=True, index=True) role = db.Column(db.Integer, db.ForeignKey('roles.id'), default=None) theme = db.Column(db.VARCHAR(64)) roles = db.relationship("Role", back_populates="user") def __repr__(self): output = "<User: <name='{name}', email='{email}' is_admin='{isadmin}'>" return output.format(name=self.name, email=self.email, isadmin=bool(self.role == 1)) def set_password(self, new_password): """ saves a password hash """ self.password_hash = bcrypt.hashpw(new_password.encode('utf-8'), bcrypt.gensalt()) @staticmethod def check_password(password, hashed_password): """ validates a password """ hashes_match = bcrypt.hashpw(password.encode('utf-8'), hashed_password.encode('utf-8')) return hashes_match
class DeviceMeasurements(CRUDMixin, db.Model): __tablename__ = "device_measurements" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) name = db.Column(db.Text, default='') device_type = db.Column(db.Text, default=None) device_id = db.Column(db.Text, default=None) # Default measurement/unit is_enabled = db.Column(db.Boolean, default=True) measurement = db.Column(db.Text, default='') measurement_type = db.Column(db.Text, default='') unit = db.Column(db.Text, default='') channel = db.Column(db.Integer, default=None) # Rescale measurement invert_scale = db.Column(db.Boolean, default=False) rescaled_measurement = db.Column(db.Text, default='') rescaled_unit = db.Column(db.Text, default='') scale_from_min = db.Column(db.Float, default=0) scale_from_max = db.Column(db.Float, default=10) scale_to_min = db.Column(db.Float, default=0) scale_to_max = db.Column(db.Float, default=20) conversion_id = db.Column(db.Text, db.ForeignKey('conversion.unique_id'), default='')
class ConditionalConditions(CRUDMixin, db.Model): __tablename__ = "conditional_data" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) conditional_id = db.Column(db.String, db.ForeignKey('conditional.unique_id'), default=None) condition_type = db.Column(db.Text, default=None) # Sensor/Math measurement = db.Column(db.Text, default='') # which measurement to monitor max_age = db.Column(db.Integer, default=120) # max age of the measurement # GPIO State gpio_pin = db.Column(db.Integer, default=0) # Output State output_id = db.Column(db.Text, default='') # Controller controller_id = db.Column(db.Text, default='') def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class PID(CRUDMixin, db.Model): __tablename__ = "pid" id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) # ID for influxdb entries name = db.Column(db.Text, default='PID') is_activated = db.Column(db.Boolean, default=False) is_held = db.Column(db.Boolean, default=False) is_paused = db.Column(db.Boolean, default=False) is_preset = db.Column(db.Boolean, default=False) # Is config saved as a preset? preset_name = db.Column(db.Text, default='') # Name for preset period = db.Column(db.Float, default=30.0) max_measure_age = db.Column(db.Float, default=120.0) measurement = db.Column( db.Text, default='') # What condition is the controller regulating? direction = db.Column( db.Text, default='Raise') # Direction of regulation (raise, lower, both) setpoint = db.Column(db.Float, default=30.0) # PID setpoint method_id = db.Column(db.Integer, db.ForeignKey('method.id'), default=None) method_start_time = db.Column(db.Text, default=None) method_end_time = db.Column(db.Text, default=None) p = db.Column(db.Float, default=1.0) # Kp gain i = db.Column(db.Float, default=0.0) # Ki gain d = db.Column(db.Float, default=0.0) # Kd gain integrator_min = db.Column(db.Float, default=-100.0) integrator_max = db.Column(db.Float, default=100.0) raise_relay_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) # Output to raise the condition raise_min_duration = db.Column(db.Float, default=0.0) raise_max_duration = db.Column(db.Float, default=0.0) raise_min_off_duration = db.Column(db.Float, default=0.0) lower_relay_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) # Output to lower the condition lower_min_duration = db.Column(db.Float, default=0.0) lower_max_duration = db.Column(db.Float, default=0.0) lower_min_off_duration = db.Column(db.Float, default=0.0) def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class LCDData(CRUDMixin, db.Model): __tablename__ = "lcd_data" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) lcd_id = db.Column(db.String, db.ForeignKey('lcd.unique_id'), default=None) line_1_id = db.Column(db.Text, default='') line_1_text = db.Column(db.Text, default='Text to display') line_1_measurement = db.Column(db.Text, default='') line_1_max_age = db.Column(db.Integer, default=360) line_1_decimal_places = db.Column(db.Integer, default=2) line_2_id = db.Column(db.Text, default='') line_2_text = db.Column(db.Text, default='Text to display') line_2_measurement = db.Column(db.Text, default='') line_2_max_age = db.Column(db.Integer, default=360) line_2_decimal_places = db.Column(db.Integer, default=2) line_3_id = db.Column(db.Text, default='') line_3_text = db.Column(db.Text, default='Text to display') line_3_measurement = db.Column(db.Text, default='') line_3_max_age = db.Column(db.Integer, default=360) line_3_decimal_places = db.Column(db.Integer, default=2) line_4_id = db.Column(db.Text, default='') line_4_text = db.Column(db.Text, default='Text to display') line_4_measurement = db.Column(db.Text, default='') line_4_max_age = db.Column(db.Integer, default=360) line_4_decimal_places = db.Column(db.Integer, default=2) line_5_id = db.Column(db.Text, default='') line_5_text = db.Column(db.Text, default='Text to display') line_5_measurement = db.Column(db.Text, default='') line_5_max_age = db.Column(db.Integer, default=360) line_5_decimal_places = db.Column(db.Integer, default=2) line_6_id = db.Column(db.Text, default='') line_6_text = db.Column(db.Text, default='Text to display') line_6_measurement = db.Column(db.Text, default='') line_6_max_age = db.Column(db.Integer, default=360) line_6_decimal_places = db.Column(db.Integer, default=2) line_7_id = db.Column(db.Text, default='') line_7_text = db.Column(db.Text, default='Text to display') line_7_measurement = db.Column(db.Text, default='') line_7_max_age = db.Column(db.Integer, default=360) line_7_decimal_places = db.Column(db.Integer, default=2) line_8_id = db.Column(db.Text, default='') line_8_text = db.Column(db.Text, default='Text to display') line_8_measurement = db.Column(db.Text, default='') line_8_max_age = db.Column(db.Integer, default=360) line_8_decimal_places = db.Column(db.Integer, default=2) def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class EnergyUsage(CRUDMixin, db.Model): __tablename__ = "energy_usage" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) # ID for influxdb entries name = db.Column(db.Text, default='Name') device_id = db.Column(db.Text, default='') measurement_id = db.Column(db.Text, db.ForeignKey('device_measurements.unique_id'), default='')
class User(UserMixin, CRUDMixin, db.Model): __tablename__ = "users" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) name = db.Column(db.VARCHAR(64), unique=True, index=True) password_hash = db.Column(db.VARCHAR(255)) code = db.Column(db.Integer, default=None) api_key = db.Column(db.BLOB, unique=True) email = db.Column(db.VARCHAR(64), unique=True, index=True) role_id = db.Column(db.Integer, db.ForeignKey('roles.id'), default=None) theme = db.Column(db.VARCHAR(64)) landing_page = db.Column(db.Text, default='live') index_page = db.Column(db.Text, default='landing') language = db.Column( db.Text, default=None) # Force the web interface to use a specific language password_reset_code = db.Column(db.Text, default=None) password_reset_code_expiration = db.Column(db.DateTime, default=None) password_reset_last_request = db.Column(db.DateTime, default=None) # roles = db.relationship("Role", back_populates="user") def __repr__(self): output = "<User: <name='{name}', email='{email}' is_admin='{isadmin}'>" return output.format(name=self.name, email=self.email, isadmin=bool(self.role_id == 1)) def set_password(self, new_password): """saves a password hash """ if isinstance(new_password, str): new_password = new_password.encode('utf-8') self.password_hash = bcrypt.hashpw(new_password, bcrypt.gensalt()) @staticmethod def check_password(password, hashed_password): """validates a password.""" # Check type of password hashed_password to determine if it is a str # and should be encoded if isinstance(password, str): password = password.encode('utf-8') if isinstance(hashed_password, str): hashed_password = hashed_password.encode('utf-8') hashes_match = bcrypt.hashpw(password, hashed_password) return hashes_match
class Camera(CRUDMixin, db.Model): __tablename__ = "camera" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) name = db.Column(db.Text, unique=True, nullable=False) library = db.Column(db.Text, nullable=False) device = db.Column(db.Text, nullable=False, default='/dev/video0') opencv_device = db.Column(db.Integer, default=0) hflip = db.Column(db.Boolean, default=False) # Horizontal flip image vflip = db.Column(db.Boolean, default=False) # Vertical flip image rotation = db.Column(db.Integer, default=0) # Rotation degree (0-360) height = db.Column(db.Integer, default=480) width = db.Column(db.Integer, default=640) brightness = db.Column(db.Float, default=None) contrast = db.Column(db.Float, default=None) exposure = db.Column(db.Float, default=None) gain = db.Column(db.Float, default=None) hue = db.Column(db.Float, default=None) saturation = db.Column(db.Float, default=0.3) white_balance = db.Column(db.Float, default=0.0) custom_options = db.Column(db.Text, default='') output_id = db.Column(db.String, db.ForeignKey('output.unique_id'), default=None) # Turn output on during capture output_duration = db.Column(db.Float, default=3.0) cmd_pre_camera = db.Column(db.Text, default='') # Command to execute before capture cmd_post_camera = db.Column(db.Text, default='') # Command to execute after capture stream_started = db.Column(db.Boolean, default=False) timelapse_started = db.Column(db.Boolean, default=False) timelapse_paused = db.Column(db.Boolean, default=False) timelapse_start_time = db.Column(db.Float, default=None) timelapse_end_time = db.Column(db.Float, default=None) timelapse_interval = db.Column(db.Float, default=None) timelapse_next_capture = db.Column(db.Float, default=None) timelapse_capture_number = db.Column(db.Integer, default=None) path_still = db.Column(db.Text, default='') path_timelapse = db.Column(db.Text, default='') path_video = db.Column(db.Text, default='') def __repr__(self): return "<{cls}(id={s.id}, name='{s.name}', library='{s.library}')>".format( s=self, cls=self.__class__.__name__)
class ConditionalActions(CRUDMixin, db.Model): __tablename__ = "conditional_data" id = db.Column(db.Integer, unique=True, primary_key=True) conditional_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) # Actions do_action = db.Column( db.Text, default='' ) # what action, such as 'email', 'execute command', 'flash LCD' do_action_string = db.Column( db.Text, default='') # string, such as the email address or command do_relay_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) do_relay_state = db.Column(db.Text, default='') # 'on' or 'off' do_relay_duration = db.Column(db.Float, default=0.0) do_camera_id = db.Column(db.Integer, db.ForeignKey('lcd.id'), default=None) do_camera_duration = db.Column(db.Float, default=0.0) do_lcd_id = db.Column(db.Integer, db.ForeignKey('lcd.id'), default=None) do_pid_id = db.Column(db.Integer, db.ForeignKey('pid.id'), default=None)
class Timer(CRUDMixin, db.Model): __tablename__ = "timer" id = db.Column(db.Integer, unique=True, primary_key=True) name = db.Column(db.Text, default='Timer') is_activated = db.Column(db.Boolean, default=False) timer_type = db.Column(db.Text, default=None) relay_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) state = db.Column(db.Text, default=None) # 'on' or 'off' time_start = db.Column(db.Text, default=None) time_end = db.Column(db.Text, default=None) duration_on = db.Column(db.Float, default=None) duration_off = db.Column(db.Float, default=None) def __reper__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class Camera(CRUDMixin, db.Model): __tablename__ = "camera" id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) name = db.Column(db.Text, unique=True, nullable=False) camera_type = db.Column(db.Text, nullable=False) library = db.Column(db.Text, nullable=False) opencv_device = db.Column(db.Integer, default=0) hflip = db.Column(db.Boolean, default=False) # Horizontal flip image vflip = db.Column(db.Boolean, default=False) # Vertical flip image rotation = db.Column(db.Integer, default=0) # Rotation degree (0-360) height = db.Column(db.Integer, default=640) width = db.Column(db.Integer, default=480) brightness = db.Column(db.Float, default=0.75) contrast = db.Column(db.Float, default=0.2) exposure = db.Column(db.Float, default=0.0) gain = db.Column(db.Float, default=0.0) hue = db.Column(db.Float, default=0.0) saturation = db.Column(db.Float, default=0.3) white_balance = db.Column(db.Float, default=0.0) relay_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) # Turn relay on during capture cmd_pre_camera = db.Column(db.Text, default='') # Command to execute before capture cmd_post_camera = db.Column(db.Text, default='') # Command to execute after capture stream_started = db.Column(db.Boolean, default=False) timelapse_started = db.Column(db.Boolean, default=False) timelapse_paused = db.Column(db.Boolean, default=False) timelapse_start_time = db.Column(db.Float, default=None) timelapse_end_time = db.Column(db.Float, default=None) timelapse_interval = db.Column(db.Float, default=None) timelapse_next_capture = db.Column(db.Float, default=None) timelapse_capture_number = db.Column(db.Integer, default=None) def __reper__(self): return "<{cls}(id={s.id}, name='{s.name}', camera_type='{s.camera_type}')>".format( s=self, cls=self.__class__.__name__)
class Timer(CRUDMixin, db.Model): __tablename__ = "timer" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) name = db.Column(db.Text, default='Timer') is_activated = db.Column(db.Boolean, default=False) timer_type = db.Column(db.Text, default=None) method_id = db.Column( db.Integer, default=None) # TODO: Add ForeignKey in next major release method_start_time = db.Column(db.Text, default=None) method_end_time = db.Column(db.Text, default=None) method_period = db.Column(db.Float, default=None) relay_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) state = db.Column(db.Text, default=None) # 'on' or 'off' time_start = db.Column(db.Text, default=None) time_end = db.Column(db.Text, default=None) duration_on = db.Column(db.Float, default=None) duration_off = db.Column(db.Float, default=None) def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class Input(CRUDMixin, db.Model): __tablename__ = "input" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) name = db.Column(db.Text, default='Input Name') is_activated = db.Column(db.Boolean, default=False) log_level_debug = db.Column(db.Boolean, default=False) is_preset = db.Column(db.Boolean, default=False) # Is config saved as a preset? preset_name = db.Column(db.Text, default=None) # Name for preset device = db.Column( db.Text, default='') # Device name, such as DHT11, DHT22, DS18B20 interface = db.Column( db.Text, default=None) # Communication interface (I2C, UART, etc.) period = db.Column(db.Float, default=15.0) # Duration between readings start_offset = db.Column(db.Float, default=0.0) power_output_id = db.Column(db.String, default=None) resolution = db.Column(db.Integer, default=0) resolution_2 = db.Column(db.Integer, default=0) sensitivity = db.Column(db.Integer, default=0) thermocouple_type = db.Column(db.Text, default=None) ref_ohm = db.Column(db.Integer, default=None) calibrate_sensor_measure = db.Column( db.Text, default=None) # sensor ID and measurement (CSV) location = db.Column( db.Text, default='') # GPIO pin or i2c address to communicate with sensor gpio_location = db.Column( db.Integer, default=None) # Pin location for GPIO communication # I2C i2c_location = db.Column( db.Text, default=None) # Address location for I2C communication i2c_bus = db.Column(db.Integer, default=1) # I2C bus the sensor is connected to # FTDI ftdi_location = db.Column( db.Text, default=None) # Device location for FTDI communication # Communication (SPI) uart_location = db.Column( db.Text, default=None) # Device location for UART communication baud_rate = db.Column(db.Integer, default=None) # Baud rate for UART communication pin_clock = db.Column(db.Integer, default=None) pin_cs = db.Column(db.Integer, default=None) pin_mosi = db.Column(db.Integer, default=None) pin_miso = db.Column(db.Integer, default=None) # Communication (Bluetooth) bt_adapter = db.Column(db.Text, default='hci0') # Switch options switch_edge = db.Column(db.Text, default='rising') switch_bouncetime = db.Column(db.Integer, default=50) switch_reset_period = db.Column(db.Integer, default=10) # Pre-measurement output options pre_output_id = db.Column( db.String, db.ForeignKey('output.unique_id'), default=None) # Output to turn on before sensor read pre_output_duration = db.Column( db.Float, default=0.0) # Duration to turn output on before sensor read pre_output_during_measure = db.Column(db.Boolean, default=True) # SHT sensor options sht_voltage = db.Column(db.Text, default='3.5') # Analog to digital converter options adc_gain = db.Column(db.Integer, default=1) adc_resolution = db.Column(db.Integer, default=18) adc_sample_speed = db.Column(db.Text, default='') # Command options cmd_command = db.Column(db.Text, default=None) # PWM and RPM options weighting = db.Column(db.Float, default=0.0) rpm_pulses_per_rev = db.Column(db.Float, default=1.0) sample_time = db.Column(db.Float, default=2.0) # Server options port = db.Column(db.Integer, default=80) times_check = db.Column(db.Integer, default=1) deadline = db.Column(db.Integer, default=2) # The Things Network: Data Storage datetime = db.Column(db.DateTime, default=None) custom_options = db.Column(db.Text, default='') def is_active(self): """ :return: Whether the sensor is currently activated :rtype: bool """ return self.is_activated def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class Sensor(CRUDMixin, db.Model): __tablename__ = "sensor" id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) # ID for influxdb entries name = db.Column(db.Text, default='Sensor') is_activated = db.Column(db.Boolean, default=False) is_preset = db.Column(db.Boolean, default=False) # Is config saved as a preset? preset_name = db.Column(db.Text, default=None) # Name for preset device = db.Column( db.Text, default='') # Device name, such as DHT11, DHT22, DS18B20 interface = db.Column( db.Text, default=None) # Communication interface (I2C, UART, etc.) device_loc = db.Column( db.Text, default=None) # Device location for UART communication calibrate_sensor_measure = db.Column( db.Text, default=None) # sensor ID and measurement (CSV) baud_rate = db.Column(db.Integer, default=None) # Baud rate for UART communication period = db.Column(db.Float, default=15.0) # Duration between readings i2c_bus = db.Column(db.Integer, default='') # I2C bus the sensor is connected to location = db.Column( db.Text, default='') # GPIO pin or i2c address to communicate with sensor power_relay_id = db.Column(db.Integer, db.ForeignKey('relay.id'), default=None) # Relay to power sensor measurements = db.Column(db.Text, default='') # Measurements separated by commas resolution = db.Column(db.Integer, default=0) sensitivity = db.Column(db.Integer, default=0) # Multiplexer options multiplexer_address = db.Column(db.Text, default=None) multiplexer_bus = db.Column(db.Integer, default=1) multiplexer_channel = db.Column(db.Integer, default=0) # Switch options switch_edge = db.Column(db.Text, default='rising') switch_bouncetime = db.Column(db.Integer, default=50) switch_reset_period = db.Column(db.Integer, default=10) # Pre-measurement relay options pre_relay_id = db.Column( db.Integer, db.ForeignKey('relay.id'), default=None) # Relay to turn on before sensor read pre_relay_duration = db.Column( db.Float, default=0.0) # Duration to turn relay on before sensor read # SHT sensor options sht_clock_pin = db.Column(db.Integer, default=0) sht_voltage = db.Column(db.Text, default='3.5') # Analog to digital converter options adc_channel = db.Column(db.Integer, default=0) adc_gain = db.Column(db.Integer, default=1) adc_resolution = db.Column(db.Integer, default=18) adc_measure = db.Column(db.Text, default='Condition') adc_measure_units = db.Column(db.Text, default='unit') adc_volts_min = db.Column(db.Float, default=None) adc_volts_max = db.Column(db.Float, default=None) adc_units_min = db.Column(db.Float, default=0) adc_units_max = db.Column(db.Float, default=10) def is_active(self): """ :return: Whether the sensor is currently activated :rtype: bool """ return self.is_activated def __reper__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class Output(CRUDMixin, db.Model): __tablename__ = "output" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) # ID for influxdb entries output_type = db.Column( db.Text, default='wired' ) # Options: 'command', 'wired', 'wireless_rpi_rf', 'pwm' output_mode = db.Column(db.Text, default=None) interface = db.Column(db.Text, default='') location = db.Column(db.Text, default='') i2c_bus = db.Column(db.Integer, default=None) baud_rate = db.Column(db.Integer, default=None) name = db.Column(db.Text, default='Output') measurement = db.Column(db.Text, default=None) unit = db.Column(db.Text, default=None) conversion_id = db.Column(db.Text, db.ForeignKey('conversion.unique_id'), default='') channel = db.Column(db.Integer, default=None) pin = db.Column(db.Integer, default=None) # Pin connected to the device/output on_state = db.Column( db.Boolean, default=True) # GPIO output to turn output on (True=HIGH, False=LOW) amps = db.Column( db.Float, default=0.0) # The current drawn by the device connected to the output on_until = db.Column( db.DateTime, default=None) # Stores time to turn off output (if on for a duration) off_until = db.Column( db.DateTime, default=None) # Stores time the output can turn on again last_duration = db.Column( db.Float, default=None) # Stores the last on duration (seconds) on_duration = db.Column( db.Boolean, default=None) # Stores if the output is currently on for a duration protocol = db.Column(db.Integer, default=None) pulse_length = db.Column(db.Integer, default=None) on_command = db.Column(db.Text, default=None) off_command = db.Column(db.Text, default=None) pwm_command = db.Column(db.Text, default=None) trigger_functions_at_start = db.Column(db.Boolean, default=True) state_startup = db.Column(db.Text, default=None) startup_value = db.Column(db.Float, default=0) state_shutdown = db.Column(db.Text, default=None) shutdown_value = db.Column(db.Float, default=0) # PWM pwm_hertz = db.Column(db.Integer, default=None) # PWM Hertz pwm_library = db.Column(db.Text, default=None) # Library to produce PWM pwm_invert_signal = db.Column( db.Boolean, default=False) # 90% duty cycle would become 10% # Atlas EZO-PMP flow_rate = db.Column(db.Float, default=None) # example: ml per minute def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__) def _is_setup(self): """ This function checks to see if the GPIO pin is setup and ready to use. This is for safety and to make sure we don't blow anything. # TODO Make it do that. :return: Is it safe to manipulate this output? :rtype: bool """ if self.output_type == 'wired' and self.pin: self.setup_pin() return True def setup_pin(self): """ Setup pin for this output :rtype: None """ try: from RPi import GPIO GPIO.setmode(GPIO.BCM) GPIO.setwarnings(True) GPIO.setup(self.pin, GPIO.OUT) except: print("RPi.GPIO and Raspberry Pi required for this action") def is_on(self): """ :return: Whether the output is currently "ON" :rtype: bool """ if self.output_type == 'wired' and self._is_setup(): return self.on_state == GPIO.input(self.pin)
class Input(CRUDMixin, db.Model): __tablename__ = "input" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) name = db.Column(db.Text, default='Input Name') is_activated = db.Column(db.Boolean, default=False) is_preset = db.Column(db.Boolean, default=False) # Is config saved as a preset? preset_name = db.Column(db.Text, default=None) # Name for preset device = db.Column( db.Text, default='') # Device name, such as DHT11, DHT22, DS18B20 interface = db.Column( db.Text, default=None) # Communication interface (I2C, UART, etc.) device_loc = db.Column( db.Text, default=None) # Device location for UART communication calibrate_sensor_measure = db.Column( db.Text, default=None) # sensor ID and measurement (CSV) baud_rate = db.Column(db.Integer, default=None) # Baud rate for UART communication period = db.Column(db.Float, default=15.0) # Duration between readings i2c_bus = db.Column(db.Integer, default='') # I2C bus the sensor is connected to location = db.Column( db.Text, default='') # GPIO pin or i2c address to communicate with sensor power_output_id = db.Column(db.String, default=None) measurements = db.Column(db.Text, default='') # Measurements separated by commas resolution = db.Column(db.Integer, default=0) sensitivity = db.Column(db.Integer, default=0) thermocouple_type = db.Column(db.Text, default=None) ref_ohm = db.Column(db.Integer, default=None) convert_to_unit = db.Column(db.Text, default='') # Communication (SPI) pin_clock = db.Column(db.Integer, default=None) pin_cs = db.Column(db.Integer, default=None) pin_mosi = db.Column(db.Integer, default=None) pin_miso = db.Column(db.Integer, default=None) # Switch options switch_edge = db.Column(db.Text, default='rising') switch_bouncetime = db.Column(db.Integer, default=50) switch_reset_period = db.Column(db.Integer, default=10) # Pre-measurement output options pre_output_id = db.Column( db.String, db.ForeignKey('output.unique_id'), default=None) # Output to turn on before sensor read pre_output_duration = db.Column( db.Float, default=0.0) # Duration to turn output on before sensor read pre_output_during_measure = db.Column(db.Boolean, default=True) # SHT sensor options sht_voltage = db.Column(db.Text, default='3.5') # Analog to digital converter options adc_channel = db.Column(db.Integer, default=0) adc_gain = db.Column(db.Integer, default=1) adc_resolution = db.Column(db.Integer, default=18) adc_measure = db.Column(db.Text, default=None) adc_measure_units = db.Column(db.Text, default=None) adc_volts_min = db.Column(db.Float, default=None) adc_volts_max = db.Column(db.Float, default=None) adc_units_min = db.Column(db.Float, default=0.0) adc_units_max = db.Column(db.Float, default=10) adc_inverse_unit_scale = db.Column(db.Boolean, default=False) # Command options cmd_command = db.Column(db.Text, default=None) cmd_measurement = db.Column(db.Text, default=None) cmd_measurement_units = db.Column(db.Text, default=None) # PWM and RPM options weighting = db.Column(db.Float, default=0.0) rpm_pulses_per_rev = db.Column(db.Float, default=1.0) sample_time = db.Column(db.Float, default=2.0) # Server options port = db.Column(db.Integer, default=80) times_check = db.Column(db.Integer, default=1) deadline = db.Column(db.Integer, default=2) def is_active(self): """ :return: Whether the sensor is currently activated :rtype: bool """ return self.is_activated def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)
class Camera(CRUDMixin, db.Model): __tablename__ = "camera" __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, unique=True, primary_key=True) unique_id = db.Column(db.String, nullable=False, unique=True, default=set_uuid) name = db.Column(db.Text, unique=True, nullable=False) library = db.Column(db.Text, nullable=False) device = db.Column(db.Text, nullable=False, default='/dev/video0') opencv_device = db.Column(db.Integer, default=0) hflip = db.Column(db.Boolean, default=False) # Horizontal flip image vflip = db.Column(db.Boolean, default=False) # Vertical flip image rotation = db.Column(db.Integer, default=0) # Rotation degree (0-360) brightness = db.Column(db.Float, default=0) contrast = db.Column(db.Float, default=0) exposure = db.Column(db.Float, default=None) gain = db.Column(db.Float, default=None) hue = db.Column(db.Float, default=None) saturation = db.Column(db.Float, default=0) white_balance = db.Column(db.Float, default=0.0) custom_options = db.Column(db.Text, default='') output_id = db.Column(db.String, db.ForeignKey('output.unique_id'), default=None) # Turn output on during capture output_duration = db.Column(db.Float, default=3.0) cmd_pre_camera = db.Column(db.Text, default='') # Command to execute before capture cmd_post_camera = db.Column(db.Text, default='') # Command to execute after capture stream_started = db.Column(db.Boolean, default=False) hide_still = db.Column(db.Boolean, default=False) hide_timelapse = db.Column(db.Boolean, default=False) url_still = db.Column(db.Text, default='') url_stream = db.Column(db.Text, default='') show_preview = db.Column(db.Boolean, default=False) output_format = db.Column(db.Text, default=None) # Timelapse timelapse_started = db.Column(db.Boolean, default=False) timelapse_paused = db.Column(db.Boolean, default=False) timelapse_start_time = db.Column(db.Float, default=None) timelapse_end_time = db.Column(db.Float, default=None) timelapse_interval = db.Column(db.Float, default=None) timelapse_next_capture = db.Column(db.Float, default=None) timelapse_capture_number = db.Column(db.Integer, default=None) timelapse_last_file = db.Column(db.Text, default=None) timelapse_last_ts = db.Column(db.Float, default=None) # Still tracking still_last_file = db.Column(db.Text, default=None) still_last_ts = db.Column(db.Float, default=None) # Paths path_still = db.Column(db.Text, default='') path_timelapse = db.Column(db.Text, default='') path_video = db.Column(db.Text, default='') # Resolutions and stream width = db.Column(db.Integer, default=1024) height = db.Column(db.Integer, default=768) resolution_stream_width = db.Column(db.Integer, default=1024) resolution_stream_height = db.Column(db.Integer, default=768) stream_fps = db.Column(db.Integer, default=5) # picamera options # TODO: Change to generic variable names next major release picamera_shutter_speed = db.Column(db.Integer, default=0) picamera_sharpness = db.Column(db.Integer, default=0) picamera_iso = db.Column(db.Integer, default=0) picamera_awb = db.Column(db.Text, default='auto') picamera_awb_gain_red = db.Column(db.Float, default=0.5) picamera_awb_gain_blue = db.Column(db.Float, default=0.5) picamera_exposure_mode = db.Column(db.Text, default='auto') picamera_meter_mode = db.Column(db.Text, default='average') picamera_image_effect = db.Column(db.Text, default='none') def __repr__(self): return "<{cls}(id={s.id}, name='{s.name}', library='{s.library}')>".format( s=self, cls=self.__class__.__name__)