diff --git a/.gitignore b/.gitignore index c286ec9f3..85142b006 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ site/ env/ .venv /databases/flask_secret_key +/mycodo/config_override.py *.db *.pem *.bak diff --git a/CHANGELOG.md b/CHANGELOG.md index 494dc9f93..6a2005400 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,16 @@ ## 8.16.1 (Unreleased) +This release introduces the ability to override MYCODO_DB_PATH, SQLALCHEMY_DATABASE_URI, and ALEMBIC_URL in mycodo/config.py to use an alternate settings database. This is accomplished by creating these variables in mycodo/config_override.py. This new config file will be checked on startup and will persist after upgrades. + ### Bugfixes - Fix restoring mycodo/user_scripts during upgrade - Fix documentation generation + - Fix theming on selection inputs ### Features + - Add ability to use alternate mysql server using config_override.py - Add Output: PWM Raspberry Pi GPIO (RPi.GPIO) (for Pi <= 4, since pigpiod is deprecated) ### Miscellaneous diff --git a/mycodo/config.py b/mycodo/config.py index 13195cfb3..2f1d5620c 100644 --- a/mycodo/config.py +++ b/mycodo/config.py @@ -4,6 +4,7 @@ # import binascii import sys +import subprocess from datetime import timedelta import os @@ -11,7 +12,12 @@ # Append proper path for other software reading this config file sys.path.append(os.path.abspath(os.path.dirname(__file__))) + from config_translations import TRANSLATIONS as T +try: + import config_override +except: + pass MYCODO_VERSION = '8.16.0' ALEMBIC_VERSION = '5966b3569c89' @@ -27,7 +33,7 @@ # Used to determine proper upgrade page to display FINAL_RELEASES = ['5.7.3', '6.4.7', '7.10.0'] -# ENABLE FLASK PROFILER +# Flask Profiler # Accessed at https://127.0.0.1/mycodo-flask-profiler ENABLE_FLASK_PROFILER = False @@ -35,12 +41,24 @@ INSTALL_DIRECTORY = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/..') # Database +DATABASE_PATH = os.path.join(INSTALL_DIRECTORY, 'databases') DATABASE_NAME = "mycodo.db" +SQL_DATABASE_MYCODO = os.path.join(DATABASE_PATH, DATABASE_NAME) +try: + MYCODO_DB_PATH = config_override.MYCODO_DB_PATH +except: + MYCODO_DB_PATH = f'sqlite:///{SQL_DATABASE_MYCODO}' + +# Alembic ALEMBIC_PATH = os.path.join(INSTALL_DIRECTORY, 'alembic_db') -DATABASE_PATH = os.path.join(INSTALL_DIRECTORY, 'databases') ALEMBIC_UPGRADE_POST = os.path.join(ALEMBIC_PATH, 'alembic_post_upgrade_versions') -SQL_DATABASE_MYCODO = os.path.join(DATABASE_PATH, DATABASE_NAME) -MYCODO_DB_PATH = f'sqlite:///{SQL_DATABASE_MYCODO}' +try: # Ensure the correct alembic url is set + ALEMBIC_URL = config_override.ALEMBIC_URL + cmd = f'/opt/Mycodo/env/bin/crudini --set /opt/Mycodo/alembic_db/alembic.ini alembic sqlalchemy.url {ALEMBIC_URL}' + subprocess.Popen(cmd, shell=True) +except: + cmd = '/opt/Mycodo/env/bin/crudini --set /opt/Mycodo/alembic_db/alembic.ini alembic sqlalchemy.url sqlite:///../databases/mycodo.db' + subprocess.Popen(cmd, shell=True) # Misc paths PATH_1WIRE = '/sys/bus/w1/devices/' @@ -532,9 +550,11 @@ class ProdConfig(object): """Production Configuration.""" - SQL_DATABASE_MYCODO = os.path.join(DATABASE_PATH, DATABASE_NAME) - MYCODO_DB_PATH = f'sqlite:///{SQL_DATABASE_MYCODO}' - SQLALCHEMY_DATABASE_URI = f'sqlite:///{SQL_DATABASE_MYCODO}' + try: + SQLALCHEMY_DATABASE_URI = config_override.MYCODO_DB_PATH + except: + SQLALCHEMY_DATABASE_URI = MYCODO_DB_PATH + SQLALCHEMY_TRACK_MODIFICATIONS = False FLASK_PROFILER = { diff --git a/mycodo/databases/models/camera.py b/mycodo/databases/models/camera.py index 07dc5368a..81121369a 100644 --- a/mycodo/databases/models/camera.py +++ b/mycodo/databases/models/camera.py @@ -9,7 +9,7 @@ class Camera(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), 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') @@ -25,7 +25,7 @@ class Camera(CRUDMixin, db.Model): 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_id = db.Column(db.String(36), 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 diff --git a/mycodo/databases/models/controller.py b/mycodo/databases/models/controller.py index df61fb007..d52f72feb 100644 --- a/mycodo/databases/models/controller.py +++ b/mycodo/databases/models/controller.py @@ -10,7 +10,7 @@ class CustomController(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) name = db.Column(db.Text, default='Custom Function') position_y = db.Column(db.Integer, default=0) device = db.Column(db.Text, default='') @@ -41,8 +41,8 @@ class FunctionChannel(CRUDMixin, db.Model): __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) - function_id = db.Column(db.Text, default=None) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) + function_id = db.Column(db.String(36), default=None) channel = db.Column(db.Integer, default=None) name = db.Column(db.Text, default='') diff --git a/mycodo/databases/models/dashboard.py b/mycodo/databases/models/dashboard.py index c9e49226b..1e0653b0f 100644 --- a/mycodo/databases/models/dashboard.py +++ b/mycodo/databases/models/dashboard.py @@ -9,7 +9,7 @@ class Dashboard(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) name = db.Column(db.Text, nullable=False, unique=True) locked = db.Column(db.Boolean, default=False) @@ -19,9 +19,9 @@ class Widget(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) graph_type = db.Column(db.Text, default=None) - dashboard_id = db.Column(db.String, default=None) + dashboard_id = db.Column(db.String(36), default=None) name = db.Column(db.Text, default='Widget') log_level_debug = db.Column(db.Boolean, default=False) font_em_name = db.Column(db.Float, default=1.0) @@ -75,7 +75,7 @@ class Widget(CRUDMixin, db.Model): enable_output_controls = db.Column(db.Boolean, default=True) # Show output controls on dashboard element show_pid_info = db.Column(db.Boolean, default=True) # Display detailed information about the PID show_set_setpoint = db.Column(db.Boolean, default=True) # Display set PID setpoint - camera_id = db.Column(db.Text, default='') # store camera ID to display + camera_id = db.Column(db.String(36), default='') # store camera ID to display camera_image_type = db.Column(db.Text, default='') # save new image, overwrite old, display last timelapse camera_max_age = db.Column(db.Integer, default=360) # max camera image age before "No new image" shown diff --git a/mycodo/databases/models/function.py b/mycodo/databases/models/function.py index 3a5f6c024..1ab6f2fb6 100644 --- a/mycodo/databases/models/function.py +++ b/mycodo/databases/models/function.py @@ -10,7 +10,7 @@ class Function(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) function_type = db.Column(db.Text, default='') name = db.Column(db.Text, default='Function Name') position_y = db.Column(db.Integer, default=0) @@ -22,7 +22,7 @@ class Conditional(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) name = db.Column(db.Text, default='Conditional') position_y = db.Column(db.Integer, default=0) @@ -46,8 +46,8 @@ class ConditionalConditions(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) + conditional_id = db.Column(db.String(36), default=None) condition_type = db.Column(db.Text, default=None) # Sensor @@ -58,10 +58,10 @@ class ConditionalConditions(CRUDMixin, db.Model): gpio_pin = db.Column(db.Integer, default=0) # Output State - output_id = db.Column(db.Text, default='') + output_id = db.Column(db.String(36), default='') # Controller - controller_id = db.Column(db.Text, default='') + controller_id = db.Column(db.String(36), default='') def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__) @@ -72,7 +72,7 @@ class Trigger(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) trigger_type = db.Column(db.Text, default=None) name = db.Column(db.Text, default='Trigger Name') position_y = db.Column(db.Integer, default=0) @@ -80,9 +80,9 @@ class Trigger(CRUDMixin, db.Model): log_level_debug = db.Column(db.Boolean, default=False) # Used to hold unique IDs - unique_id_1 = db.Column(db.String, default=None) - unique_id_2 = db.Column(db.String, default=None) - unique_id_3 = db.Column(db.String, default=None) + unique_id_1 = db.Column(db.String(36), default=None) + unique_id_2 = db.Column(db.String(36), default=None) + unique_id_3 = db.Column(db.String(36), default=None) # Output output_state = db.Column(db.Text, default='') # What action to watch output for @@ -130,8 +130,8 @@ class Actions(CRUDMixin, db.Model): __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) - function_id = db.Column(db.String, default=None) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) + function_id = db.Column(db.String(36), default=None) function_type = db.Column(db.Text, default='') action_type = db.Column(db.Text, default='') # what action, such as 'email', 'execute command', 'flash LCD' @@ -139,7 +139,7 @@ class Actions(CRUDMixin, db.Model): # Actions pause_duration = db.Column(db.Float, default=5.0) - do_unique_id = db.Column(db.Text, default='') + do_unique_id = db.Column(db.String(36), default='') do_action_string = db.Column(db.Text, default='') # string, such as the email address or command do_output_state = db.Column(db.Text, default='') # 'on' or 'off' do_output_amount = db.Column(db.Float, default=0.0) diff --git a/mycodo/databases/models/input.py b/mycodo/databases/models/input.py index 99f64d502..24ea282ae 100644 --- a/mycodo/databases/models/input.py +++ b/mycodo/databases/models/input.py @@ -10,7 +10,7 @@ class Input(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) device = db.Column(db.Text, default='') # Device name, such as DHT11, DHT22, DS18B20 is_activated = db.Column(db.Boolean, default=False) @@ -22,7 +22,7 @@ class Input(CRUDMixin, db.Model): 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) + power_output_id = db.Column(db.String(36), default=None) resolution = db.Column(db.Integer, default=0) resolution_2 = db.Column(db.Integer, default=0) sensitivity = db.Column(db.Integer, default=0) @@ -57,7 +57,7 @@ class Input(CRUDMixin, db.Model): 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_id = db.Column(db.String(36), default=None) # Output to turn on before sensor read pre_output_duration = db.Column(db.Float, default=10.0) # Duration to turn output on before sensor read pre_output_during_measure = db.Column(db.Boolean, default=True) @@ -108,8 +108,8 @@ class InputChannel(CRUDMixin, db.Model): __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) - input_id = db.Column(db.Text, default=None) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) + input_id = db.Column(db.String(36), default=None) channel = db.Column(db.Integer, default=None) name = db.Column(db.Text, default='') diff --git a/mycodo/databases/models/measurement.py b/mycodo/databases/models/measurement.py index 34bf8feab..8af1f6bd6 100644 --- a/mycodo/databases/models/measurement.py +++ b/mycodo/databases/models/measurement.py @@ -13,7 +13,7 @@ class Measurement(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) name_safe = db.Column(db.Text) name = db.Column(db.Text) units = db.Column(db.Text) @@ -32,7 +32,7 @@ class Unit(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) name_safe = db.Column(db.Text) name = db.Column(db.Text) unit = db.Column(db.Text) @@ -51,7 +51,7 @@ class Conversion(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) convert_unit_from = db.Column(db.Text) convert_unit_to = db.Column(db.Text) equation = db.Column(db.Text) @@ -71,11 +71,11 @@ class DeviceMeasurements(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), 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) + device_id = db.Column(db.String(36), default=None) # Default measurement/unit is_enabled = db.Column(db.Boolean, default=True) @@ -95,9 +95,7 @@ class DeviceMeasurements(CRUDMixin, db.Model): 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='') - - conversion = relationship("Conversion", foreign_keys="DeviceMeasurements.conversion_id") + conversion_id = db.Column(db.String(36), default='') class DeviceMeasurementsSchema(ma.SQLAlchemyAutoSchema): diff --git a/mycodo/databases/models/method.py b/mycodo/databases/models/method.py index e62e5e472..34bcda90d 100644 --- a/mycodo/databases/models/method.py +++ b/mycodo/databases/models/method.py @@ -9,7 +9,7 @@ class Method(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) name = db.Column(db.Text, default='Method') method_type = db.Column(db.Text, default='') method_order = db.Column(db.Text, default='') @@ -23,13 +23,13 @@ class MethodData(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) + method_id = db.Column(db.String(36), 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_id = db.Column(db.String(36), 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) @@ -46,7 +46,7 @@ class MethodData(CRUDMixin, db.Model): 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) + linked_method_id = db.Column(db.String(36), default=None) def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__) diff --git a/mycodo/databases/models/misc.py b/mycodo/databases/models/misc.py index 8187d8a8d..21bc96330 100644 --- a/mycodo/databases/models/misc.py +++ b/mycodo/databases/models/misc.py @@ -43,19 +43,19 @@ class Misc(CRUDMixin, db.Model): mycodo_upgrade_available = db.Column(db.Boolean, default=False) # Stores if an upgrade is available rpyc_timeout = db.Column(db.Integer, default=30) daemon_debug_mode = db.Column(db.Boolean, default=False) - net_test_ip = db.Column(db.String, default='8.8.8.8') + net_test_ip = db.Column(db.String(16), default='8.8.8.8') net_test_port = db.Column(db.Integer, default=53) net_test_timeout = db.Column(db.Integer, default=3) - default_login_page = db.Column(db.String, default='password') - brand_display = db.Column(db.String, default='hostname') - title_display = db.Column(db.String, default='hostname') - hostname_override = db.Column(db.String, default='') + default_login_page = db.Column(db.String(16), default='password') + brand_display = db.Column(db.String(36), default='hostname') + title_display = db.Column(db.String(36), default='hostname') + hostname_override = db.Column(db.String(36), default='') brand_image = db.Column(db.BLOB, default=b'') brand_image_height = db.Column(db.Integer, default=55) - favicon_display = db.Column(db.String, default='default') + favicon_display = db.Column(db.String(16), default='default') brand_favicon = db.Column(db.BLOB, default=b'') - custom_css = db.Column(db.String, default='') - custom_layout = db.Column(db.String, default='') + custom_css = db.Column(db.Text, default='') + custom_layout = db.Column(db.Text, default='') # Measurement database db_name = 'influxdb' # Default @@ -83,14 +83,14 @@ class Misc(CRUDMixin, db.Model): except: logger.exception("Determining influxdb version") - measurement_db_retention_policy = db.Column(db.String, default=db_retention_policy) - measurement_db_name = db.Column(db.String, default=db_name) - measurement_db_version = db.Column(db.String, default=db_version) - measurement_db_host = db.Column(db.String, default=db_host) - measurement_db_port = db.Column(db.String, default=db_port) - measurement_db_user = db.Column(db.String, default='mycodo') - measurement_db_password = db.Column(db.String, default='mmdu77sj3nIoiajjs') - measurement_db_dbname = db.Column(db.String, default='mycodo_db') + measurement_db_retention_policy = db.Column(db.String(36), default=db_retention_policy) + measurement_db_name = db.Column(db.String(36), default=db_name) + measurement_db_version = db.Column(db.String(36), default=db_version) + measurement_db_host = db.Column(db.String(36), default=db_host) + measurement_db_port = db.Column(db.String(36), default=db_port) + measurement_db_user = db.Column(db.String(36), default='mycodo') + measurement_db_password = db.Column(db.String(36), default='mmdu77sj3nIoiajjs') + measurement_db_dbname = db.Column(db.String(36), default='mycodo_db') def __repr__(self): return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__) @@ -101,7 +101,7 @@ class EnergyUsage(CRUDMixin, db.Model): __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 + unique_id = db.Column(db.String(36), 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='') + device_id = db.Column(db.String(36), default='') + measurement_id = db.Column(db.String(36), default='') diff --git a/mycodo/databases/models/notes.py b/mycodo/databases/models/notes.py index 853abec39..f92167542 100644 --- a/mycodo/databases/models/notes.py +++ b/mycodo/databases/models/notes.py @@ -11,7 +11,7 @@ class Notes(CRUDMixin, db.Model): __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 + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) # ID for influxdb entries date_time = db.Column(db.DateTime, default=datetime.datetime.utcnow) name = db.Column(db.Text, default=None) tags = db.Column(db.Text, default=None) @@ -27,7 +27,7 @@ class NoteTags(CRUDMixin, db.Model): __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 + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) # ID for influxdb entries name = db.Column(db.Text, default=None) def __repr__(self): diff --git a/mycodo/databases/models/output.py b/mycodo/databases/models/output.py index 0ab4e0330..685655895 100644 --- a/mycodo/databases/models/output.py +++ b/mycodo/databases/models/output.py @@ -10,7 +10,7 @@ class Output(CRUDMixin, db.Model): __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 + unique_id = db.Column(db.String(36), 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' name = db.Column(db.Text, default='Output') position_y = db.Column(db.Integer, default=0) @@ -75,7 +75,7 @@ class OutputChannel(CRUDMixin, db.Model): __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 + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) # ID for influxdb entries output_id = db.Column(db.Text, default=None) channel = db.Column(db.Integer, default=None) name = db.Column(db.Text, default='') diff --git a/mycodo/databases/models/pid.py b/mycodo/databases/models/pid.py index fdf1893a7..00b2c3a75 100644 --- a/mycodo/databases/models/pid.py +++ b/mycodo/databases/models/pid.py @@ -10,7 +10,7 @@ class PID(CRUDMixin, db.Model): __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 + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) # ID for influxdb entries name = db.Column(db.Text, default='PID') position_y = db.Column(db.Integer, default=0) @@ -33,8 +33,8 @@ class PID(CRUDMixin, db.Model): 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_output_type = db.Column(db.String, default=None) + raise_output_id = db.Column(db.String(36), default=None) # Output to raise the condition + raise_output_type = db.Column(db.String(36), default=None) # TODO: Change "duration" to more general "amount" raise_min_duration = db.Column(db.Float, default=0.0) @@ -42,8 +42,8 @@ class PID(CRUDMixin, db.Model): raise_min_off_duration = db.Column(db.Float, default=0.0) raise_always_min_pwm = db.Column(db.Boolean, default=False) - lower_output_id = db.Column(db.String, db.ForeignKey('output.unique_id'), default=None) # Output to lower the condition - lower_output_type = db.Column(db.String, default=None) + lower_output_id = db.Column(db.String(36), default=None) # Output to lower the condition + lower_output_type = db.Column(db.String(36), default=None) # TODO: Change "duration" to more general "amount" lower_min_duration = db.Column(db.Float, default=0.0) @@ -56,7 +56,7 @@ class PID(CRUDMixin, db.Model): # Setpoint tracking setpoint_tracking_type = db.Column(db.Text, default='') - setpoint_tracking_id = db.Column(db.Text, default='') + setpoint_tracking_id = db.Column(db.String(36), default='') setpoint_tracking_max_age = db.Column(db.Float, default=120.0) method_start_time = db.Column(db.Text, default=None) method_end_time = db.Column(db.Text, default=None) diff --git a/mycodo/databases/models/remote.py b/mycodo/databases/models/remote.py index 81f41dff8..f1545a282 100644 --- a/mycodo/databases/models/remote.py +++ b/mycodo/databases/models/remote.py @@ -9,7 +9,7 @@ class Remote(CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) is_activated = db.Column(db.Boolean, default=False) host = db.Column(db.Text, default='') username = db.Column(db.Text, default='') diff --git a/mycodo/databases/models/role.py b/mycodo/databases/models/role.py index 799c0f6f1..24bbd5eb6 100644 --- a/mycodo/databases/models/role.py +++ b/mycodo/databases/models/role.py @@ -10,8 +10,8 @@ class Role(CRUDMixin, db.Model): # __abstract__ = 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.String, nullable=False, unique=True) + unique_id = db.Column(db.String(36), nullable=False, unique=True, default=set_uuid) + name = db.Column(db.String(36), nullable=False, unique=True) edit_settings = db.Column(db.Boolean, nullable=False, default=False) edit_controllers = db.Column(db.Boolean, nullable=False, default=False) edit_users = db.Column(db.Boolean, nullable=False, default=False) diff --git a/mycodo/databases/models/user.py b/mycodo/databases/models/user.py index 91d2aa853..2f60594d4 100644 --- a/mycodo/databases/models/user.py +++ b/mycodo/databases/models/user.py @@ -13,13 +13,13 @@ class User(UserMixin, CRUDMixin, db.Model): __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) + unique_id = db.Column(db.String(36), 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) + role_id = db.Column(db.Integer, default=None) theme = db.Column(db.VARCHAR(64)) landing_page = db.Column(db.Text, default='live') index_page = db.Column(db.Text, default='landing') @@ -28,8 +28,6 @@ class User(UserMixin, CRUDMixin, db.Model): 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 = "" return output.format(name=self.name, email=self.email, isadmin=bool(self.role_id == 1)) diff --git a/mycodo/mycodo_flask/templates/pages/data_options/input_options.html b/mycodo/mycodo_flask/templates/pages/data_options/input_options.html index f11a4d4f2..94dfe3882 100644 --- a/mycodo/mycodo_flask/templates/pages/data_options/input_options.html +++ b/mycodo/mycodo_flask/templates/pages/data_options/input_options.html @@ -308,7 +308,7 @@
{{_('Actions')}}
- {% for value, name in choices_actions %} {% endfor %} diff --git a/mycodo/mycodo_flask/templates/pages/function.html b/mycodo/mycodo_flask/templates/pages/function.html index 04df8c58e..1a0049524 100644 --- a/mycodo/mycodo_flask/templates/pages/function.html +++ b/mycodo/mycodo_flask/templates/pages/function.html @@ -53,7 +53,7 @@

{{dict_translation['function']['title']}}
- {% for each_controller in choices_functions_add -%} {% endfor -%} diff --git a/mycodo/mycodo_flask/templates/pages/function_options/conditional_options.html b/mycodo/mycodo_flask/templates/pages/function_options/conditional_options.html index 215a0370d..cb47a1997 100644 --- a/mycodo/mycodo_flask/templates/pages/function_options/conditional_options.html +++ b/mycodo/mycodo_flask/templates/pages/function_options/conditional_options.html @@ -121,7 +121,7 @@
{{_('Conditions')}}
- {% for value, name in conditional_conditions_list %} {% endfor %} @@ -150,7 +150,7 @@
{{_('Actions')}}
- {% for value, name in choices_actions %} {% endfor %} diff --git a/mycodo/mycodo_flask/templates/pages/function_options/custom_function_options.html b/mycodo/mycodo_flask/templates/pages/function_options/custom_function_options.html index 0e7613bea..f02da00a8 100644 --- a/mycodo/mycodo_flask/templates/pages/function_options/custom_function_options.html +++ b/mycodo/mycodo_flask/templates/pages/function_options/custom_function_options.html @@ -280,7 +280,7 @@
{{_('Actions')}}
- {% for value, name in choices_actions %} {% endfor %} diff --git a/mycodo/mycodo_flask/templates/pages/function_options/function_options.html b/mycodo/mycodo_flask/templates/pages/function_options/function_options.html index 459384b85..b3b8d4f4b 100644 --- a/mycodo/mycodo_flask/templates/pages/function_options/function_options.html +++ b/mycodo/mycodo_flask/templates/pages/function_options/function_options.html @@ -61,7 +61,7 @@
- {% for value, name in choices_actions %} {% endfor %} diff --git a/mycodo/mycodo_flask/templates/pages/function_options/trigger_options.html b/mycodo/mycodo_flask/templates/pages/function_options/trigger_options.html index 8acc6f887..0517bcb8f 100644 --- a/mycodo/mycodo_flask/templates/pages/function_options/trigger_options.html +++ b/mycodo/mycodo_flask/templates/pages/function_options/trigger_options.html @@ -77,7 +77,7 @@
{{_('Actions')}}
- {% for value, name in choices_actions %} {% endfor %} diff --git a/mycodo/mycodo_flask/templates/pages/input.html b/mycodo/mycodo_flask/templates/pages/input.html index 246ba81a5..a4c55f725 100644 --- a/mycodo/mycodo_flask/templates/pages/input.html +++ b/mycodo/mycodo_flask/templates/pages/input.html @@ -48,7 +48,7 @@

{{dict_translation['input']['title']}}
- {{form_add_input.input_type(class_='selectpicker', **{'data-live-search': 'true', 'title': dict_translation['input']['title'] + ': ' + dict_translation['select_one']['title']})}} + {{form_add_input.input_type(class_='selectpicker', **{'data-style': 'btn btn-primary', 'data-live-search': 'true', 'title': dict_translation['input']['title'] + ': ' + dict_translation['select_one']['title']})}}
diff --git a/mycodo/mycodo_flask/templates/pages/output.html b/mycodo/mycodo_flask/templates/pages/output.html index 55012f993..98fe0acec 100644 --- a/mycodo/mycodo_flask/templates/pages/output.html +++ b/mycodo/mycodo_flask/templates/pages/output.html @@ -145,7 +145,7 @@

{{dict_translation['output']['title']}}
- {{form_add_output.output_type(class_='selectpicker', **{'data-live-search': 'true', 'title': dict_translation['output']['title'] + ': ' + dict_translation['select_one']['title']})}} + {{form_add_output.output_type(class_='selectpicker', **{'data-style': 'btn btn-primary', 'data-live-search': 'true', 'title': dict_translation['output']['title'] + ': ' + dict_translation['select_one']['title']})}}
diff --git a/mycodo/mycodo_flask/templates/tools/export.html b/mycodo/mycodo_flask/templates/tools/export.html index fe21a8b5a..e7546627d 100644 --- a/mycodo/mycodo_flask/templates/tools/export.html +++ b/mycodo/mycodo_flask/templates/tools/export.html @@ -29,7 +29,7 @@

Export Measurement Data as CSV

{{form_export_measurements.measurement.label(class_='control-label')}}
- {% for each_input_form in choices_input -%} {% endfor -%} diff --git a/mycodo/mycodo_flask/templates/tools/notes.html b/mycodo/mycodo_flask/templates/tools/notes.html index 04b27c789..d95aa5a59 100644 --- a/mycodo/mycodo_flask/templates/tools/notes.html +++ b/mycodo/mycodo_flask/templates/tools/notes.html @@ -39,7 +39,7 @@

{{_('Manage')}} {{_('Tags')}}

- {%- for each_tag in tags -%} {%- endfor -%} @@ -192,13 +192,13 @@

{{_('Search')}} {{_('Notes')}}

{{form_note_show.sort_by.label(class_='control-label')}}
- {{form_note_show.sort_by(class_='selectpicker')}} + {{form_note_show.sort_by(class_='selectpicker', **{'data-style': 'btn btn-primary'})}}
{{form_note_show.sort_direction.label(class_='control-label')}}
- {{form_note_show.sort_direction(class_='selectpicker')}} + {{form_note_show.sort_direction(class_='selectpicker', **{'data-style': 'btn btn-primary'})}}
diff --git a/mycodo/scripts/upgrade_install.sh b/mycodo/scripts/upgrade_install.sh index 3f8a47ede..327fa898a 100644 --- a/mycodo/scripts/upgrade_install.sh +++ b/mycodo/scripts/upgrade_install.sh @@ -112,6 +112,14 @@ runSelfUpgrade() { fi printf "Done.\n" + if [ -f "${CURRENT_MYCODO_DIRECTORY}"/config_override.py ] ; then + printf "Copying config_override.py..." + if ! cp "${CURRENT_MYCODO_DIRECTORY}"/config_override.py "${THIS_MYCODO_DIRECTORY}" ; then + printf "Failed: Error while trying to copy config_override.py." + fi + printf "Done.\n" + fi + printf "Copying flask_secret_key..." if ! cp "${CURRENT_MYCODO_DIRECTORY}"/databases/flask_secret_key "${THIS_MYCODO_DIRECTORY}"/databases ; then printf "Failed: Error while trying to copy flask_secret_key."