def math_del(form_mod_math): action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller=TRANSLATIONS['math']['title']) error = [] math_id = form_mod_math.math_id.data try: math = Math.query.filter( Math.unique_id == math_id).first() if math.is_activated: controller_activate_deactivate( 'deactivate', 'Math', form_mod_math.math_id.data) device_measurements = DeviceMeasurements.query.filter( DeviceMeasurements.device_id == math_id).all() for each_measurement in device_measurements: delete_entry_with_id(DeviceMeasurements, each_measurement.unique_id) delete_entry_with_id(Math, math_id) try: display_order = csv_to_list_of_str(DisplayOrder.query.first().math) display_order.remove(math_id) DisplayOrder.query.first().math = list_to_csv(display_order) except Exception: # id not in list pass db.session.commit() except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_data'))
def conditional_condition_add(form): """Add a Conditional Condition""" error = [] action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller='{} {}'.format(TRANSLATIONS['conditional']['title'], gettext("Condition"))) cond = Conditional.query.filter( Conditional.unique_id == form.function_id.data).first() if cond.is_activated: error.append("Deactivate the Conditional before adding a Condition") if form.condition_type.data == '': error.append("Must select a condition") try: new_condition = ConditionalConditions() new_condition.conditional_id = form.function_id.data new_condition.condition_type = form.condition_type.data if new_condition.condition_type == 'measurement': new_condition.max_age = 360 if not error: new_condition.save() except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def action_del(form): """Delete a Conditional Action""" error = [] action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller='{} {}'.format(TRANSLATIONS['conditional']['title'], TRANSLATIONS['actions']['title'])) conditional = Conditional.query.filter( Conditional.unique_id == form.function_id.data).first() trigger = Trigger.query.filter( Trigger.unique_id == form.function_id.data).first() if ((conditional and conditional.is_activated) or (trigger and trigger.is_activated)): error.append("Deactivate the Conditional before deleting an Action") try: if not error: function_action_id = Actions.query.filter( Actions.unique_id == form.function_action_id.data).first().unique_id delete_entry_with_id(Actions, function_action_id) except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def export_measurements(form): """ Take user input to query the InfluxDB and return a CSV file of timestamps and measurement values """ action = '{action} {controller}'.format( action=TRANSLATIONS['export']['title'], controller=TRANSLATIONS['measurement']['title']) error = [] if form.validate(): try: if not error: start_time = form.date_range.data.split(' - ')[0] start_seconds = int(time.mktime( time.strptime(start_time, '%m/%d/%Y %H:%M'))) end_time = form.date_range.data.split(' - ')[1] end_seconds = int(time.mktime( time.strptime(end_time, '%m/%d/%Y %H:%M'))) unique_id = form.measurement.data.split(',')[0] measurement_id = form.measurement.data.split(',')[1] url = '/export_data/{id}/{meas}/{start}/{end}'.format( id=unique_id, meas=measurement_id, start=start_seconds, end=end_seconds) return url except Exception as err: error.append("Error: {}".format(err)) else: flash_form_errors(form) return flash_success_errors(error, action, url_for('routes_page.page_export'))
def function_del(function_id): """Delete a Function""" action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller=TRANSLATIONS['function']['title']) error = [] try: # Delete Actions actions = Actions.query.filter( Actions.function_id == function_id).all() for each_action in actions: delete_entry_with_id(Actions, each_action.unique_id) delete_entry_with_id(Function, function_id) display_order = csv_to_list_of_str(DisplayOrder.query.first().function) display_order.remove(function_id) DisplayOrder.query.first().function = list_to_csv(display_order) db.session.commit() except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def conditional_activate(cond_id): """Activate a Conditional""" error = [] action = '{action} {controller}'.format( action=TRANSLATIONS['activate']['title'], controller=TRANSLATIONS['conditional']['title']) conditions = ConditionalConditions.query.filter( ConditionalConditions.conditional_id == cond_id).all() for each_condition in conditions: # Check for errors in the Conditional settings error = check_cond_measurements(each_condition, error) conditions = ConditionalConditions.query.filter( ConditionalConditions.conditional_id == cond_id) if not conditions.count(): error.append("No Conditions found: Add at least one Condition before activating.") actions = Actions.query.filter( Actions.function_id == cond_id) if not actions.count(): error.append("No Actions found: Add at least one Action before activating.") for each_action in actions.all(): error = check_actions(each_action, error) if not error: controller_activate_deactivate('activate', 'Conditional', cond_id) flash_success_errors(error, action, url_for('routes_page.page_function'))
def conditional_condition_del(form): """Delete a Conditional Condition""" error = [] action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller='{} {}'.format(TRANSLATIONS['conditional']['title'], gettext("Condition"))) cond = Conditional.query.filter( Conditional.unique_id == form.conditional_id.data).first() if cond.is_activated: error.append("Deactivate the Conditional before deleting a Condition") try: if not error: cond_condition_id = ConditionalConditions.query.filter( ConditionalConditions.unique_id == form.conditional_condition_id.data).first().unique_id delete_entry_with_id(ConditionalConditions, cond_condition_id) except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def export_influxdb(form): """ Save the InfluxDB metastore and mycodo_db database to a zip file and serve it to the user """ action = '{action} {controller}'.format( action=TRANSLATIONS['export']['title'], controller=TRANSLATIONS['measurement']['title']) error = [] try: influx_backup_dir = os.path.join(INSTALL_DIRECTORY, 'influx_backup') # Delete influxdb directory if it exists if os.path.isdir(influx_backup_dir): shutil.rmtree(influx_backup_dir) # Create new directory (make sure it's empty) assure_path_exists(influx_backup_dir) cmd = "/usr/bin/influxd backup -database mycodo_db {path}".format( path=influx_backup_dir) _, _, status = cmd_output(cmd) influxd_version_out, _, _ = cmd_output( '/usr/bin/influxd version') if influxd_version_out: influxd_version = influxd_version_out.decode('utf-8').split(' ')[1] else: influxd_version = None error.append("Could not determine Influxdb version") if not status and influxd_version: # Zip all files in the influx_backup directory data = io.BytesIO() with zipfile.ZipFile(data, mode='w') as z: for _, _, files in os.walk(influx_backup_dir): for filename in files: z.write(os.path.join(influx_backup_dir, filename), filename) data.seek(0) # Delete influxdb directory if it exists if os.path.isdir(influx_backup_dir): shutil.rmtree(influx_backup_dir) # Send zip file to user return send_file( data, mimetype='application/zip', as_attachment=True, attachment_filename='Mycodo_{mv}_Influxdb_{iv}_{host}_{dt}.zip'.format( mv=MYCODO_VERSION, iv=influxd_version, host=socket.gethostname().replace(' ', ''), dt=datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")) ) except Exception as err: error.append("Error: {}".format(err)) flash_success_errors(error, action, url_for('routes_page.page_export'))
def pid_del(pid_id): action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller=TRANSLATIONS['pid']['title']) error = [] try: pid = PID.query.filter( PID.unique_id == pid_id).first() if pid.is_activated: pid_deactivate(pid_id) device_measurements = DeviceMeasurements.query.filter( DeviceMeasurements.device_id == pid_id).all() for each_measurement in device_measurements: delete_entry_with_id(DeviceMeasurements, each_measurement.unique_id) delete_entry_with_id(PID, pid_id) try: display_order = csv_to_list_of_str(DisplayOrder.query.first().math) display_order.remove(pid_id) DisplayOrder.query.first().function = list_to_csv(display_order) except Exception: # id not in list pass db.session.commit() except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def lcd_del(lcd_id): action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller=TRANSLATIONS['lcd']['title']) error = [] lcd = LCD.query.filter( LCD.unique_id == lcd_id).first() if lcd.is_activated: error.append(gettext("Deactivate LCD controller before modifying " "its settings.")) if not error: try: # Delete all LCD Displays lcd_displays = LCDData.query.filter( LCDData.lcd_id == lcd_id).all() for each_lcd_display in lcd_displays: lcd_display_del(each_lcd_display.unique_id, delete_last=True) # Delete LCD delete_entry_with_id(LCD, lcd_id) display_order = csv_to_list_of_str(DisplayOrder.query.first().lcd) display_order.remove(lcd_id) DisplayOrder.query.first().lcd = list_to_csv(display_order) db.session.commit() except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_lcd'))
def lcd_activate(lcd_id): action = '{action} {controller}'.format( action=TRANSLATIONS['activate']['title'], controller=TRANSLATIONS['lcd']['title']) error = [] try: # All display lines must be filled to activate display lcd = LCD.query.filter( LCD.unique_id == lcd_id).first() lcd_data = LCDData.query.filter( LCDData.lcd_id == lcd_id).all() blank_line_detected = False for each_lcd_data in lcd_data: if ( (lcd.y_lines in [2, 4] and (not each_lcd_data.line_1_id or not each_lcd_data.line_2_id) ) or (lcd.y_lines == 4 and (not each_lcd_data.line_3_id or not each_lcd_data.line_4_id)) ): blank_line_detected = True if blank_line_detected: error.append(gettext( "Cannot activate LCD if there are blank lines")) if not error: controller_activate_deactivate('activate', 'LCD', lcd_id) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_lcd'))
def export_settings(form): """ Save the Mycodo settings database (mycodo.db) to a zip file and serve it to the user """ action = '{action} {controller}'.format( action=TRANSLATIONS['export']['title'], controller=TRANSLATIONS['settings']['title']) error = [] try: data = io.BytesIO() with zipfile.ZipFile(data, mode='w') as z: z.write(SQL_DATABASE_MYCODO, os.path.basename(SQL_DATABASE_MYCODO)) data.seek(0) return send_file( data, mimetype='application/zip', as_attachment=True, attachment_filename= 'Mycodo_{mver}_Settings_{aver}_{host}_{dt}.zip'.format( mver=MYCODO_VERSION, aver=ALEMBIC_VERSION, host=socket.gethostname().replace(' ', ''), dt=datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")) ) except Exception as err: error.append("Error: {}".format(err)) flash_success_errors(error, action, url_for('routes_page.page_export'))
def lcd_display_del(lcd_data_id, delete_last=False): action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller=TRANSLATIONS['display']['title']) error = [] lcd_data_this = LCDData.query.filter( LCDData.unique_id == lcd_data_id).first() lcd_data_all = LCDData.query.filter( LCDData.lcd_id == lcd_data_this.lcd_id).all() lcd = LCD.query.filter( LCD.unique_id == lcd_data_this.lcd_id).first() if lcd.is_activated: error.append(gettext("Deactivate LCD controller before modifying" " its settings")) if not delete_last and len(lcd_data_all) < 2: error.append(gettext("The last display cannot be deleted")) if not error: try: delete_entry_with_id(LCDData, lcd_data_id) db.session.commit() except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_lcd'))
def lcd_add(form): action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['lcd']['title']) error = [] if current_app.config['TESTING']: dep_unmet = False else: dep_unmet, _ = return_dependencies(form.lcd_type.data) if dep_unmet: list_unmet_deps = [] for each_dep in dep_unmet: list_unmet_deps.append(each_dep[0]) error.append("The {dev} device you're trying to add has unmet dependencies: {dep}".format( dev=form.lcd_type.data, dep=', '.join(list_unmet_deps))) try: new_lcd = LCD() new_lcd_data = LCDData() if GPIO.RPI_REVISION == 2 or GPIO.RPI_REVISION == 3: new_lcd.i2c_bus = 1 else: new_lcd.i2c_bus = 0 new_lcd.lcd_type = form.lcd_type.data new_lcd.name = str(LCD_INFO[form.lcd_type.data]['name']) if form.lcd_type.data == '128x32_pioled': new_lcd.location = '0x3c' new_lcd.x_characters = 21 new_lcd.y_lines = 4 elif form.lcd_type.data == '128x64_pioled': new_lcd.location = '0x3c' new_lcd.x_characters = 21 new_lcd.y_lines = 8 elif form.lcd_type.data == '16x2_generic': new_lcd.location = '0x27' new_lcd.x_characters = 16 new_lcd.y_lines = 2 elif form.lcd_type.data == '16x4_generic': new_lcd.location = '0x27' new_lcd.x_characters = 16 new_lcd.y_lines = 4 if not error: new_lcd.save() new_lcd_data.lcd_id = new_lcd.unique_id new_lcd_data.save() display_order = csv_to_list_of_str(DisplayOrder.query.first().lcd) DisplayOrder.query.first().lcd = add_display_order( display_order, new_lcd.unique_id) db.session.commit() except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_lcd')) if dep_unmet: return 1
def lcd_mod(form_mod_lcd): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['lcd']['title']) error = [] mod_lcd = LCD.query.filter( LCD.unique_id == form_mod_lcd.lcd_id.data).first() if mod_lcd.is_activated: error.append(gettext("Deactivate LCD controller before modifying" " its settings.")) if not error: if form_mod_lcd.validate(): try: mod_lcd.name = form_mod_lcd.name.data if mod_lcd.lcd_type in ['16x2_generic', '16x4_generic']: mod_lcd.location = form_mod_lcd.location.data mod_lcd.i2c_bus = form_mod_lcd.i2c_bus.data mod_lcd.period = form_mod_lcd.period.data db.session.commit() except Exception as except_msg: error.append(except_msg) else: flash_form_errors(form_mod_lcd) flash_success_errors(error, action, url_for('routes_page.page_lcd'))
def file_del(form): action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller=gettext("File")) error = [] if not form.note_unique_id.data: error.append("Unique id is empty") mod_note = Notes.query.filter( Notes.unique_id == form.note_unique_id.data).first() files_list = mod_note.files.split(",") if form.file_selected.data in files_list: try: files_list.remove(form.file_selected.data) except: error.append("Could not remove file from note") if mod_note.files: try: full_file_path = os.path.join(PATH_NOTE_ATTACHMENTS, form.file_selected.data) os.remove(full_file_path) except: error.append("Could not remove file from filesystem") if not error: mod_note.files = ",".join(files_list) db.session.commit() flash_success_errors(error, action, url_for('routes_page.page_notes'))
def input_del(input_id): action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller=TRANSLATIONS['input']['title']) error = [] try: input_dev = Input.query.filter( Input.unique_id == input_id).first() if input_dev.is_activated: input_deactivate_associated_controllers(input_id) controller_activate_deactivate('deactivate', 'Input', input_id) device_measurements = DeviceMeasurements.query.filter( DeviceMeasurements.device_id == input_id).all() for each_measurement in device_measurements: delete_entry_with_id(DeviceMeasurements, each_measurement.unique_id) delete_entry_with_id(Input, input_id) try: display_order = csv_to_list_of_str( DisplayOrder.query.first().inputs) display_order.remove(input_id) DisplayOrder.query.first().inputs = list_to_csv(display_order) except Exception: # id not in list pass db.session.commit() except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_data'))
def math_add(form_add_math): action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['math']['title']) error = [] dep_unmet, _ = return_dependencies(form_add_math.math_type.data) if dep_unmet: list_unmet_deps = [] for each_dep in dep_unmet: list_unmet_deps.append(each_dep[0]) error.append("The {dev} device you're trying to add has unmet dependencies: {dep}".format( dev=form_add_math.math_type.data, dep=', '.join(list_unmet_deps))) if form_add_math.validate(): new_math = Math() new_math.name = str(MATH_INFO[form_add_math.math_type.data]['name']) new_math.math_type = form_add_math.math_type.data try: new_math.save() display_order = csv_to_list_of_str( DisplayOrder.query.first().math) DisplayOrder.query.first().math = add_display_order( display_order, new_math.unique_id) db.session.commit() if not MATH_INFO[form_add_math.math_type.data]['measure']: new_measurement = DeviceMeasurements() new_measurement.device_id = new_math.unique_id new_measurement.channel = 0 new_measurement.save() else: for each_channel, measure_info in MATH_INFO[form_add_math.math_type.data]['measure'].items(): new_measurement = DeviceMeasurements() if 'name' in measure_info and measure_info['name']: new_measurement.name = measure_info['name'] new_measurement.device_id = new_math.unique_id new_measurement.measurement = measure_info['measurement'] new_measurement.unit = measure_info['unit'] new_measurement.channel = each_channel new_measurement.save() flash(gettext( "%(type)s Math with ID %(id)s (%(uuid)s) successfully added", type=form_add_math.math_type.data, id=new_math.id, uuid=new_math.unique_id), "success") except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_data')) else: flash_form_errors(form_add_math) if dep_unmet: return 1
def output_on_off(form_output): action = '{action} {controller}'.format( action=gettext("Actuate"), controller=TRANSLATIONS['output']['title']) error = [] try: control = DaemonControl() output = Output.query.filter_by(unique_id=form_output.output_id.data).first() if output.output_type == 'wired' and int(form_output.output_pin.data) == 0: error.append(gettext("Cannot modulate output with a GPIO of 0")) elif form_output.on_submit.data: if output.output_type in ['wired', 'wireless_rpi_rf', 'command']: if float(form_output.sec_on.data) <= 0: error.append(gettext("Value must be greater than 0")) else: return_value = control.output_on(form_output.output_id.data, duration=float(form_output.sec_on.data)) flash(gettext("Output turned on for %(sec)s seconds: %(rvalue)s", sec=form_output.sec_on.data, rvalue=return_value), "success") if output.output_type == 'pwm': if int(form_output.output_pin.data) == 0: error.append(gettext("Invalid pin")) if output.pwm_hertz <= 0: error.append(gettext("PWM Hertz must be a positive value")) if float(form_output.pwm_duty_cycle_on.data) <= 0: error.append(gettext("PWM duty cycle must be a positive value")) if not error: return_value = control.output_on( form_output.output_id.data, duty_cycle=float(form_output.pwm_duty_cycle_on.data)) flash(gettext("PWM set to %(dc)s %% at %(hertz)s Hz: %(rvalue)s", dc=float(form_output.pwm_duty_cycle_on.data), hertz=output.pwm_hertz, rvalue=return_value), "success") elif form_output.turn_on.data: return_value = control.output_on(form_output.output_id.data, 0) flash(gettext("Output turned on: %(rvalue)s", rvalue=return_value), "success") elif form_output.turn_off.data: return_value = control.output_off(form_output.output_id.data) flash(gettext("Output turned off: %(rvalue)s", rvalue=return_value), "success") except ValueError as except_msg: error.append('{err}: {msg}'.format( err=gettext("Invalid value"), msg=except_msg)) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_output'))
def note_mod(form): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['note']['title']) error = [] list_tags = [] mod_note = Notes.query.filter( Notes.unique_id == form.note_unique_id.data).first() if not form.name.data: error.append("Name cannot be left blank") if not form.note_tags.data: error.append("At least one tag must be selected") if not form.note.data: error.append("Note cannot be left blank") try: for each_tag in form.note_tags.data: check_tag = NoteTags.query.filter( NoteTags.unique_id == each_tag).first() if not check_tag: error.append("Invalid tag: {}".format(each_tag)) else: list_tags.append(check_tag.unique_id) except Exception as msg: error.append("Invalid tag format: {}".format(msg)) try: mod_note.date_time = datetime_time_to_utc(form.date_time.data) except: error.append("Error while parsing date/time") if form.files.data: assure_path_exists(PATH_NOTE_ATTACHMENTS) if mod_note.files: filename_list = mod_note.files.split(",") else: filename_list = [] for each_file in form.files.raw_data: file_name = "{pre}_{name}".format( pre=mod_note.unique_id, name=each_file.filename) file_save_path = os.path.join(PATH_NOTE_ATTACHMENTS, file_name) each_file.save(file_save_path) filename_list.append(file_name) mod_note.files = ",".join(filename_list) if not error: mod_note.name = form.name.data mod_note.tags = ",".join(list_tags) mod_note.note = form.note.data db.session.commit() flash_success_errors(error, action, url_for('routes_page.page_notes'))
def conditional_deactivate(cond_id): """Deactivate a Conditional""" error = [] action = '{action} {controller}'.format( action=TRANSLATIONS['deactivate']['title'], controller=TRANSLATIONS['conditional']['title']) if not error: controller_activate_deactivate('deactivate', 'Conditional', cond_id) flash_success_errors(error, action, url_for('routes_page.page_function'))
def method_del(method_id): action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller=TRANSLATIONS['method']['title']) error = [] try: delete_entry_with_id(Method, method_id) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_method.method_list'))
def energy_usage_delete(energy_usage_id): action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller=TRANSLATIONS['energy_usage']['title']) error = [] try: delete_entry_with_id(EnergyUsage, energy_usage_id) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_data'))
def tag_del(form): action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller=TRANSLATIONS['tag']['title']) error = [] if Notes.query.filter(Notes.tags.ilike("%{0}%".format(form.tag_unique_id.data))).first(): error.append("Cannot delete tag because it's currently assicuated with at least one note") if not error: delete_entry_with_id(NoteTags, form.tag_unique_id.data) flash_success_errors(error, action, url_for('routes_page.page_notes'))
def trigger_deactivate(trigger_id): """Deactivate a Trigger""" error = [] action = '{action} {controller}'.format( action=TRANSLATIONS['deactivate']['title'], controller=TRANSLATIONS['trigger']['title']) if not error: controller_activate_deactivate( 'deactivate', 'Trigger', trigger_id) flash_success_errors(error, action, url_for('routes_page.page_function'))
def measurement_mod(form): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['measurement']['title']) error = [] try: mod_meas = DeviceMeasurements.query.filter( DeviceMeasurements.unique_id == form.input_measurement_id.data).first() mod_input = Input.query.filter(Input.unique_id == mod_meas.device_id).first() if mod_input.is_activated: error.append(gettext( "Deactivate controller before modifying its settings")) mod_meas.name = form.name.data input_info = parse_input_information() if ('enable_channel_unit_select' in input_info[mod_input.device] and input_info[mod_input.device]['enable_channel_unit_select']): if ',' in form.select_measurement_unit.data: mod_meas.measurement = form.select_measurement_unit.data.split(',')[0] mod_meas.unit = form.select_measurement_unit.data.split(',')[1] else: mod_meas.measurement = '' mod_meas.unit = '' if form.rescaled_measurement_unit.data != '' and ',' in form.rescaled_measurement_unit.data: mod_meas.rescaled_measurement = form.rescaled_measurement_unit.data.split(',')[0] mod_meas.rescaled_unit = form.rescaled_measurement_unit.data.split(',')[1] elif form.rescaled_measurement_unit.data == '': mod_meas.rescaled_measurement = '' mod_meas.rescaled_unit = '' mod_meas.scale_from_min = form.scale_from_min.data mod_meas.scale_from_max = form.scale_from_max.data mod_meas.scale_to_min = form.scale_to_min.data mod_meas.scale_to_max = form.scale_to_max.data mod_meas.invert_scale = form.invert_scale.data mod_meas.conversion_id = form.convert_to_measurement_unit.data if not error: db.session.commit() except Exception as except_msg: logger.exception(1) error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_data'))
def function_reorder(function_id, display_order, direction): action = '{action} {controller}'.format( action=TRANSLATIONS['reorder']['title'], controller=TRANSLATIONS['function']['title']) error = [] try: status, reord_list = reorder( display_order, function_id, direction) if status == 'success': DisplayOrder.query.first().function = ','.join(map(str, reord_list)) db.session.commit() else: error.append(reord_list) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def pid_activate(pid_id): if has_required_pid_values(pid_id): return redirect(url_for('routes_page.page_function')) action = '{action} {controller}'.format( action=TRANSLATIONS['activate']['title'], controller=TRANSLATIONS['pid']['title']) error = [] # Check if associated sensor is activated pid = PID.query.filter( PID.unique_id == pid_id).first() error = can_set_output( error, pid_id, pid.raise_output_id, pid.lower_output_id) device_unique_id = pid.measurement.split(',')[0] input_dev = Input.query.filter( Input.unique_id == device_unique_id).first() math = Math.query.filter( Math.unique_id == device_unique_id).first() if (input_dev and not input_dev.is_activated) or (math and not math.is_activated): error.append(gettext( "Cannot activate PID controller if the associated sensor " "controller is inactive")) if ((pid.direction == 'both' and not (pid.lower_output_id and pid.raise_output_id)) or (pid.direction == 'lower' and not pid.lower_output_id) or (pid.direction == 'raise' and not pid.raise_output_id)): error.append(gettext( "Cannot activate PID controller if raise and/or lower output IDs " "are not selected")) if not error: # Signal the duration method can run because it's been # properly initiated (non-power failure) method = Method.query.filter( Method.unique_id == pid.method_id).first() if method and method.method_type == 'Duration': mod_pid = PID.query.filter(PID.unique_id == pid_id).first() mod_pid.method_start_time = 'Ready' db.session.commit() time.sleep(1) controller_activate_deactivate('activate', 'PID', pid_id) flash_success_errors(error, action, url_for('routes_page.page_function'))
def dashboard_del(form_base): """Delete an item on the dashboard""" action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller=TRANSLATIONS['dashboard']['title']) error = [] try: delete_entry_with_id(Dashboard, form_base.dashboard_id.data) display_order = csv_to_list_of_str(DisplayOrder.query.first().dashboard) display_order.remove(form_base.dashboard_id.data) DisplayOrder.query.first().dashboard = list_to_csv(display_order) db.session.commit() except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_dashboard'))
def output_del(form_output): action = '{action} {controller}'.format( action=TRANSLATIONS['delete']['title'], controller=TRANSLATIONS['output']['title']) error = [] try: delete_entry_with_id(Output, form_output.output_id.data) display_order = csv_to_list_of_str(DisplayOrder.query.first().output) display_order.remove(form_output.output_id.data) DisplayOrder.query.first().output = list_to_csv(display_order) db.session.commit() manipulate_output('Delete', form_output.output_id.data) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_output'))
def input_mod(form_mod, request_form): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['input']['title']) error = [] dict_inputs = parse_input_information() try: mod_input = Input.query.filter( Input.unique_id == form_mod.input_id.data).first() if mod_input.is_activated: error.append(gettext( "Deactivate controller before modifying its settings")) if (mod_input.device == 'AM2315' and form_mod.period.data < 7): error.append(gettext( "Choose a Read Period equal to or greater than 7. The " "AM2315 may become unresponsive if the period is " "below 7.")) if (form_mod.period.data and mod_input.pre_output_duration and form_mod.period.data < mod_input.pre_output_duration): error.append(gettext( "The Read Period cannot be less than the Pre Output Duration")) if (form_mod.uart_location.data and not os.path.exists(form_mod.uart_location.data)): error.append(gettext( "Invalid device or improper permissions to read device")) if ('gpio_location' in dict_inputs[mod_input.device]['options_enabled'] and form_mod.gpio_location.data is None): error.append(gettext("Pin (GPIO) must be set")) mod_input.name = form_mod.name.data if form_mod.location.data: mod_input.location = form_mod.location.data if form_mod.i2c_location.data: mod_input.i2c_location = form_mod.i2c_location.data if form_mod.ftdi_location.data: mod_input.ftdi_location = form_mod.ftdi_location.data if form_mod.uart_location.data: mod_input.uart_location = form_mod.uart_location.data if form_mod.gpio_location.data and form_mod.gpio_location.data is not None: mod_input.gpio_location = form_mod.gpio_location.data if form_mod.power_output_id.data: mod_input.power_output_id = form_mod.power_output_id.data else: mod_input.power_output_id = None if form_mod.pre_output_id.data: mod_input.pre_output_id = form_mod.pre_output_id.data else: mod_input.pre_output_id = None # Enable/disable Channels measurements = DeviceMeasurements.query.filter( DeviceMeasurements.device_id == form_mod.input_id.data).all() if form_mod.measurements_enabled.data: for each_measurement in measurements: if each_measurement.unique_id in form_mod.measurements_enabled.data: each_measurement.is_enabled = True else: each_measurement.is_enabled = False mod_input.log_level_debug = form_mod.log_level_debug.data mod_input.i2c_bus = form_mod.i2c_bus.data mod_input.baud_rate = form_mod.baud_rate.data mod_input.pre_output_duration = form_mod.pre_output_duration.data mod_input.pre_output_during_measure = form_mod.pre_output_during_measure.data if form_mod.period.data: mod_input.period = form_mod.period.data if form_mod.start_offset.data: mod_input.start_offset = form_mod.start_offset.data mod_input.resolution = form_mod.resolution.data mod_input.resolution_2 = form_mod.resolution_2.data mod_input.sensitivity = form_mod.sensitivity.data mod_input.calibrate_sensor_measure = form_mod.calibrate_sensor_measure.data mod_input.cmd_command = form_mod.cmd_command.data mod_input.thermocouple_type = form_mod.thermocouple_type.data mod_input.ref_ohm = form_mod.ref_ohm.data # Serial options mod_input.pin_clock = form_mod.pin_clock.data mod_input.pin_cs = form_mod.pin_cs.data mod_input.pin_mosi = form_mod.pin_mosi.data mod_input.pin_miso = form_mod.pin_miso.data # Bluetooth options mod_input.bt_adapter = form_mod.bt_adapter.data mod_input.adc_gain = form_mod.adc_gain.data mod_input.adc_resolution = form_mod.adc_resolution.data mod_input.adc_sample_speed = form_mod.adc_sample_speed.data # Switch options mod_input.switch_edge = form_mod.switch_edge.data mod_input.switch_bouncetime = form_mod.switch_bouncetime.data mod_input.switch_reset_period = form_mod.switch_reset_period.data # PWM and RPM options mod_input.weighting = form_mod.weighting.data mod_input.rpm_pulses_per_rev = form_mod.rpm_pulses_per_rev.data mod_input.sample_time = form_mod.sample_time.data # Server options mod_input.port = form_mod.port.data mod_input.times_check = form_mod.times_check.data mod_input.deadline = form_mod.deadline.data # SHT sensor options if form_mod.sht_voltage.data: mod_input.sht_voltage = form_mod.sht_voltage.data channels = InputChannel.query.filter( InputChannel.input_id == form_mod.input_id.data) # Add or delete channels for variable measurement Inputs if ('measurements_variable_amount' in dict_inputs[mod_input.device] and dict_inputs[mod_input.device]['measurements_variable_amount']): measurements = DeviceMeasurements.query.filter( DeviceMeasurements.device_id == form_mod.input_id.data) if measurements.count() != form_mod.num_channels.data: # Delete measurements/channels if form_mod.num_channels.data < measurements.count(): for index, each_channel in enumerate(measurements.all()): if index + 1 >= measurements.count(): delete_entry_with_id(DeviceMeasurements, each_channel.unique_id) if ('channel_quantity_same_as_measurements' in dict_inputs[mod_input.device] and dict_inputs[mod_input.device]["channel_quantity_same_as_measurements"]): if form_mod.num_channels.data < channels.count(): for index, each_channel in enumerate(channels.all()): if index + 1 >= channels.count(): delete_entry_with_id(InputChannel, each_channel.unique_id) # Add measurements/channels elif form_mod.num_channels.data > measurements.count(): start_number = measurements.count() for index in range(start_number, form_mod.num_channels.data): new_measurement = DeviceMeasurements() new_measurement.name = "" new_measurement.device_id = mod_input.unique_id new_measurement.measurement = "" new_measurement.unit = "" new_measurement.channel = index new_measurement.save() if ('channel_quantity_same_as_measurements' in dict_inputs[mod_input.device] and dict_inputs[mod_input.device]["channel_quantity_same_as_measurements"]): new_channel = InputChannel() new_channel.name = "" new_channel.input_id = mod_input.unique_id new_channel.channel = index error, custom_options = custom_channel_options_return_json( error, dict_inputs, request_form, mod_input.unique_id, index, device=mod_input.device, use_defaults=True) new_channel.custom_options = custom_options new_channel.save() # Parse pre-save custom options for output device and its channels try: custom_options_dict_presave = json.loads(mod_input.custom_options) except: logger.error("Malformed JSON") custom_options_dict_presave = {} custom_options_channels_dict_presave = {} for each_channel in channels.all(): if each_channel.custom_options and each_channel.custom_options != "{}": custom_options_channels_dict_presave[each_channel.channel] = json.loads( each_channel.custom_options) else: custom_options_channels_dict_presave[each_channel.channel] = {} # Parse post-save custom options for output device and its channels error, custom_options_json_postsave = custom_options_return_json( error, dict_inputs, request_form, device=mod_input.device) custom_options_dict_postsave = json.loads(custom_options_json_postsave) custom_options_channels_dict_postsave = {} for each_channel in channels.all(): error, custom_options_channels_json_postsave_tmp = custom_channel_options_return_json( error, dict_inputs, request_form, form_mod.input_id.data, each_channel.channel, device=mod_input.device, use_defaults=True) custom_options_channels_dict_postsave[each_channel.channel] = json.loads( custom_options_channels_json_postsave_tmp) if 'execute_at_modification' in dict_inputs[mod_input.device]: # pass custom options to module prior to saving to database (allow_saving, mod_output, custom_options_dict, custom_options_channels_dict) = dict_inputs[mod_input.device]['execute_at_modification']( mod_input, request_form, custom_options_dict_presave, custom_options_channels_dict_presave, custom_options_dict_postsave, custom_options_channels_dict_postsave) custom_options = json.dumps(custom_options_dict) # Convert from dict to JSON string custom_channel_options = custom_options_channels_dict if not allow_saving: error.append("execute_at_modification() would not allow input options to be saved") else: # Don't pass custom options to module custom_options = json.dumps(custom_options_dict_postsave) custom_channel_options = custom_options_channels_dict_postsave # Finally, save custom options for both output and channels mod_input.custom_options = custom_options for each_channel in channels: if 'name' in custom_channel_options[each_channel.channel]: each_channel.name = custom_channel_options[each_channel.channel]['name'] each_channel.custom_options = json.dumps(custom_channel_options[each_channel.channel]) if not error: db.session.commit() except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_input'))
def input_activate(form_mod): action = '{action} {controller}'.format( action=TRANSLATIONS['activate']['title'], controller=TRANSLATIONS['input']['title']) error = [] dict_inputs = parse_input_information() input_id = form_mod.input_id.data input_dev = Input.query.filter(Input.unique_id == input_id).first() device_measurements = DeviceMeasurements.query.filter( DeviceMeasurements.device_id == input_dev.unique_id) custom_options_values_inputs = parse_custom_option_values( input_dev, dict_controller=dict_inputs) # # General Input checks # if not input_dev.period: error.append("Period must be set") if (input_dev.pre_output_id and len(input_dev.pre_output_id) > 1 and not input_dev.pre_output_duration): error.append("Pre Output Duration must be > 0 if Pre Output is enabled") if not device_measurements.filter(DeviceMeasurements.is_enabled.is_(True)).count(): error.append("At least one measurement must be enabled") # # Check if required custom options are set # if 'custom_options' in dict_inputs[input_dev.device]: for each_option in dict_inputs[input_dev.device]['custom_options']: if each_option['id'] not in custom_options_values_inputs[input_dev.unique_id]: if 'required' in each_option and each_option['required']: error.append("{} not found and is required to be set. " "Set option and save Input.".format( each_option['name'])) else: value = custom_options_values_inputs[input_dev.unique_id][each_option['id']] if ('required' in each_option and each_option['required'] and not value): error.append("{} is required to be set".format( each_option['name'])) # # Input-specific checks # if input_dev.device == 'LinuxCommand' and not input_dev.cmd_command: error.append("Cannot activate Command Input without a Command set") elif ('measurements_variable_amount' in dict_inputs[input_dev.device] and dict_inputs[input_dev.device]['measurements_variable_amount']): measure_set = True for each_channel in device_measurements.all(): if (not each_channel.name or not each_channel.measurement or not each_channel.unit): measure_set = False if not measure_set: error.append("All measurements must have a name and unit/measurement set") if not error: controller_activate_deactivate('activate', 'Input', input_id) flash_success_errors(error, action, url_for('routes_page.page_input'))
def dashboard_mod(form_base, form_object, request_form): """Modify the settings of an item on the dashboard""" action = '{action} {controller}'.format(action=gettext("Modify"), controller=gettext("Dashboard")) error = [] mod_graph = Dashboard.query.filter( Dashboard.unique_id == form_base.dashboard_id.data).first() mod_graph.name = form_base.name.data # Graph Mod if form_base.dashboard_type.data == 'graph': error = graph_error_check(form_object, error) # Generate color option string from form inputs sorted_colors_string, error = custom_colors_graph_str( request_form, error) mod_graph.custom_colors = sorted_colors_string mod_graph.use_custom_colors = form_object.use_custom_colors.data # Generate y-axis option string from form inputs yaxes_string = custom_yaxes_str_from_form(request_form) mod_graph.custom_yaxes = yaxes_string mod_graph.enable_manual_y_axis = form_object.enable_manual_y_axis.data mod_graph.enable_align_ticks = form_object.enable_align_ticks.data mod_graph.enable_start_on_tick = form_object.enable_start_on_tick.data mod_graph.enable_end_on_tick = form_object.enable_end_on_tick.data if form_object.math_ids.data: math_ids_joined = ";".join(form_object.math_ids.data) mod_graph.math_ids = math_ids_joined else: mod_graph.math_ids = '' if form_object.pid_ids.data: pid_ids_joined = ";".join(form_object.pid_ids.data) mod_graph.pid_ids = pid_ids_joined else: mod_graph.pid_ids = '' if form_object.output_ids.data: output_ids_joined = ";".join(form_object.output_ids.data) mod_graph.output_ids = output_ids_joined else: mod_graph.output_ids = '' if form_object.input_ids.data: input_ids_joined = ";".join(form_object.input_ids.data) mod_graph.input_ids_measurements = input_ids_joined else: mod_graph.input_ids_measurements = '' mod_graph.width = form_base.width.data mod_graph.height = form_base.height.data mod_graph.x_axis_duration = form_object.xaxis_duration.data mod_graph.refresh_duration = form_base.refresh_duration.data mod_graph.enable_auto_refresh = form_object.enable_auto_refresh.data mod_graph.enable_xaxis_reset = form_object.enable_xaxis_reset.data mod_graph.enable_title = form_object.enable_title.data mod_graph.enable_navbar = form_object.enable_navbar.data mod_graph.enable_export = form_object.enable_export.data mod_graph.enable_rangeselect = form_object.enable_range.data mod_graph.enable_graph_shift = form_object.enable_graph_shift.data # If a gauge type is changed, the color format must change elif (form_base.dashboard_type.data == 'gauge' and mod_graph.graph_type != form_object.gauge_type.data): mod_graph.graph_type = form_object.gauge_type.data if form_object.gauge_type.data == 'gauge_solid': mod_graph.range_colors = '0.2,#33CCFF;0.4,#55BF3B;0.6,#DDDF0D;0.8,#DF5353' elif form_object.gauge_type.data == 'gauge_angular': mod_graph.range_colors = '0,25,#33CCFF;25,50,#55BF3B;50,75,#DDDF0D;75,100,#DF5353' # Gauge Mod elif form_base.dashboard_type.data == 'gauge': error = gauge_error_check(form_object, error) # Generate color option string from form inputs sorted_colors_string, error = custom_colors_gauge_str( request_form, form_object.gauge_type.data, error) mod_graph.range_colors = sorted_colors_string mod_graph.width = form_base.width.data mod_graph.height = form_base.height.data mod_graph.refresh_duration = form_base.refresh_duration.data mod_graph.y_axis_min = form_object.y_axis_min.data mod_graph.y_axis_max = form_object.y_axis_max.data mod_graph.max_measure_age = form_object.max_measure_age.data mod_graph.enable_timestamp = form_object.enable_timestamp.data if form_object.input_ids.data: mod_graph.input_ids_measurements = form_object.input_ids.data else: error.append("A valid Measurement must be selected") # Measurement Mod elif form_base.dashboard_type.data == 'measurement': error = measurement_error_check(form_object, error) mod_graph.width = form_base.width.data mod_graph.height = form_base.height.data mod_graph.refresh_duration = form_base.refresh_duration.data mod_graph.max_measure_age = form_object.max_measure_age.data mod_graph.font_em_value = form_object.font_em_value.data mod_graph.font_em_timestamp = form_object.font_em_timestamp.data mod_graph.decimal_places = form_object.decimal_places.data if form_object.measurement_id.data: mod_graph.input_ids_measurements = form_object.measurement_id.data # Output Mod elif form_base.dashboard_type.data == 'output': error = output_error_check(form_object, error) mod_graph.width = form_base.width.data mod_graph.height = form_base.height.data mod_graph.refresh_duration = form_base.refresh_duration.data mod_graph.max_measure_age = form_object.max_measure_age.data mod_graph.font_em_value = form_object.font_em_value.data mod_graph.font_em_timestamp = form_object.font_em_timestamp.data mod_graph.decimal_places = form_object.decimal_places.data mod_graph.enable_output_controls = form_object.enable_output_controls.data if form_object.output_id.data: mod_graph.output_ids = form_object.output_id.data # PID Control Mod elif form_base.dashboard_type.data == 'pid_control': error = pid_error_check(form_object, error) mod_graph.width = form_base.width.data mod_graph.height = form_base.height.data mod_graph.refresh_duration = form_base.refresh_duration.data mod_graph.max_measure_age = form_object.max_measure_age.data mod_graph.font_em_value = form_object.font_em_value.data mod_graph.font_em_timestamp = form_object.font_em_timestamp.data mod_graph.decimal_places = form_object.decimal_places.data mod_graph.show_pid_info = form_object.show_pid_info.data mod_graph.show_set_setpoint = form_object.show_set_setpoint.data if form_object.pid_id.data: mod_graph.pid_ids = form_object.pid_id.data # Camera Mod elif form_base.dashboard_type.data == 'camera': mod_graph.width = form_base.width.data mod_graph.height = form_base.height.data mod_graph.refresh_duration = form_base.refresh_duration.data mod_graph.camera_max_age = form_object.camera_max_age.data mod_graph.camera_id = form_object.camera_id.data mod_graph.camera_image_type = form_object.camera_image_type.data else: flash_form_errors(form_base) if not error: try: db.session.commit() except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_dashboard'))
def output_mod(form_output): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['output']['title']) error = [] try: mod_output = Output.query.filter( Output.unique_id == form_output.output_id.data).first() mod_output.name = form_output.name.data mod_output.amps = form_output.amps.data if form_output.trigger_functions_at_start.data: mod_output.trigger_functions_at_start = form_output.trigger_functions_at_start.data if mod_output.output_type == 'wired': if not is_int(form_output.gpio_location.data): error.append("BCM GPIO Pin must be an integer") mod_output.pin = form_output.gpio_location.data mod_output.trigger = bool(int(form_output.trigger.data)) elif mod_output.output_type == 'wireless_rpi_rf': if not is_int(form_output.gpio_location.data): error.append("Pin must be an integer") if not is_int(form_output.protocol.data): error.append("Protocol must be an integer") if not is_int(form_output.pulse_length.data): error.append("Pulse Length must be an integer") if not is_int(form_output.on_command.data): error.append("On Command must be an integer") if not is_int(form_output.off_command.data): error.append("Off Command must be an integer") mod_output.pin = form_output.gpio_location.data mod_output.protocol = form_output.protocol.data mod_output.pulse_length = form_output.pulse_length.data mod_output.on_command = form_output.on_command.data mod_output.off_command = form_output.off_command.data elif mod_output.output_type in ['command', 'python']: mod_output.on_command = form_output.on_command.data mod_output.off_command = form_output.off_command.data elif mod_output.output_type in ['command_pwm', 'python_pwm']: mod_output.pwm_command = form_output.pwm_command.data mod_output.pwm_invert_signal = form_output.pwm_invert_signal.data elif mod_output.output_type == 'pwm': mod_output.pin = form_output.gpio_location.data mod_output.pwm_hertz = form_output.pwm_hertz.data mod_output.pwm_library = form_output.pwm_library.data mod_output.pwm_invert_signal = form_output.pwm_invert_signal.data elif mod_output.output_type.startswith('atlas_ezo_pmp'): mod_output.location = form_output.location.data if form_output.flow_rate.data > 105 or form_output.flow_rate.data < 0.5: error.append("Flow Rate must be between 0.5 and 105 ml/min") else: mod_output.flow_rate = form_output.flow_rate.data if form_output.i2c_bus.data: mod_output.i2c_bus = form_output.i2c_bus.data if form_output.baud_rate.data: mod_output.baud_rate = form_output.baud_rate.data if (form_output.on_at_start.data == '-1' or mod_output.output_type in ['pwm', 'command_pwm']): mod_output.on_at_start = None elif form_output.on_at_start.data is not None: try: mod_output.on_at_start = bool(int( form_output.on_at_start.data)) except Exception: logger.error( "Error: Could not handle form_output.on_at_start.data: " "{}".format(form_output.on_at_start.data)) if not error: db.session.commit() manipulate_output('Modify', form_output.output_id.data) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_output'))
def pid_mod(form_mod_pid_base, form_mod_pid_pwm_raise, form_mod_pid_pwm_lower, form_mod_pid_output_raise, form_mod_pid_output_lower, form_mod_pid_value_raise, form_mod_pid_value_lower, form_mod_pid_volume_raise, form_mod_pid_volume_lower): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['pid']['title']) error = [] dict_outputs = parse_output_information() if not form_mod_pid_base.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_base) mod_pid = PID.query.filter( PID.unique_id == form_mod_pid_base.function_id.data).first() mod_pid.name = form_mod_pid_base.name.data mod_pid.measurement = form_mod_pid_base.measurement.data mod_pid.direction = form_mod_pid_base.direction.data mod_pid.period = form_mod_pid_base.period.data mod_pid.log_level_debug = form_mod_pid_base.log_level_debug.data mod_pid.start_offset = form_mod_pid_base.start_offset.data mod_pid.max_measure_age = form_mod_pid_base.max_measure_age.data mod_pid.setpoint = form_mod_pid_base.setpoint.data mod_pid.band = abs(form_mod_pid_base.band.data) mod_pid.store_lower_as_negative = form_mod_pid_base.store_lower_as_negative.data mod_pid.p = form_mod_pid_base.k_p.data mod_pid.i = form_mod_pid_base.k_i.data mod_pid.d = form_mod_pid_base.k_d.data mod_pid.integrator_min = form_mod_pid_base.integrator_max.data mod_pid.integrator_max = form_mod_pid_base.integrator_min.data mod_pid.setpoint_tracking_type = form_mod_pid_base.setpoint_tracking_type.data if form_mod_pid_base.setpoint_tracking_type.data == 'method': mod_pid.setpoint_tracking_id = form_mod_pid_base.setpoint_tracking_method_id.data elif form_mod_pid_base.setpoint_tracking_type.data == 'input-math': mod_pid.setpoint_tracking_id = form_mod_pid_base.setpoint_tracking_input_math_id.data if form_mod_pid_base.setpoint_tracking_max_age.data: mod_pid.setpoint_tracking_max_age = form_mod_pid_base.setpoint_tracking_max_age.data else: mod_pid.setpoint_tracking_max_age = 120 else: mod_pid.setpoint_tracking_id = '' # Change measurement information if ',' in form_mod_pid_base.measurement.data: measurement_id = form_mod_pid_base.measurement.data.split(',')[1] selected_measurement = get_measurement(measurement_id) measurements = DeviceMeasurements.query.filter( DeviceMeasurements.device_id == form_mod_pid_base.function_id.data).all() for each_measurement in measurements: # Only set channels 0, 1, 2 if each_measurement.channel in [0, 1, 2]: each_measurement.measurement = selected_measurement.measurement each_measurement.unit = selected_measurement.unit # # Handle Raise Output Settings # if form_mod_pid_base.raise_output_id.data: output_id = form_mod_pid_base.raise_output_id.data.split(",")[0] channel_id = form_mod_pid_base.raise_output_id.data.split(",")[1] raise_output_type = Output.query.filter( Output.unique_id == output_id).first().output_type def default_raise_output_settings(mod): if mod.raise_output_type == 'on_off': mod.raise_min_duration = 0 mod.raise_max_duration = 0 mod.raise_min_off_duration = 0 elif mod.raise_output_type == 'pwm': mod.raise_min_duration = 2 mod.raise_max_duration = 98 elif mod.raise_output_type == 'value': mod.raise_min_duration = 0 mod.raise_max_duration = 0 elif mod.raise_output_type == 'volume': mod.raise_min_duration = 0 mod.raise_max_duration = 0 return mod raise_output_id_changed = False if mod_pid.raise_output_id != form_mod_pid_base.raise_output_id.data: mod_pid.raise_output_id = form_mod_pid_base.raise_output_id.data raise_output_id_changed = True # Output ID changed if ('output_types' in dict_outputs[raise_output_type] and mod_pid.raise_output_id and raise_output_id_changed): if len(dict_outputs[raise_output_type]['output_types']) == 1: mod_pid.raise_output_type = dict_outputs[ raise_output_type]['output_types'][0] else: mod_pid.raise_output_type = None mod_pid = default_raise_output_settings(mod_pid) # Output ID unchanged elif ('output_types' in dict_outputs[raise_output_type] and mod_pid.raise_output_id and not raise_output_id_changed): if (not mod_pid.raise_output_type or mod_pid.raise_output_type != form_mod_pid_base.raise_output_type.data): if len(dict_outputs[raise_output_type] ['output_types']) > 1: mod_pid.raise_output_type = form_mod_pid_base.raise_output_type.data mod_pid = default_raise_output_settings(mod_pid) elif mod_pid.raise_output_type == 'on_off': if not form_mod_pid_output_raise.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_output_raise) else: mod_pid.raise_min_duration = form_mod_pid_output_raise.raise_min_duration.data mod_pid.raise_max_duration = form_mod_pid_output_raise.raise_max_duration.data mod_pid.raise_min_off_duration = form_mod_pid_output_raise.raise_min_off_duration.data elif mod_pid.raise_output_type == 'pwm': if not form_mod_pid_pwm_raise.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_pwm_raise) else: mod_pid.raise_min_duration = form_mod_pid_pwm_raise.raise_min_duty_cycle.data mod_pid.raise_max_duration = form_mod_pid_pwm_raise.raise_max_duty_cycle.data mod_pid.raise_always_min_pwm = form_mod_pid_pwm_raise.raise_always_min_pwm.data elif mod_pid.raise_output_type == 'value': if not form_mod_pid_value_raise.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_value_raise) else: mod_pid.raise_min_duration = form_mod_pid_value_raise.raise_min_amount.data mod_pid.raise_max_duration = form_mod_pid_value_raise.raise_max_amount.data elif mod_pid.raise_output_type == 'volume': if not form_mod_pid_volume_raise.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_volume_raise) else: mod_pid.raise_min_duration = form_mod_pid_volume_raise.raise_min_amount.data mod_pid.raise_max_duration = form_mod_pid_volume_raise.raise_max_amount.data else: mod_pid.raise_output_id = None # # Handle Lower Output Settings # if form_mod_pid_base.lower_output_id.data: output_id = form_mod_pid_base.lower_output_id.data.split(",")[0] channel_id = form_mod_pid_base.lower_output_id.data.split(",")[1] lower_output_type = Output.query.filter( Output.unique_id == output_id).first().output_type def default_lower_output_settings(mod): if mod.lower_output_type == 'on_off': mod.lower_min_duration = 0 mod.lower_max_duration = 0 mod.lower_min_off_duration = 0 elif mod.lower_output_type == 'pwm': mod.lower_min_duration = 2 mod.lower_max_duration = 98 elif mod.lower_output_type == 'value': mod.lower_min_duration = 0 mod.lower_max_duration = 0 elif mod.lower_output_type == 'volume': mod.lower_min_duration = 0 mod.lower_max_duration = 0 return mod lower_output_id_changed = False if mod_pid.lower_output_id != form_mod_pid_base.lower_output_id.data: mod_pid.lower_output_id = form_mod_pid_base.lower_output_id.data lower_output_id_changed = True # Output ID changed if ('output_types' in dict_outputs[lower_output_type] and mod_pid.lower_output_id and lower_output_id_changed): if len(dict_outputs[lower_output_type]['output_types']) == 1: mod_pid.lower_output_type = dict_outputs[ lower_output_type]['output_types'][0] else: mod_pid.lower_output_type = None mod_pid = default_lower_output_settings(mod_pid) # Output ID unchanged elif ('output_types' in dict_outputs[lower_output_type] and mod_pid.lower_output_id and not lower_output_id_changed): if (not mod_pid.lower_output_type or mod_pid.lower_output_type != form_mod_pid_base.lower_output_type.data): if len(dict_outputs[lower_output_type] ['output_types']) > 1: mod_pid.lower_output_type = form_mod_pid_base.lower_output_type.data mod_pid = default_lower_output_settings(mod_pid) elif mod_pid.lower_output_type == 'on_off': if not form_mod_pid_output_lower.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_output_lower) else: mod_pid.lower_min_duration = form_mod_pid_output_lower.lower_min_duration.data mod_pid.lower_max_duration = form_mod_pid_output_lower.lower_max_duration.data mod_pid.lower_min_off_duration = form_mod_pid_output_lower.lower_min_off_duration.data elif mod_pid.lower_output_type == 'pwm': if not form_mod_pid_pwm_lower.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_pwm_lower) else: mod_pid.lower_min_duration = form_mod_pid_pwm_lower.lower_min_duty_cycle.data mod_pid.lower_max_duration = form_mod_pid_pwm_lower.lower_max_duty_cycle.data mod_pid.lower_always_min_pwm = form_mod_pid_pwm_lower.lower_always_min_pwm.data elif mod_pid.lower_output_type == 'value': if not form_mod_pid_value_lower.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_value_lower) else: mod_pid.lower_min_duration = form_mod_pid_value_lower.lower_min_amount.data mod_pid.lower_max_duration = form_mod_pid_value_lower.lower_max_amount.data elif mod_pid.lower_output_type == 'volume': if not form_mod_pid_volume_lower.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_volume_lower) else: mod_pid.lower_min_duration = form_mod_pid_volume_lower.lower_min_amount.data mod_pid.lower_max_duration = form_mod_pid_volume_lower.lower_max_amount.data else: mod_pid.lower_output_id = None if (mod_pid.raise_output_id and mod_pid.lower_output_id and mod_pid.raise_output_id == mod_pid.lower_output_id): error.append(gettext("Raise and lower outputs cannot be the same")) try: if not error: db.session.commit() # If the controller is active or paused, refresh variables in thread if mod_pid.is_activated: control = DaemonControl() return_value = control.pid_mod( form_mod_pid_base.function_id.data) flash( "PID Controller settings refresh response: " "{resp}".format(resp=return_value), "success") except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def measurement_mod(form, return_url): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['measurement']['title']) error = [] mod_device = None device_info = None try: mod_meas = DeviceMeasurements.query.filter( DeviceMeasurements.unique_id == form.measurement_id.data).first() controller_type = determine_controller_type(mod_meas.device_id) if controller_type == "Input": mod_device = Input.query.filter(Input.unique_id == mod_meas.device_id).first() device_info = parse_input_information() elif controller_type == "Function": mod_device = CustomController.query.filter(CustomController.unique_id == mod_meas.device_id).first() device_info = parse_function_information() if not mod_device or not device_info: logger.error("Could not find mod_device or device_info") return if mod_device.is_activated: error.append(gettext( "Deactivate controller before modifying its settings")) mod_meas.name = form.name.data if form.device_type.data == 'measurement_select': if not form.select_measurement_unit.data: error.append("Must select a measurement unit") else: mod_meas.measurement = form.select_measurement_unit.data.split(',')[0] mod_meas.unit = form.select_measurement_unit.data.split(',')[1] elif form.device_type.data == 'measurement_convert': if ('enable_channel_unit_select' in device_info[mod_device.device] and device_info[mod_device.device]['enable_channel_unit_select']): if ',' in form.select_measurement_unit.data: mod_meas.measurement = form.select_measurement_unit.data.split(',')[0] mod_meas.unit = form.select_measurement_unit.data.split(',')[1] else: mod_meas.measurement = '' mod_meas.unit = '' if form.rescaled_measurement_unit.data != '' and ',' in form.rescaled_measurement_unit.data: mod_meas.rescaled_measurement = form.rescaled_measurement_unit.data.split(',')[0] mod_meas.rescaled_unit = form.rescaled_measurement_unit.data.split(',')[1] elif form.rescaled_measurement_unit.data == '': mod_meas.rescaled_measurement = '' mod_meas.rescaled_unit = '' mod_meas.scale_from_min = form.scale_from_min.data mod_meas.scale_from_max = form.scale_from_max.data mod_meas.scale_to_min = form.scale_to_min.data mod_meas.scale_to_max = form.scale_to_max.data mod_meas.invert_scale = form.invert_scale.data mod_meas.conversion_id = form.convert_to_measurement_unit.data if not error: db.session.commit() except Exception as except_msg: logger.exception(1) error.append(except_msg) flash_success_errors(error, action, return_url)
def widget_mod(form_base, request_form): """Modify the settings of an item on the dashboard""" action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['widget']['title']) error = [] dict_widgets = parse_widget_information() mod_widget = Widget.query.filter( Widget.unique_id == form_base.widget_id.data).first() mod_widget.name = form_base.name.data mod_widget.font_em_name = form_base.font_em_name.data mod_widget.enable_drag_handle = form_base.enable_drag_handle.data mod_widget.refresh_duration = form_base.refresh_duration.data try: custom_options_json_presave = json.loads(mod_widget.custom_options) except: logger.error("Malformed JSON") custom_options_json_presave = {} # Generate string to save from custom options error, custom_options_json_postsave = custom_options_return_json( error, dict_widgets, request_form, mod_dev=mod_widget, device=mod_widget.graph_type) if 'execute_at_modification' in dict_widgets[mod_widget.graph_type]: (allow_saving, page_refresh, mod_widget, custom_options ) = dict_widgets[mod_widget.graph_type]['execute_at_modification']( mod_widget, request_form, custom_options_json_presave, json.loads(custom_options_json_postsave)) custom_options = json.dumps( custom_options) # Convert from dict to JSON string if not allow_saving: error.append( "execute_at_modification() would not allow widget options to be saved" ) else: custom_options = custom_options_json_postsave mod_widget.custom_options = custom_options if not error: try: db.session.commit() except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) control = DaemonControl() control.widget_add_refresh(mod_widget.unique_id) flash_success_errors( error, action, url_for('routes_dashboard.page_dashboard', dashboard_id=form_base.dashboard_id.data))
def conditional_action_mod(form): """Modify a Conditional Action""" error = [] action = '{action} {controller}'.format( action=gettext("Mod"), controller=gettext("Conditional")) error = check_form_actions(form, error) try: mod_action = ConditionalActions.query.filter( ConditionalActions.id == form.conditional_action_id.data).first() if mod_action.do_action == 'output': mod_action.do_relay_id = form.do_relay_id.data mod_action.do_relay_state = form.do_relay_state.data mod_action.do_relay_duration = form.do_relay_duration.data elif mod_action.do_action in ['activate_pid', 'deactivate_pid', 'resume_pid', 'pause_pid' ]: mod_action.do_pid_id = form.do_pid_id.data elif mod_action.do_action == 'email': mod_action.do_action_string = form.do_action_string.data elif mod_action.do_action in ['photo_email', 'video_email']: mod_action.do_action_string = form.do_action_string.data mod_action.do_camera_id = form.do_camera_id.data elif mod_action.do_action in ['flash_lcd', 'flash_lcd_on', 'flash_lcd_off', 'lcd_backlight_off', 'lcd_backlight_on']: mod_action.do_lcd_id = form.do_lcd_id.data elif mod_action.do_action == 'photo': mod_action.do_camera_id = form.do_camera_id.data elif mod_action.do_action == 'video': mod_action.do_camera_id = form.do_camera_id.data mod_action.do_camera_duration = form.do_camera_duration.data elif mod_action.do_action == 'command': mod_action.do_action_string = form.do_action_string.data if not error: db.session.commit() check_refresh_conditional(form.conditional_id.data) except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def function_add(form_add_func): action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['function']['title']) error = [] function_name = form_add_func.function_type.data dict_controllers = parse_controller_information() if current_app.config['TESTING']: dep_unmet = False else: dep_unmet, _ = return_dependencies(function_name) if dep_unmet: list_unmet_deps = [] for each_dep in dep_unmet: list_unmet_deps.append(each_dep[0]) error.append( "The {dev} device you're trying to add has unmet " "dependencies: {dep}".format( dev=function_name, dep=', '.join(list_unmet_deps))) new_func = None try: if function_name.startswith('conditional_'): new_func = Conditional() new_func.conditional_statement = ''' # Example code for learning how to use a Conditional. See the manual for more information. self.logger.info("This INFO log entry will appear in the Daemon Log") self.logger.error("This ERROR log entry will appear in the Daemon Log") # Replace "asdf1234" with a Condition ID measurement = self.condition("{asdf1234}") self.logger.info("Check this measurement in the Daemon Log. The value is {val}".format(val=measurement)) if measurement is not None: # If a measurement exists self.message += "This message appears in email alerts and notes.\\n" if measurement < 23: # If the measurement is less than 23 self.message += "Measurement is too Low! Measurement is {meas}\\n".format(meas=measurement) self.run_all_actions(message=self.message) # Run all actions sequentially elif measurement > 27: # Else If the measurement is greater than 27 self.message += "Measurement is too High! Measurement is {meas}\\n".format(meas=measurement) # Replace "qwer5678" with an Action ID self.run_action("{qwer5678}", message=self.message) # Run a single specific Action''' if not error: new_func.save() save_conditional_code( error, new_func.conditional_statement, new_func.unique_id, test=False) elif function_name.startswith('pid_'): new_func = PID().save() for each_channel, measure_info in PID_INFO['measure'].items(): new_measurement = DeviceMeasurements() if 'name' in measure_info: new_measurement.name = measure_info['name'] if 'measurement_type' in measure_info: new_measurement.measurement_type = measure_info['measurement_type'] new_measurement.device_id = new_func.unique_id new_measurement.measurement = measure_info['measurement'] new_measurement.unit = measure_info['unit'] new_measurement.channel = each_channel if not error: new_measurement.save() elif function_name.startswith('trigger_'): new_func = Trigger() new_func.name = '{}'.format(FUNCTION_INFO[function_name]['name']) new_func.trigger_type = function_name if not error: new_func.save() elif function_name.startswith('function_'): new_func = Function() if function_name == 'function_spacer': new_func.name = 'Spacer' new_func.function_type = function_name if not error: new_func.save() elif function_name in dict_controllers: new_func = CustomController() new_func.device = function_name if 'controller_name' in dict_controllers[function_name]: new_func.name = dict_controllers[function_name]['controller_name'] else: new_func.name = 'Controller Name' list_options = [] if 'custom_options' in dict_controllers[function_name]: for each_option in dict_controllers[function_name]['custom_options']: if each_option['default_value'] is False: default_value = '' else: default_value = each_option['default_value'] option = '{id},{value}'.format( id=each_option['id'], value=default_value) list_options.append(option) new_func.custom_options = ';'.join(list_options) if not error: new_func.save() elif function_name == '': error.append("Must select a function type") else: error.append("Unknown function type: '{}'".format( function_name)) if not error: display_order = csv_to_list_of_str( DisplayOrder.query.first().function) DisplayOrder.query.first().function = add_display_order( display_order, new_func.unique_id) db.session.commit() except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function')) if dep_unmet: return 1
def lcd_add(form): action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['lcd']['title']) error = [] if current_app.config['TESTING']: dep_unmet = False else: dep_unmet, _ = return_dependencies(form.lcd_type.data.split(",")[0]) if dep_unmet: list_unmet_deps = [] for each_dep in dep_unmet: list_unmet_deps.append(each_dep[0]) error.append( "The {dev} device you're trying to add has unmet " "dependencies: {dep}".format( dev=form.lcd_type.data, dep=', '.join(list_unmet_deps))) try: new_lcd = LCD() new_lcd_data = LCDData() try: from RPi import GPIO if GPIO.RPI_REVISION == 2 or GPIO.RPI_REVISION == 3: new_lcd.i2c_bus = 1 else: new_lcd.i2c_bus = 0 except: logger.error("RPi.GPIO and Raspberry Pi required for this action") lcd_id = form.lcd_type.data.split(",")[0] lcd_interface = form.lcd_type.data.split(",")[1] new_lcd.lcd_type = lcd_id new_lcd.interface = lcd_interface new_lcd.name = str(LCD_INFO[lcd_id]['name']) if (lcd_interface == 'I2C' and lcd_id in [ '128x32_pioled', '128x64_pioled', '128x32_pioled_circuit_python', '128x64_pioled_circuit_python']): new_lcd.location = '0x3c' new_lcd.pin_reset = 19 elif lcd_interface == 'I2C' and lcd_id in ['16x2_generic', '20x4_generic']: new_lcd.location = '0x27' elif lcd_interface == 'I2C' and lcd_id == '16x2_grove_lcd_rgb': new_lcd.location = '0x3e' new_lcd.location_backlight = '0x62' elif lcd_interface == 'SPI': new_lcd.pin_reset = 19 new_lcd.pin_dc = 16 new_lcd.pin_cs = 17 new_lcd.spi_device = 0 new_lcd.spi_bus = 0 if lcd_id in ['28x32_pioled', '128x32_pioled_circuit_python']: new_lcd.x_characters = 21 new_lcd.y_lines = 4 elif lcd_id in ['128x64_pioled', '128x64_pioled_circuit_python']: new_lcd.x_characters = 21 new_lcd.y_lines = 8 elif lcd_id == '16x2_generic': new_lcd.x_characters = 16 new_lcd.y_lines = 2 elif lcd_id == '20x4_generic': new_lcd.x_characters = 20 new_lcd.y_lines = 4 elif lcd_id == '16x2_grove_lcd_rgb': new_lcd.x_characters = 16 new_lcd.y_lines = 2 if not error: new_lcd.save() new_lcd_data.lcd_id = new_lcd.unique_id new_lcd_data.save() display_order = csv_to_list_of_str(DisplayOrder.query.first().lcd) DisplayOrder.query.first().lcd = add_display_order( display_order, new_lcd.unique_id) db.session.commit() except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_lcd')) if dep_unmet: return 1
def widget_mod(form_base, form_object, request_form): """Modify the settings of an item on the dashboard""" action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['widget']['title']) error = [] mod_widget = Widget.query.filter( Widget.unique_id == form_base.widget_id.data).first() mod_widget.name = form_base.name.data mod_widget.font_em_name = form_base.font_em_name.data mod_widget.enable_drag_handle = form_base.enable_drag_handle.data # Graph Mod if form_base.widget_type.data == 'graph': error = graph_error_check(form_object, error) # Generate color option string from form inputs sorted_colors_string, error = custom_colors_graph_str( request_form, error) mod_widget.custom_colors = sorted_colors_string disable_data_grouping_string, error = data_grouping_graph_str( request_form, error) mod_widget.disable_data_grouping = disable_data_grouping_string mod_widget.use_custom_colors = form_object.use_custom_colors.data # Generate y-axis option string from form inputs yaxes_string = custom_yaxes_str_from_form(request_form) mod_widget.custom_yaxes = yaxes_string mod_widget.enable_manual_y_axis = form_object.enable_manual_y_axis.data mod_widget.enable_align_ticks = form_object.enable_align_ticks.data mod_widget.enable_start_on_tick = form_object.enable_start_on_tick.data mod_widget.enable_end_on_tick = form_object.enable_end_on_tick.data if form_object.math_ids.data: mod_widget.math_ids = ";".join(form_object.math_ids.data) else: mod_widget.math_ids = '' if form_object.pid_ids.data: mod_widget.pid_ids = ";".join(form_object.pid_ids.data) else: mod_widget.pid_ids = '' if form_object.output_ids.data: mod_widget.output_ids = ";".join(form_object.output_ids.data) else: mod_widget.output_ids = '' if form_object.input_ids.data: mod_widget.input_ids_measurements = ";".join( form_object.input_ids.data) else: mod_widget.input_ids_measurements = '' if form_object.note_tag_ids.data: mod_widget.note_tag_ids = ";".join(form_object.note_tag_ids.data) else: mod_widget.note_tag_ids = '' mod_widget.refresh_duration = form_base.refresh_duration.data mod_widget.enable_header_buttons = form_object.enable_header_buttons.data mod_widget.x_axis_duration = form_object.xaxis_duration.data mod_widget.enable_auto_refresh = form_object.enable_auto_refresh.data mod_widget.enable_xaxis_reset = form_object.enable_xaxis_reset.data mod_widget.enable_title = form_object.enable_title.data mod_widget.enable_navbar = form_object.enable_navbar.data mod_widget.enable_export = form_object.enable_export.data mod_widget.enable_rangeselect = form_object.enable_rangeselect.data mod_widget.enable_graph_shift = form_object.enable_graph_shift.data # If a gauge type is changed, the color format must change elif (form_base.widget_type.data == 'gauge' and mod_widget.graph_type != form_object.gauge_type.data): mod_widget.graph_type = form_object.gauge_type.data mod_widget.range_colors = gauge_reformat_stops( form_object.gauge_type.data, 4, form_object.stops.data, current_colors=None) mod_widget.stops = form_object.stops.data # Gauge Mod elif form_base.widget_type.data == 'gauge': error = gauge_error_check(form_object, error) # Generate color option string from form inputs sorted_colors_string, error = custom_colors_gauge_str( request_form, form_object.gauge_type.data, error) mod_widget.refresh_duration = form_base.refresh_duration.data mod_widget.range_colors = sorted_colors_string mod_widget.y_axis_min = form_object.y_axis_min.data mod_widget.y_axis_max = form_object.y_axis_max.data mod_widget.max_measure_age = form_object.max_measure_age.data mod_widget.enable_timestamp = form_object.enable_timestamp.data mod_widget.range_colors = gauge_reformat_stops( form_object.gauge_type.data, mod_widget.stops, form_object.stops.data, current_colors=mod_widget.range_colors) mod_widget.stops = form_object.stops.data if form_object.input_ids.data: mod_widget.input_ids_measurements = form_object.input_ids.data else: error.append("A valid Measurement must be selected") # Indicator Mod elif form_base.widget_type.data == 'indicator': error = indicator_error_check(form_object, error) mod_widget.refresh_duration = form_base.refresh_duration.data mod_widget.max_measure_age = form_object.max_measure_age.data mod_widget.font_em_timestamp = form_object.font_em_timestamp.data mod_widget.option_invert = form_object.option_invert.data mod_widget.enable_timestamp = form_object.enable_timestamp.data if form_object.measurement_id.data: mod_widget.input_ids_measurements = form_object.measurement_id.data # Measurement Mod elif form_base.widget_type.data == 'measurement': error = measurement_error_check(form_object, error) mod_widget.refresh_duration = form_base.refresh_duration.data mod_widget.max_measure_age = form_object.max_measure_age.data mod_widget.font_em_value = form_object.font_em_value.data mod_widget.font_em_timestamp = form_object.font_em_timestamp.data mod_widget.decimal_places = form_object.decimal_places.data mod_widget.enable_name = form_object.enable_name.data mod_widget.enable_unit = form_object.enable_unit.data mod_widget.enable_measurement = form_object.enable_measurement.data mod_widget.enable_channel = form_object.enable_channel.data mod_widget.enable_timestamp = form_object.enable_timestamp.data if form_object.measurement_id.data: mod_widget.input_ids_measurements = form_object.measurement_id.data # Output Mod elif form_base.widget_type.data in ['output', 'output_pwm_slider']: error = output_error_check(form_object, error) mod_widget.refresh_duration = form_base.refresh_duration.data mod_widget.max_measure_age = form_object.max_measure_age.data mod_widget.font_em_value = form_object.font_em_value.data mod_widget.font_em_timestamp = form_object.font_em_timestamp.data mod_widget.decimal_places = form_object.decimal_places.data mod_widget.enable_output_controls = form_object.enable_output_controls.data mod_widget.enable_status = form_object.enable_status.data mod_widget.enable_value = form_object.enable_value.data mod_widget.enable_unit = form_object.enable_unit.data mod_widget.enable_timestamp = form_object.enable_timestamp.data if form_object.output_id.data: mod_widget.output_ids = form_object.output_id.data # PID Control Mod elif form_base.widget_type.data == 'pid_control': error = pid_error_check(form_object, error) mod_widget.refresh_duration = form_base.refresh_duration.data mod_widget.max_measure_age = form_object.max_measure_age.data mod_widget.font_em_value = form_object.font_em_value.data mod_widget.font_em_timestamp = form_object.font_em_timestamp.data mod_widget.decimal_places = form_object.decimal_places.data mod_widget.enable_status = form_object.enable_status.data mod_widget.enable_timestamp = form_object.enable_timestamp.data mod_widget.show_pid_info = form_object.show_pid_info.data mod_widget.show_set_setpoint = form_object.show_set_setpoint.data if form_object.pid_id.data: mod_widget.pid_ids = form_object.pid_id.data # Camera Mod elif form_base.widget_type.data == 'camera': mod_widget.refresh_duration = form_base.refresh_duration.data mod_widget.camera_max_age = form_object.camera_max_age.data mod_widget.camera_id = form_object.camera_id.data mod_widget.camera_image_type = form_object.camera_image_type.data else: flash_form_errors(form_base) if not error: try: db.session.commit() except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) flash_success_errors( error, action, url_for('routes_page.page_dashboard', dashboard_id=form_base.dashboard_id.data))
def widget_add(form_base, form_object): """Add a widget to the dashboard""" action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['widget']['title']) error = [] new_widget = Widget() new_widget.dashboard_id = form_base.dashboard_id.data new_widget.name = form_base.name.data new_widget.font_em_name = form_base.font_em_name.data new_widget.enable_drag_handle = form_base.enable_drag_handle.data # Find where the next widget should be placed on the grid # Finds the lowest position to create as the new Widget's starting position position_y_start = 0 for each_widget in Widget.query.filter( Widget.dashboard_id == form_base.dashboard_id.data).all(): highest_position = each_widget.position_y + each_widget.height if highest_position > position_y_start: position_y_start = highest_position new_widget.position_y = position_y_start # Spacer if form_base.widget_type.data == 'spacer': widget_type = 'Spacer' new_widget.graph_type = form_base.widget_type.data new_widget.width = 20 new_widget.height = 1 # Graph elif (form_base.widget_type.data == 'graph' and (form_base.name.data and form_object.xaxis_duration.data and form_base.refresh_duration.data)): widget_type = 'Graph' error = graph_error_check(form_object, error) new_widget.graph_type = form_base.widget_type.data if form_object.math_ids.data: new_widget.math_ids = ";".join(form_object.math_ids.data) if form_object.pid_ids.data: new_widget.pid_ids = ";".join(form_object.pid_ids.data) if form_object.output_ids.data: new_widget.output_ids = ";".join(form_object.output_ids.data) if form_object.input_ids.data: new_widget.input_ids_measurements = ";".join( form_object.input_ids.data) if form_object.note_tag_ids.data: new_widget.note_tag_ids = ";".join(form_object.note_tag_ids.data) new_widget.refresh_duration = form_base.refresh_duration.data new_widget.enable_header_buttons = form_object.enable_header_buttons.data new_widget.x_axis_duration = form_object.xaxis_duration.data new_widget.enable_auto_refresh = form_object.enable_auto_refresh.data new_widget.enable_xaxis_reset = form_object.enable_xaxis_reset.data new_widget.enable_title = form_object.enable_title.data new_widget.enable_navbar = form_object.enable_navbar.data new_widget.enable_rangeselect = form_object.enable_rangeselect.data new_widget.enable_export = form_object.enable_export.data new_widget.enable_graph_shift = form_object.enable_graph_shift.data new_widget.enable_manual_y_axis = form_object.enable_manual_y_axis.data new_widget.width = 20 new_widget.height = 9 # Gauge elif form_base.widget_type.data == 'gauge': widget_type = 'Gauge' error = gauge_error_check(form_object, error) new_widget.graph_type = form_object.gauge_type.data new_widget.refresh_duration = form_base.refresh_duration.data new_widget.max_measure_age = form_object.max_measure_age.data new_widget.y_axis_min = form_object.y_axis_min.data new_widget.y_axis_max = form_object.y_axis_max.data new_widget.input_ids_measurements = form_object.input_ids.data new_widget.enable_timestamp = form_object.enable_timestamp.data new_widget.stops = form_object.stops.data new_widget.width = 4 if form_object.gauge_type.data == 'gauge_solid': new_widget.height = 4 elif form_object.gauge_type.data == 'gauge_angular': new_widget.height = 5 if form_object.stops.data < 2: error.append("Must be at least 2 stops") else: new_widget.range_colors = gauge_reformat_stops( form_object.gauge_type.data, 4, new_widget.stops, current_colors=None) # Indicator elif form_base.widget_type.data == 'indicator': widget_type = 'Indicator' error = measurement_error_check(form_object, error) new_widget.graph_type = 'indicator' new_widget.refresh_duration = form_base.refresh_duration.data new_widget.max_measure_age = form_object.max_measure_age.data new_widget.font_em_timestamp = form_object.font_em_timestamp.data new_widget.input_ids_measurements = form_object.measurement_id.data new_widget.enable_timestamp = form_object.enable_timestamp.data new_widget.width = 3 new_widget.height = 4 # Measurement elif form_base.widget_type.data == 'measurement': widget_type = 'Measurement' error = measurement_error_check(form_object, error) new_widget.graph_type = 'measurement' new_widget.max_measure_age = form_object.max_measure_age.data new_widget.refresh_duration = form_base.refresh_duration.data new_widget.font_em_value = form_object.font_em_value.data new_widget.font_em_timestamp = form_object.font_em_timestamp.data new_widget.decimal_places = form_object.decimal_places.data new_widget.input_ids_measurements = form_object.measurement_id.data new_widget.enable_name = form_object.enable_name.data new_widget.enable_unit = form_object.enable_unit.data new_widget.enable_measurement = form_object.enable_measurement.data new_widget.enable_channel = form_object.enable_channel.data new_widget.enable_timestamp = form_object.enable_timestamp.data new_widget.width = 4 new_widget.height = 5 # Output elif form_base.widget_type.data == 'output': widget_type = 'Output' error = output_error_check(form_object, error) new_widget.graph_type = 'output' new_widget.max_measure_age = form_object.max_measure_age.data new_widget.refresh_duration = form_base.refresh_duration.data new_widget.font_em_value = form_object.font_em_value.data new_widget.font_em_timestamp = form_object.font_em_timestamp.data new_widget.enable_output_controls = form_object.enable_output_controls.data new_widget.decimal_places = form_object.decimal_places.data new_widget.output_ids = form_object.output_id.data new_widget.enable_status = form_object.enable_status.data new_widget.enable_value = form_object.enable_value.data new_widget.enable_unit = form_object.enable_unit.data new_widget.enable_timestamp = form_object.enable_timestamp.data new_widget.width = 5 new_widget.height = 4 # Output Range Slider elif form_base.widget_type.data == 'output_pwm_slider': widget_type = 'Output Range Slider' error = output_error_check(form_object, error) new_widget.graph_type = 'output_pwm_slider' new_widget.max_measure_age = form_object.max_measure_age.data new_widget.refresh_duration = form_base.refresh_duration.data new_widget.font_em_value = form_object.font_em_value.data new_widget.font_em_timestamp = form_object.font_em_timestamp.data new_widget.enable_output_controls = form_object.enable_output_controls.data new_widget.decimal_places = form_object.decimal_places.data new_widget.output_ids = form_object.output_id.data new_widget.enable_status = form_object.enable_status.data new_widget.enable_value = form_object.enable_value.data new_widget.enable_unit = form_object.enable_unit.data new_widget.enable_timestamp = form_object.enable_timestamp.data new_widget.width = 5 new_widget.height = 4 # PID Control elif form_base.widget_type.data == 'pid_control': widget_type = 'PID Control' error = pid_error_check(form_object, error) new_widget.graph_type = 'pid_control' new_widget.max_measure_age = form_object.max_measure_age.data new_widget.refresh_duration = form_base.refresh_duration.data new_widget.font_em_value = form_object.font_em_value.data new_widget.font_em_timestamp = form_object.font_em_timestamp.data new_widget.decimal_places = form_object.decimal_places.data new_widget.show_pid_info = form_object.show_pid_info.data new_widget.enable_status = form_object.enable_status.data new_widget.enable_timestamp = form_object.enable_timestamp.data new_widget.show_set_setpoint = form_object.show_set_setpoint.data new_widget.pid_ids = form_object.pid_id.data new_widget.width = 6 new_widget.height = 5 # Camera elif form_base.widget_type.data == 'camera': widget_type = 'Camera' camera = Camera.query.filter( Camera.unique_id == form_object.camera_id.data).first() if not camera: error.append("Invalid Camera ID.") elif (form_object.camera_image_type.data == 'stream' and camera.library not in ['opencv', 'picamera']): error.append("Only cameras that use the 'picamera' or " "'opencv' library may be used for streaming") new_widget.graph_type = form_base.widget_type.data new_widget.refresh_duration = form_base.refresh_duration.data new_widget.camera_max_age = form_object.camera_max_age.data new_widget.camera_id = form_object.camera_id.data new_widget.camera_image_type = form_object.camera_image_type.data new_widget.width = 7 new_widget.height = 8 else: flash_form_errors(form_base) return try: if not error: new_widget.save() flash( gettext("{dev} with ID %(id)s successfully added".format( dev=widget_type), id=new_widget.id), "success") except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) flash_success_errors( error, action, url_for('routes_page.page_dashboard', dashboard_id=form_base.dashboard_id.data))
def camera_mod(form_camera): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['camera']['title']) error = [] try: if (Camera.query.filter( Camera.unique_id != form_camera.camera_id.data).filter( Camera.name == form_camera.name.data).count()): flash("You must choose a unique name", "error") return redirect(url_for('routes_settings.settings_camera')) if 0 > form_camera.rotation.data > 360: flash("Rotation must be between 0 and 360 degrees", "error") return redirect(url_for('routes_settings.settings_camera')) mod_camera = Camera.query.filter( Camera.unique_id == form_camera.camera_id.data).first() mod_camera.name = form_camera.name.data mod_camera.width = form_camera.width.data mod_camera.height = form_camera.height.data mod_camera.hflip = form_camera.hflip.data mod_camera.vflip = form_camera.vflip.data mod_camera.rotation = form_camera.rotation.data mod_camera.brightness = form_camera.brightness.data mod_camera.hide_still = form_camera.hide_still.data mod_camera.hide_timelapse = form_camera.hide_timelapse.data mod_camera.path_still = form_camera.path_still.data mod_camera.path_timelapse = form_camera.path_timelapse.data mod_camera.path_video = form_camera.path_video.data if form_camera.stream_fps.data: if form_camera.stream_fps.data < 1: error.append("Stream FPS cannot be less than 1") mod_camera.stream_fps = form_camera.stream_fps.data if mod_camera.library == 'fswebcam': mod_camera.device = form_camera.device.data mod_camera.custom_options = form_camera.custom_options.data if mod_camera.library == 'raspistill': mod_camera.brightness = form_camera.brightness.data mod_camera.contrast = form_camera.contrast.data mod_camera.saturation = form_camera.saturation.data mod_camera.picamera_sharpness = form_camera.picamera_sharpness.data mod_camera.picamera_iso = int(form_camera.picamera_iso.data) mod_camera.picamera_awb = form_camera.picamera_awb.data mod_camera.custom_options = form_camera.custom_options.data elif mod_camera.library == 'picamera': mod_camera.resolution_stream_width = form_camera.resolution_stream_width.data mod_camera.resolution_stream_height = form_camera.resolution_stream_height.data mod_camera.contrast = form_camera.contrast.data mod_camera.exposure = form_camera.exposure.data mod_camera.saturation = form_camera.saturation.data mod_camera.picamera_shutter_speed = form_camera.picamera_shutter_speed.data mod_camera.picamera_sharpness = form_camera.picamera_sharpness.data mod_camera.picamera_iso = int(form_camera.picamera_iso.data) mod_camera.picamera_awb = form_camera.picamera_awb.data mod_camera.picamera_awb_gain_red = form_camera.picamera_awb_gain_red.data mod_camera.picamera_awb_gain_blue = form_camera.picamera_awb_gain_blue.data mod_camera.picamera_exposure_mode = form_camera.picamera_exposure_mode.data mod_camera.picamera_meter_mode = form_camera.picamera_meter_mode.data mod_camera.picamera_image_effect = form_camera.picamera_image_effect.data elif mod_camera.library == 'opencv': mod_camera.opencv_device = form_camera.opencv_device.data mod_camera.resolution_stream_width = form_camera.resolution_stream_width.data mod_camera.resolution_stream_height = form_camera.resolution_stream_height.data mod_camera.hflip = form_camera.hflip.data mod_camera.vflip = form_camera.vflip.data mod_camera.rotation = form_camera.rotation.data mod_camera.height = form_camera.height.data mod_camera.width = form_camera.width.data mod_camera.brightness = form_camera.brightness.data mod_camera.contrast = form_camera.contrast.data mod_camera.exposure = form_camera.exposure.data mod_camera.gain = form_camera.gain.data mod_camera.hue = form_camera.hue.data mod_camera.saturation = form_camera.saturation.data mod_camera.white_balance = form_camera.white_balance.data elif mod_camera.library == 'http_address': mod_camera.url_still = form_camera.url_still.data mod_camera.url_stream = form_camera.url_stream.data elif mod_camera.library == 'http_address_requests': mod_camera.url_still = form_camera.url_still.data mod_camera.url_stream = form_camera.url_stream.data else: error.append("Unknown camera library") if form_camera.output_id.data: mod_camera.output_id = form_camera.output_id.data else: mod_camera.output_id = None mod_camera.output_duration = form_camera.output_duration.data mod_camera.cmd_pre_camera = form_camera.cmd_pre_camera.data mod_camera.cmd_post_camera = form_camera.cmd_post_camera.data if not error: db.session.commit() control = DaemonControl() control.refresh_daemon_camera_settings() except Exception as except_msg: logger.exception(1) error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_camera'))
def trigger_mod(form): """Modify a Trigger""" error = [] action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['trigger']['title']) try: trigger = Trigger.query.filter( Trigger.unique_id == form.function_id.data).first() trigger.name = form.name.data if trigger.trigger_type == 'trigger_edge': error = check_form_edge(form, error) trigger.measurement = form.measurement.data trigger.edge_detected = form.edge_detected.data elif trigger.trigger_type == 'trigger_output': error = check_form_output(form, error) trigger.unique_id_1 = form.unique_id_1.data trigger.output_state = form.output_state.data trigger.output_duration = form.output_duration.data elif trigger.trigger_type == 'trigger_output_duration': error = check_form_output_duration(form, error) trigger.unique_id_1 = form.unique_id_1.data trigger.output_state = form.output_state.data trigger.output_duration = form.output_duration.data elif trigger.trigger_type == 'trigger_output_pwm': error = check_form_output_pwm(form, error) trigger.unique_id_1 = form.unique_id_1.data trigger.output_state = form.output_state.data trigger.output_duty_cycle = form.output_duty_cycle.data elif trigger.trigger_type == 'trigger_run_pwm_method': error = check_form_run_pwm_method(form, error) trigger.unique_id_1 = form.unique_id_1.data trigger.unique_id_2 = form.unique_id_2.data trigger.period = form.period.data trigger.trigger_actions_at_start = form.trigger_actions_at_start.data trigger.trigger_actions_at_period = form.trigger_actions_at_period.data elif trigger.trigger_type == 'trigger_sunrise_sunset': error = check_form_sunrise_sunset(form, error) trigger.rise_or_set = form.rise_or_set.data trigger.latitude = form.latitude.data trigger.longitude = form.longitude.data trigger.zenith = form.zenith.data trigger.date_offset_days = form.date_offset_days.data trigger.time_offset_minutes = form.time_offset_minutes.data elif trigger.trigger_type == 'trigger_timer_daily_time_point': error = check_form_timer_daily_time_point(form, error) trigger.timer_start_time = form.timer_start_time.data elif trigger.trigger_type == 'trigger_timer_daily_time_span': error = check_form_timer_daily_time_span(form, error) trigger.period = form.period.data trigger.timer_start_time = form.timer_start_time.data trigger.timer_end_time = form.timer_end_time.data elif trigger.trigger_type == 'trigger_timer_duration': error = check_form_timer_duration(form, error) trigger.period = form.period.data trigger.timer_start_offset = form.timer_start_offset.data if not error: db.session.commit() if trigger.is_activated: control = DaemonControl() return_value = control.refresh_daemon_trigger_settings( form.function_id.data) flash(gettext("Daemon response: %(resp)s", resp=return_value), "success") except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def controller_mod(form_mod, request_form): """Modify a Custom Function""" error = [] action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['controller']['title']) dict_controllers = parse_function_information() try: mod_controller = CustomController.query.filter( CustomController.unique_id == form_mod.function_id.data).first() if mod_controller.is_activated: error.append( gettext("Deactivate controller before modifying its settings")) mod_controller.name = form_mod.name.data mod_controller.log_level_debug = form_mod.log_level_debug.data # Enable/disable Channels measurements = DeviceMeasurements.query.filter( DeviceMeasurements.device_id == form_mod.function_id.data).all() if form_mod.measurements_enabled.data: for each_measurement in measurements: if each_measurement.unique_id in form_mod.measurements_enabled.data: each_measurement.is_enabled = True else: each_measurement.is_enabled = False channels = FunctionChannel.query.filter( FunctionChannel.function_id == form_mod.function_id.data) # Add or delete channels for variable measurement Inputs if ('measurements_variable_amount' in dict_controllers[mod_controller.device] and dict_controllers[ mod_controller.device]['measurements_variable_amount']): measurements = DeviceMeasurements.query.filter( DeviceMeasurements.device_id == form_mod.function_id.data) if measurements.count() != form_mod.num_channels.data: # Delete measurements/channels if form_mod.num_channels.data < measurements.count(): for index, each_channel in enumerate(measurements.all()): if index + 1 >= measurements.count(): delete_entry_with_id(DeviceMeasurements, each_channel.unique_id) if ('channel_quantity_same_as_measurements' in dict_controllers[mod_controller.device] and dict_controllers[mod_controller.device] ["channel_quantity_same_as_measurements"]): if form_mod.num_channels.data < channels.count(): for index, each_channel in enumerate( channels.all()): if index + 1 >= channels.count(): delete_entry_with_id( FunctionChannel, each_channel.unique_id) # Add measurements/channels elif form_mod.num_channels.data > measurements.count(): start_number = measurements.count() for index in range(start_number, form_mod.num_channels.data): new_measurement = DeviceMeasurements() new_measurement.name = "" new_measurement.device_id = mod_controller.unique_id new_measurement.measurement = "" new_measurement.unit = "" new_measurement.channel = index new_measurement.save() if ('channel_quantity_same_as_measurements' in dict_controllers[mod_controller.device] and dict_controllers[mod_controller.device] ["channel_quantity_same_as_measurements"]): new_channel = FunctionChannel() new_channel.name = "" new_channel.function_id = mod_controller.unique_id new_measurement.channel = index error, custom_options = custom_channel_options_return_json( error, dict_controllers, request_form, mod_controller.unique_id, index, device=mod_controller.device, use_defaults=True) new_channel.custom_options = custom_options new_channel.save() # Generate string to save from custom options error, custom_options = custom_options_return_json( error, dict_controllers, request_form=request_form, device=mod_controller.device, use_defaults=True) mod_controller.custom_options = custom_options if not error: db.session.commit() except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def method_add(form_add_method): """ Add line to method_data table """ action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['method']['title']) error = [] start_time = None end_time = None method = Method.query.filter( Method.unique_id == form_add_method.method_id.data).first() display_order = csv_to_list_of_str(method.method_order) try: if validate_method_data(form_add_method, method): return 1 if method.method_type == 'DailySine': add_method_data = MethodData.query.filter( MethodData.method_id == form_add_method.method_id.data).first() add_method_data.amplitude = form_add_method.amplitude.data add_method_data.frequency = form_add_method.frequency.data add_method_data.shift_angle = form_add_method.shift_angle.data add_method_data.shift_y = form_add_method.shiftY.data db.session.commit() return 0 elif method.method_type == 'DailyBezier': if not 0 <= form_add_method.shift_angle.data <= 360: flash(gettext("Error: Angle Shift is out of range. It must be " "<= 0 and <= 360."), "error") return 1 if form_add_method.x0.data <= form_add_method.x3.data: flash(gettext("Error: X0 must be greater than X3."), "error") return 1 add_method_data = MethodData.query.filter( MethodData.method_id == form_add_method.method_id.data).first() add_method_data.shift_angle = form_add_method.shift_angle.data add_method_data.x0 = form_add_method.x0.data add_method_data.y0 = form_add_method.y0.data add_method_data.x1 = form_add_method.x1.data add_method_data.y1 = form_add_method.y1.data add_method_data.x2 = form_add_method.x2.data add_method_data.y2 = form_add_method.y2.data add_method_data.x3 = form_add_method.x3.data add_method_data.y3 = form_add_method.y3.data db.session.commit() return 0 if form_add_method.method_select.data == 'setpoint': if method.method_type == 'Date': start_time = datetime.strptime( form_add_method.time_start.data, '%Y-%m-%d %H:%M:%S') end_time = datetime.strptime( form_add_method.time_end.data, '%Y-%m-%d %H:%M:%S') elif method.method_type == 'Daily': start_time = datetime.strptime( form_add_method.daily_time_start.data, '%H:%M:%S') end_time = datetime.strptime( form_add_method.daily_time_end.data, '%H:%M:%S') if method.method_type in ['Date', 'Daily']: # Check if the start time comes after the last entry's end time display_order = csv_to_list_of_str(method.method_order) if display_order: last_method = MethodData.query.filter( MethodData.unique_id == display_order[-1]).first() else: last_method = None if last_method is not None: if method.method_type == 'Date': last_method_end_time = datetime.strptime( last_method.time_end, '%Y-%m-%d %H:%M:%S') elif method.method_type == 'Daily': last_method_end_time = datetime.strptime( last_method.time_end, '%H:%M:%S') else: last_method_end_time = None if (start_time and last_method_end_time and start_time < last_method_end_time): flash(gettext("The new entry start time (%(st)s) " "cannot overlap the last entry's end " "time (%(et)s). Note: They may be the " "same time.", st=last_method_end_time, et=start_time), "error") return 1 elif form_add_method.method_select.data == 'output': if method.method_type == 'Date': start_time = datetime.strptime( form_add_method.output_time.data, '%Y-%m-%d %H:%M:%S') elif method.method_type == 'Daily': start_time = datetime.strptime( form_add_method.output_daily_time.data, '%H:%M:%S') add_method_data = MethodData() add_method_data.method_id = form_add_method.method_id.data if method.method_type == 'Date': if form_add_method.method_select.data == 'setpoint': add_method_data.time_start = start_time.strftime( '%Y-%m-%d %H:%M:%S') add_method_data.time_end = end_time.strftime( '%Y-%m-%d %H:%M:%S') if form_add_method.method_select.data == 'output': add_method_data.time_start = form_add_method.output_time.data elif method.method_type == 'Daily': if form_add_method.method_select.data == 'setpoint': add_method_data.time_start = start_time.strftime('%H:%M:%S') add_method_data.time_end = end_time.strftime('%H:%M:%S') if form_add_method.method_select.data == 'output': add_method_data.time_start = form_add_method.output_daily_time.data elif method.method_type == 'Duration': if form_add_method.restart.data: add_method_data.duration_sec = 0 add_method_data.duration_end = form_add_method.duration_end.data else: add_method_data.duration_sec = form_add_method.duration.data if form_add_method.method_select.data == 'setpoint': add_method_data.setpoint_start = form_add_method.setpoint_start.data add_method_data.setpoint_end = form_add_method.setpoint_end.data elif form_add_method.method_select.data == 'output': add_method_data.output_id = form_add_method.output_id.data add_method_data.output_state = form_add_method.output_state.data add_method_data.output_duration = form_add_method.output_duration.data db.session.add(add_method_data) db.session.commit() # Add line to method data list if not a output duration if form_add_method.method_select.data != 'output': method.method_order = add_display_order( display_order, add_method_data.unique_id) db.session.commit() if form_add_method.method_select.data == 'setpoint': if method.method_type == 'Date': flash(gettext("Added duration to method from %(st)s to " "%(end)s", st=start_time, end=end_time), "success") elif method.method_type == 'Daily': flash(gettext("Added duration to method from %(st)s to " "%(end)s", st=start_time.strftime('%H:%M:%S'), end=end_time.strftime('%H:%M:%S')), "success") elif method.method_type == 'Duration': if form_add_method.restart.data: flash(gettext("Added method restart"), "success") else: flash(gettext("Added duration to method for %(sec)s seconds", sec=form_add_method.duration.data), "success") elif form_add_method.method_select.data == 'output': if method.method_type == 'Date': flash(gettext("Added output modulation to method at start " "time: %(tm)s", tm=start_time), "success") elif method.method_type == 'Daily': flash(gettext("Added output modulation to method at start " "time: %(tm)s", tm=start_time.strftime('%H:%M:%S')), "success") elif method.method_type == 'Duration': flash(gettext("Added output modulation to method at start " "time: %(tm)s", tm=form_add_method.duration.data), "success") except Exception as except_msg: logger.exception(1) error.append(except_msg) flash_success_errors(error, action, url_for('routes_method.method_list'))
def output_add(form_add): action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['output']['title']) error = [] dep_unmet, _ = return_dependencies(form_add.output_type.data) if dep_unmet: list_unmet_deps = [] for each_dep in dep_unmet: list_unmet_deps.append(each_dep[0]) error.append( "The {dev} device you're trying to add has unmet dependencies: " "{dep}".format(dev=form_add.output_type.data, dep=', '.join(list_unmet_deps))) if len(form_add.output_type.data.split(',')) < 2: error.append("Must select an Output type") if not is_int(form_add.output_quantity.data, check_range=[1, 20]): error.append("{error}. {accepted_values}: 1-20".format( error=gettext("Invalid quantity"), accepted_values=gettext("Acceptable values"))) if not error: for _ in range(0, form_add.output_quantity.data): try: output_type = form_add.output_type.data.split(',')[0] interface = form_add.output_type.data.split(',')[1] new_output = Output() new_output.name = str(OUTPUT_INFO[output_type]['name']) new_output.output_type = output_type new_output.interface = interface if output_type in [ 'wired', 'wireless_rpi_rf', 'command', 'python' ]: new_output.measurement = 'duration_time' new_output.unit = 's' elif output_type in ['command_pwm', 'pwm', 'python_pwm']: new_output.measurement = 'duty_cycle' new_output.unit = 'percent' elif output_type == 'atlas_ezo_pmp': new_output.measurement = 'volume' new_output.unit = 'ml' new_output.channel = 0 if output_type == 'wired': new_output.on_at_start = False elif output_type == 'wireless_rpi_rf': new_output.pin = None new_output.protocol = 1 new_output.pulse_length = 189 new_output.on_command = '22559' new_output.off_command = '22558' elif output_type == 'command': new_output.on_command = '/home/pi/script_on.sh' new_output.off_command = '/home/pi/script_off.sh' elif output_type == 'command_pwm': new_output.pwm_command = '/home/pi/script_pwm.sh ((duty_cycle))' elif output_type == 'pwm': new_output.pwm_hertz = 22000 new_output.pwm_library = 'pigpio_any' elif output_type == 'python': new_output.on_command = """ timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") write_string = "{ts}: ID: {id}: ON\\n".format(id=output_id, ts=timestamp) with open("/home/pi/Mycodo/OutputTest.txt", "a") as myfile: myfile.write(write_string)""" new_output.off_command = """ timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") write_string = "{ts}: ID: {id}: OFF\\n".format(id=output_id, ts=timestamp) with open("/home/pi/Mycodo/OutputTest.txt", "a") as myfile: myfile.write(write_string)""" elif output_type == 'python_pwm': new_output.pwm_command = """ timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") write_string = "{ts}: ID: {id}: Duty Cycle: ((duty_cycle)) %\\n".format( id=output_id, ts=timestamp) with open("/home/pi/Mycodo/OutputTest.txt", "a") as myfile: myfile.write(write_string)""" elif output_type == 'atlas_ezo_pmp': new_output.flow_rate = 10 if interface == 'I2C': new_output.location = '0x67' new_output.i2c_bus = 1 elif interface == 'UART': new_output.location = '/dev/ttyAMA0' new_output.baud_rate = 9600 if not error: new_output.save() display_order = csv_to_list_of_str( DisplayOrder.query.first().output) DisplayOrder.query.first().output = add_display_order( display_order, new_output.unique_id) db.session.commit() manipulate_output('Add', new_output.unique_id) except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_output')) if dep_unmet: return 1
def method_mod(form_mod_method): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['method']['title']) error = [] method = Method.query.filter( Method.unique_id == form_mod_method.method_id.data).first() method_data = MethodData.query.filter( MethodData.unique_id == form_mod_method.method_data_id.data).first() display_order = csv_to_list_of_str(method.method_order) try: if form_mod_method.delete.data: delete_entry_with_id(MethodData, form_mod_method.method_data_id.data) if form_mod_method.method_select.data != 'output': method_order = Method.query.filter( Method.unique_id == method.unique_id).first() display_order = csv_to_list_of_str(method_order.method_order) display_order.remove(method_data.unique_id) method_order.method_order = list_to_csv(display_order) db.session.commit() return 0 if form_mod_method.rename.data: method.name = form_mod_method.name.data db.session.commit() return 0 # Ensure data is valid if validate_method_data(form_mod_method, method): return 1 if form_mod_method.method_select.data == 'setpoint': if method.method_type == 'Date': start_time = datetime.strptime(form_mod_method.time_start.data, '%Y-%m-%d %H:%M:%S') end_time = datetime.strptime(form_mod_method.time_end.data, '%Y-%m-%d %H:%M:%S') # Ensure the start time comes after the previous entry's end time # and the end time comes before the next entry's start time # method_id_set is the id given to all method entries, 'method_id', not 'id' previous_method = None next_method = None for index, each_order in enumerate(display_order): if each_order == method_data.unique_id: if len(display_order) > 1 and index > 0: previous_method = MethodData.query.filter( MethodData.unique_id == display_order[index-1]).first() if len(display_order) > index+1: next_method = MethodData.query.filter( MethodData.unique_id == display_order[index+1]).first() if previous_method is not None and previous_method.time_end is not None: previous_end_time = datetime.strptime( previous_method.time_end, '%Y-%m-%d %H:%M:%S') if previous_end_time is not None and start_time < previous_end_time: error.append( gettext("The entry start time (%(st)s) cannot " "overlap the previous entry's end time " "(%(et)s)", st=start_time, et=previous_end_time)) if next_method is not None and next_method.time_start is not None: next_start_time = datetime.strptime( next_method.time_start, '%Y-%m-%d %H:%M:%S') if next_start_time is not None and end_time > next_start_time: error.append( gettext("The entry end time (%(et)s) cannot " "overlap the next entry's start time " "(%(st)s)", et=end_time, st=next_start_time)) method_data.time_start = start_time.strftime('%Y-%m-%d %H:%M:%S') method_data.time_end = end_time.strftime('%Y-%m-%d %H:%M:%S') elif method.method_type == 'Duration': if method_data.duration_sec == 0: method_data.duration_end = form_mod_method.duration_end.data else: method_data.duration_sec = form_mod_method.duration.data elif method.method_type == 'Daily': method_data.time_start = form_mod_method.daily_time_start.data method_data.time_end = form_mod_method.daily_time_end.data method_data.setpoint_start = form_mod_method.setpoint_start.data method_data.setpoint_end = form_mod_method.setpoint_end.data elif form_mod_method.method_select.data == 'output': if method.method_type == 'Date': method_data.time_start = form_mod_method.output_time.data elif method.method_type == 'Duration': method_data.duration_sec = form_mod_method.duration.data if form_mod_method.output_id.data == '': method_data.output_id = None else: method_data.output_id = form_mod_method.output_id.data method_data.output_state = form_mod_method.output_state.data method_data.output_duration = form_mod_method.output_duration.data elif method.method_type == 'DailySine': if form_mod_method.method_select.data == 'output': method_data.time_start = form_mod_method.output_time.data if form_mod_method.output_id.data == '': method_data.output_id = None else: method_data.output_id = form_mod_method.output_id.data method_data.output_state = form_mod_method.output_state.data method_data.output_duration = form_mod_method.output_duration.data if not error: db.session.commit() except Exception as except_msg: logger.exception(1) error.append(except_msg) flash_success_errors(error, action, url_for('routes_method.method_list'))
def dashboard_add(form_base, form_object, display_order): """ Add an item to the dashboard Either Graph, Gauge, or Camera """ action = '{action} {controller}'.format(action=gettext("Add"), controller=gettext("Dashboard")) error = [] dashboard_type = '' new_graph = Dashboard() new_graph.name = form_base.name.data # Graph if (form_base.dashboard_type.data == 'graph' and (form_base.name.data and form_base.width.data and form_base.height.data and form_object.xaxis_duration.data and form_base.refresh_duration.data)): dashboard_type = 'Graph' error = graph_error_check(form_object, error) new_graph.graph_type = form_base.dashboard_type.data if form_object.math_ids.data: math_ids_joined = ";".join(form_object.math_ids.data) new_graph.math_ids = math_ids_joined if form_object.pid_ids.data: pid_ids_joined = ";".join(form_object.pid_ids.data) new_graph.pid_ids = pid_ids_joined if form_object.output_ids.data: output_ids_joined = ";".join(form_object.output_ids.data) new_graph.output_ids = output_ids_joined if form_object.input_ids.data: input_ids_joined = ";".join(form_object.input_ids.data) new_graph.input_ids_measurements = input_ids_joined new_graph.width = form_base.width.data new_graph.height = form_base.height.data new_graph.x_axis_duration = form_object.xaxis_duration.data new_graph.refresh_duration = form_base.refresh_duration.data new_graph.enable_auto_refresh = form_object.enable_auto_refresh.data new_graph.enable_xaxis_reset = form_object.enable_xaxis_reset.data new_graph.enable_title = form_object.enable_title.data new_graph.enable_navbar = form_object.enable_navbar.data new_graph.enable_rangeselect = form_object.enable_range.data new_graph.enable_export = form_object.enable_export.data new_graph.enable_graph_shift = form_object.enable_graph_shift.data new_graph.enable_manual_y_axis = form_object.enable_manual_y_axis.data # Gauge elif form_base.dashboard_type.data == 'gauge': dashboard_type = 'Gauge' error = gauge_error_check(form_object, error) new_graph.graph_type = form_object.gauge_type.data if form_object.gauge_type.data == 'gauge_solid': new_graph.range_colors = '20,#33CCFF;40,#55BF3B;60,#DDDF0D;80,#DF5353' elif form_object.gauge_type.data == 'gauge_angular': new_graph.range_colors = '0,25,#33CCFF;25,50,#55BF3B;50,75,#DDDF0D;75,100,#DF5353' new_graph.width = form_base.width.data new_graph.height = form_base.height.data new_graph.max_measure_age = form_object.max_measure_age.data new_graph.refresh_duration = form_base.refresh_duration.data new_graph.y_axis_min = form_object.y_axis_min.data new_graph.y_axis_max = form_object.y_axis_max.data new_graph.input_ids_measurements = form_object.input_ids.data new_graph.enable_timestamp = form_object.enable_timestamp.data # Measurement elif form_base.dashboard_type.data == 'measurement': dashboard_type = 'Measurement' error = measurement_error_check(form_object, error) new_graph.graph_type = 'measurement' new_graph.width = form_base.width.data new_graph.height = form_base.height.data new_graph.max_measure_age = form_object.max_measure_age.data new_graph.refresh_duration = form_base.refresh_duration.data new_graph.font_em_value = form_object.font_em_value.data new_graph.font_em_timestamp = form_object.font_em_timestamp.data new_graph.decimal_places = form_object.decimal_places.data new_graph.input_ids_measurements = form_object.measurement_id.data # Output elif form_base.dashboard_type.data == 'output': dashboard_type = 'Output' error = output_error_check(form_object, error) new_graph.graph_type = 'output' new_graph.width = form_base.width.data new_graph.height = form_base.height.data new_graph.max_measure_age = form_object.max_measure_age.data new_graph.refresh_duration = form_base.refresh_duration.data new_graph.font_em_value = form_object.font_em_value.data new_graph.font_em_timestamp = form_object.font_em_timestamp.data new_graph.enable_output_controls = form_object.enable_output_controls.data new_graph.decimal_places = form_object.decimal_places.data new_graph.output_ids = form_object.output_id.data # PID Control elif form_base.dashboard_type.data == 'pid_control': dashboard_type = 'PID Control' error = pid_error_check(form_object, error) new_graph.graph_type = 'pid_control' new_graph.width = form_base.width.data new_graph.height = form_base.height.data new_graph.max_measure_age = form_object.max_measure_age.data new_graph.refresh_duration = form_base.refresh_duration.data new_graph.font_em_value = form_object.font_em_value.data new_graph.font_em_timestamp = form_object.font_em_timestamp.data new_graph.decimal_places = form_object.decimal_places.data new_graph.show_pid_info = form_object.show_pid_info.data new_graph.show_set_setpoint = form_object.show_set_setpoint.data new_graph.pid_ids = form_object.pid_id.data # Camera elif (form_base.dashboard_type.data == 'camera' and form_object.camera_id.data): dashboard_type = 'Camera' new_graph.graph_type = form_base.dashboard_type.data new_graph.width = form_base.width.data new_graph.height = form_base.height.data new_graph.refresh_duration = form_base.refresh_duration.data new_graph.camera_max_age = form_object.camera_max_age.data new_graph.camera_id = form_object.camera_id.data new_graph.camera_image_type = form_object.camera_image_type.data else: flash_form_errors(form_base) return try: if not error: new_graph.save() flash( gettext("{dev} with ID %(id)s successfully added".format( dev=dashboard_type), id=new_graph.id), "success") DisplayOrder.query.first().dashboard = add_display_order( display_order, new_graph.unique_id) db.session.commit() except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_dashboard'))
def method_create(form_create_method): """ Create new method table entry (all data stored in method_data table) """ action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['method']['title']) error = [] try: # Create method new_method = Method() new_method.name = form_create_method.name.data new_method.method_type = form_create_method.method_type.data db.session.add(new_method) db.session.commit() # Add new method line id to method display order method_order = DisplayOrder.query.first() display_order = csv_to_list_of_str(method_order.method) method_order.method = add_display_order(display_order, new_method.unique_id) db.session.commit() # Add new method data line id to method_data display order if new_method.method_type in ['DailyBezier', 'DailySine']: # For tables that require only one entry to configure, # create that single entry now with default values new_method_data = MethodData() new_method_data.method_id = new_method.unique_id if new_method.method_type == 'DailySine': new_method_data.amplitude = 1.0 new_method_data.frequency = 1.0 new_method_data.shift_angle = 0 new_method_data.shift_y = 1.0 elif new_method.method_type == 'DailyBezier': new_method_data = MethodData() new_method_data.method_id = new_method.unique_id new_method_data.shift_angle = 0.0 new_method_data.x0 = 20.0 new_method_data.y0 = 20.0 new_method_data.x1 = 10.0 new_method_data.y1 = 13.5 new_method_data.x2 = 22.5 new_method_data.y2 = 30.0 new_method_data.x3 = 0.0 new_method_data.y3 = 20.0 db.session.add(new_method_data) db.session.commit() display_order = csv_to_list_of_str(new_method.method_order) method = Method.query.filter( Method.unique_id == new_method.unique_id).first() method.method_order = add_display_order(display_order, new_method_data.unique_id) db.session.commit() return 0 except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_method.method_list'))
def pid_mod(form_mod_pid_base, form_mod_pid_pwm_raise, form_mod_pid_pwm_lower, form_mod_pid_output_raise, form_mod_pid_output_lower): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['pid']['title']) error = [] if not form_mod_pid_base.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_base) mod_pid = PID.query.filter( PID.unique_id == form_mod_pid_base.function_id.data).first() mod_pid.name = form_mod_pid_base.name.data mod_pid.measurement = form_mod_pid_base.measurement.data mod_pid.direction = form_mod_pid_base.direction.data mod_pid.period = form_mod_pid_base.period.data mod_pid.log_level_debug = form_mod_pid_base.log_level_debug.data mod_pid.start_offset = form_mod_pid_base.start_offset.data mod_pid.max_measure_age = form_mod_pid_base.max_measure_age.data mod_pid.setpoint = form_mod_pid_base.setpoint.data mod_pid.band = abs(form_mod_pid_base.band.data) mod_pid.store_lower_as_negative = form_mod_pid_base.store_lower_as_negative.data mod_pid.p = form_mod_pid_base.k_p.data mod_pid.i = form_mod_pid_base.k_i.data mod_pid.d = form_mod_pid_base.k_d.data mod_pid.integrator_min = form_mod_pid_base.integrator_max.data mod_pid.integrator_max = form_mod_pid_base.integrator_min.data mod_pid.setpoint_tracking_type = form_mod_pid_base.setpoint_tracking_type.data if form_mod_pid_base.setpoint_tracking_type.data == 'method': mod_pid.setpoint_tracking_id = form_mod_pid_base.setpoint_tracking_method_id.data elif form_mod_pid_base.setpoint_tracking_type.data == 'input-math': mod_pid.setpoint_tracking_id = form_mod_pid_base.setpoint_tracking_input_math_id.data mod_pid.setpoint_tracking_max_age = form_mod_pid_base.setpoint_tracking_max_age.data else: mod_pid.setpoint_tracking_id = '' # Change measurement information if ',' in form_mod_pid_base.measurement.data: measurement_id = form_mod_pid_base.measurement.data.split(',')[1] selected_measurement = get_measurement(measurement_id) measurements = DeviceMeasurements.query.filter( DeviceMeasurements.device_id == form_mod_pid_base.function_id.data).all() for each_measurement in measurements: # Only set channels 0, 1, 2 if each_measurement.channel in [0, 1, 2]: each_measurement.measurement = selected_measurement.measurement each_measurement.unit = selected_measurement.unit if form_mod_pid_base.raise_output_id.data: raise_output_type = Output.query.filter( Output.unique_id == form_mod_pid_base.raise_output_id.data).first().output_type if mod_pid.raise_output_id == form_mod_pid_base.raise_output_id.data: if raise_output_type in OUTPUTS_PWM: if not form_mod_pid_pwm_raise.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_pwm_raise) else: mod_pid.raise_min_duration = form_mod_pid_pwm_raise.raise_min_duty_cycle.data mod_pid.raise_max_duration = form_mod_pid_pwm_raise.raise_max_duty_cycle.data else: if not form_mod_pid_output_raise.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_output_raise) else: mod_pid.raise_min_duration = form_mod_pid_output_raise.raise_min_duration.data mod_pid.raise_max_duration = form_mod_pid_output_raise.raise_max_duration.data mod_pid.raise_min_off_duration = form_mod_pid_output_raise.raise_min_off_duration.data else: if raise_output_type in OUTPUTS_PWM: mod_pid.raise_min_duration = 2 mod_pid.raise_max_duration = 98 else: mod_pid.raise_min_duration = 0 mod_pid.raise_max_duration = 0 mod_pid.raise_min_off_duration = 0 mod_pid.raise_output_id = form_mod_pid_base.raise_output_id.data else: mod_pid.raise_output_id = None if form_mod_pid_base.lower_output_id.data: lower_output_type = Output.query.filter( Output.unique_id == form_mod_pid_base.lower_output_id.data).first().output_type if mod_pid.lower_output_id == form_mod_pid_base.lower_output_id.data: if lower_output_type in OUTPUTS_PWM: if not form_mod_pid_pwm_lower.validate(): error.append(gettext("Error in form field(s)")) flash_form_errors(form_mod_pid_pwm_lower) else: mod_pid.lower_min_duration = form_mod_pid_pwm_lower.lower_min_duty_cycle.data mod_pid.lower_max_duration = form_mod_pid_pwm_lower.lower_max_duty_cycle.data else: if not form_mod_pid_output_lower.validate(): error.append(gettext("Error in form field(s)")) flash_form_errors(form_mod_pid_output_lower) else: mod_pid.lower_min_duration = form_mod_pid_output_lower.lower_min_duration.data mod_pid.lower_max_duration = form_mod_pid_output_lower.lower_max_duration.data mod_pid.lower_min_off_duration = form_mod_pid_output_lower.lower_min_off_duration.data else: if lower_output_type in OUTPUTS_PWM: mod_pid.lower_min_duration = 2 mod_pid.lower_max_duration = 98 else: mod_pid.lower_min_duration = 0 mod_pid.lower_max_duration = 0 mod_pid.lower_min_off_duration = 0 mod_pid.lower_output_id = form_mod_pid_base.lower_output_id.data else: mod_pid.lower_output_id = None if (mod_pid.raise_output_id and mod_pid.lower_output_id and mod_pid.raise_output_id == mod_pid.lower_output_id): error.append(gettext("Raise and lower outputs cannot be the same")) try: if not error: db.session.commit() # If the controller is active or paused, refresh variables in thread if mod_pid.is_activated: control = DaemonControl() return_value = control.pid_mod(form_mod_pid_base.function_id.data) flash("PID Controller settings refresh response: " "{resp}".format(resp=return_value), "success") except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def lcd_activate(lcd_id): action = '{action} {controller}'.format( action=TRANSLATIONS['activate']['title'], controller=TRANSLATIONS['lcd']['title']) error = [] try: # All display lines must be filled to activate display lcd = LCD.query.filter(LCD.unique_id == lcd_id).first() lcd_data = LCDData.query.filter(LCDData.lcd_id == lcd_id).all() blank_line_detected = False for each_lcd_data in lcd_data: if ( (lcd.y_lines in [2, 4, 8] and (not each_lcd_data.line_1_id or not each_lcd_data.line_2_id) ) or (lcd.y_lines in [4, 8] and (not each_lcd_data.line_3_id or not each_lcd_data.line_4_id) ) or (lcd.y_lines == 8 and (not each_lcd_data.line_5_id or not each_lcd_data.line_6_id or not each_lcd_data.line_7_id or not each_lcd_data.line_8_id)) ): blank_line_detected = True def check_display_set(error, display_num, measurement, max_age, decimal_places): if measurement not in ["BLANK", "IP", "TEXT"]: if max_age is None: error.append( "Display Set {n}: {set}: {opt}".format( n=display_num, set=gettext("Must be set"), opt=TRANSLATIONS['max_age']['title'])) if decimal_places is None: error.append("Display Set {n}: {set}: {opt}".format( n=display_num, set=gettext("Must be set"), opt=gettext("Decimal Places"))) return error for each_lcd_data in lcd_data: if lcd.y_lines in [2, 4, 8]: error = check_display_set( error, 1, each_lcd_data.line_1_measurement, each_lcd_data.line_1_max_age, each_lcd_data.line_1_decimal_places) error = check_display_set( error, 2, each_lcd_data.line_2_measurement, each_lcd_data.line_2_max_age, each_lcd_data.line_2_decimal_places) if lcd.y_lines in [4, 8]: error = check_display_set( error, 3, each_lcd_data.line_3_measurement, each_lcd_data.line_3_max_age, each_lcd_data.line_3_decimal_places) error = check_display_set( error, 4, each_lcd_data.line_4_measurement, each_lcd_data.line_4_max_age, each_lcd_data.line_4_decimal_places) if lcd.y_lines == 8: error = check_display_set( error, 5, each_lcd_data.line_5_measurement, each_lcd_data.line_5_max_age, each_lcd_data.line_5_decimal_places) error = check_display_set( error, 6, each_lcd_data.line_6_measurement, each_lcd_data.line_6_max_age, each_lcd_data.line_6_decimal_places) error = check_display_set( error, 7, each_lcd_data.line_7_measurement, each_lcd_data.line_7_max_age, each_lcd_data.line_7_decimal_places) error = check_display_set( error, 8, each_lcd_data.line_8_measurement, each_lcd_data.line_8_max_age, each_lcd_data.line_8_decimal_places) if blank_line_detected: error.append(gettext( 'Detected at least one "Line" unset. Cannot activate LCD if there are unconfigured lines.')) if not error: controller_activate_deactivate('activate', 'LCD', lcd_id) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_lcd'))
def input_add(form_add): action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['input']['title']) error = [] dict_inputs = parse_input_information() # only one comma should be in the input_type string if form_add.input_type.data.count(',') > 1: error.append("Invalid input module formatting. It appears there is " "a comma in either 'input_name_unique' or 'interfaces'.") if form_add.input_type.data.count(',') == 1: input_name = form_add.input_type.data.split(',')[0] input_interface = form_add.input_type.data.split(',')[1] else: input_name = '' input_interface = '' error.append("Invalid input string (must be a comma-separated string)") if current_app.config['TESTING']: dep_unmet = False else: dep_unmet, _ = return_dependencies(input_name) if dep_unmet: list_unmet_deps = [] for each_dep in dep_unmet: list_unmet_deps.append(each_dep[0]) error.append("The {dev} device you're trying to add has unmet dependencies: {dep}".format( dev=input_name, dep=', '.join(list_unmet_deps))) if form_add.validate(): new_input = Input() new_input.device = input_name if input_interface: new_input.interface = input_interface try: from RPi import GPIO if GPIO.RPI_INFO['P1_REVISION'] == 1: new_input.i2c_bus = 0 else: new_input.i2c_bus = 1 except: logger.error( "RPi.GPIO and Raspberry Pi required for this action") if 'input_name' in dict_inputs[input_name]: new_input.name = dict_inputs[input_name]['input_name'] else: new_input.name = 'Name' # # Set default values for new input being added # # input add options if input_name in dict_inputs: def dict_has_value(key): if (key in dict_inputs[input_name] and (dict_inputs[input_name][key] or dict_inputs[input_name][key] == 0)): return True # # Interfacing options # if input_interface == 'I2C': if dict_has_value('i2c_location'): new_input.i2c_location = dict_inputs[input_name]['i2c_location'][0] # First entry in list if input_interface == 'FTDI': if dict_has_value('ftdi_location'): new_input.ftdi_location = dict_inputs[input_name]['ftdi_location'] if input_interface == 'UART': if dict_has_value('uart_location'): new_input.uart_location = dict_inputs[input_name]['uart_location'] # UART options if dict_has_value('uart_baud_rate'): new_input.baud_rate = dict_inputs[input_name]['uart_baud_rate'] if dict_has_value('pin_cs'): new_input.pin_cs = dict_inputs[input_name]['pin_cs'] if dict_has_value('pin_miso'): new_input.pin_miso = dict_inputs[input_name]['pin_miso'] if dict_has_value('pin_mosi'): new_input.pin_mosi = dict_inputs[input_name]['pin_mosi'] if dict_has_value('pin_clock'): new_input.pin_clock = dict_inputs[input_name]['pin_clock'] # Bluetooth (BT) options elif input_interface == 'BT': if dict_has_value('bt_location'): if not re.match("[0-9a-fA-F]{2}([:]?)[0-9a-fA-F]{2}(\\1[0-9a-fA-F]{2}){4}$", dict_inputs[input_name]['bt_location']): error.append("Please specify device MAC-Address in format AA:BB:CC:DD:EE:FF") else: new_input.location = dict_inputs[input_name]['bt_location'] if dict_has_value('bt_adapter'): new_input.bt_adapter = dict_inputs[input_name]['bt_adapter'] # GPIO options elif input_interface == 'GPIO': if dict_has_value('gpio_location'): new_input.gpio_location = dict_inputs[input_name]['gpio_location'] # Custom location location elif dict_has_value('location'): new_input.location = dict_inputs[input_name]['location']['options'][0][0] # First entry in list # # General options # if dict_has_value('period'): new_input.period = dict_inputs[input_name]['period'] # Server Ping options if dict_has_value('times_check'): new_input.times_check = dict_inputs[input_name]['times_check'] if dict_has_value('deadline'): new_input.deadline = dict_inputs[input_name]['deadline'] if dict_has_value('port'): new_input.port = dict_inputs[input_name]['port'] # Signal options if dict_has_value('weighting'): new_input.weighting = dict_inputs[input_name]['weighting'] if dict_has_value('sample_time'): new_input.sample_time = dict_inputs[input_name]['sample_time'] # Analog-to-digital converter options if dict_has_value('adc_gain'): if len(dict_inputs[input_name]['adc_gain']) == 1: new_input.adc_gain = dict_inputs[input_name]['adc_gain'][0] elif len(dict_inputs[input_name]['adc_gain']) > 1: new_input.adc_gain = dict_inputs[input_name]['adc_gain'][0][0] if dict_has_value('adc_resolution'): if len(dict_inputs[input_name]['adc_resolution']) == 1: new_input.adc_resolution = dict_inputs[input_name]['adc_resolution'][0] elif len(dict_inputs[input_name]['adc_resolution']) > 1: new_input.adc_resolution = dict_inputs[input_name]['adc_resolution'][0][0] if dict_has_value('adc_sample_speed'): if len(dict_inputs[input_name]['adc_sample_speed']) == 1: new_input.adc_sample_speed = dict_inputs[input_name]['adc_sample_speed'][0] elif len(dict_inputs[input_name]['adc_sample_speed']) > 1: new_input.adc_sample_speed = dict_inputs[input_name]['adc_sample_speed'][0][0] # Linux command if dict_has_value('cmd_command'): new_input.cmd_command = dict_inputs[input_name]['cmd_command'] # Misc options if dict_has_value('resolution'): if len(dict_inputs[input_name]['resolution']) == 1: new_input.resolution = dict_inputs[input_name]['resolution'][0] elif len(dict_inputs[input_name]['resolution']) > 1: new_input.resolution = dict_inputs[input_name]['resolution'][0][0] if dict_has_value('resolution_2'): if len(dict_inputs[input_name]['resolution_2']) == 1: new_input.resolution_2 = dict_inputs[input_name]['resolution_2'][0] elif len(dict_inputs[input_name]['resolution_2']) > 1: new_input.resolution_2 = dict_inputs[input_name]['resolution_2'][0][0] if dict_has_value('sensitivity'): if len(dict_inputs[input_name]['sensitivity']) == 1: new_input.sensitivity = dict_inputs[input_name]['sensitivity'][0] elif len(dict_inputs[input_name]['sensitivity']) > 1: new_input.sensitivity = dict_inputs[input_name]['sensitivity'][0][0] if dict_has_value('thermocouple_type'): if len(dict_inputs[input_name]['thermocouple_type']) == 1: new_input.thermocouple_type = dict_inputs[input_name]['thermocouple_type'][0] elif len(dict_inputs[input_name]['thermocouple_type']) > 1: new_input.thermocouple_type = dict_inputs[input_name]['thermocouple_type'][0][0] if dict_has_value('sht_voltage'): if len(dict_inputs[input_name]['sht_voltage']) == 1: new_input.sht_voltage = dict_inputs[input_name]['sht_voltage'][0] elif len(dict_inputs[input_name]['sht_voltage']) > 1: new_input.sht_voltage = dict_inputs[input_name]['sht_voltage'][0][0] if dict_has_value('ref_ohm'): new_input.ref_ohm = dict_inputs[input_name]['ref_ohm'] # # Custom Options # # Generate string to save from custom options error, custom_options = custom_options_return_json( error, dict_inputs, device=input_name, use_defaults=True) new_input.custom_options = custom_options # # Execute at Creation # new_input.unique_id = set_uuid() if ('execute_at_creation' in dict_inputs[new_input.device] and not current_app.config['TESTING']): error, new_input = dict_inputs[new_input.device]['execute_at_creation']( error, new_input, dict_inputs[new_input.device]) try: if not error: new_input.save() display_order = csv_to_list_of_str( DisplayOrder.query.first().inputs) DisplayOrder.query.first().inputs = add_display_order( display_order, new_input.unique_id) db.session.commit() # # If there are a variable number of measurements # if ('measurements_variable_amount' in dict_inputs[input_name] and dict_inputs[input_name]['measurements_variable_amount']): # Add first default measurement with empty unit and measurement new_measurement = DeviceMeasurements() new_measurement.name = "" new_measurement.device_id = new_input.unique_id new_measurement.measurement = "" new_measurement.unit = "" new_measurement.channel = 0 new_measurement.save() # # If measurements defined in the Input Module # elif ('measurements_dict' in dict_inputs[input_name] and dict_inputs[input_name]['measurements_dict']): for each_channel in dict_inputs[input_name]['measurements_dict']: measure_info = dict_inputs[input_name]['measurements_dict'][each_channel] new_measurement = DeviceMeasurements() if 'name' in measure_info: new_measurement.name = measure_info['name'] new_measurement.device_id = new_input.unique_id new_measurement.measurement = measure_info['measurement'] new_measurement.unit = measure_info['unit'] new_measurement.channel = each_channel new_measurement.save() if 'channels_dict' in dict_inputs[new_input.device]: for each_channel, channel_info in dict_inputs[new_input.device]['channels_dict'].items(): new_channel = InputChannel() new_channel.channel = each_channel new_channel.input_id = new_input.unique_id # Generate string to save from custom options error, custom_options = custom_channel_options_return_json( error, dict_inputs, None, new_input.unique_id, each_channel, device=new_input.device, use_defaults=True) new_channel.custom_options = custom_options new_channel.save() flash(gettext( "%(type)s Input with ID %(id)s (%(uuid)s) successfully added", type=input_name, id=new_input.id, uuid=new_input.unique_id), "success") except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_input')) else: flash_form_errors(form_add) if dep_unmet: return 1
def output_mod(form_output, request_form): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['output']['title']) error = [] dict_outputs = parse_output_information() try: channels = OutputChannel.query.filter( OutputChannel.output_id == form_output.output_id.data).all() mod_output = Output.query.filter( Output.unique_id == form_output.output_id.data).first() if (form_output.uart_location.data and not os.path.exists(form_output.uart_location.data)): error.append( gettext( "Invalid device or improper permissions to read device")) mod_output.name = form_output.name.data if form_output.location.data: mod_output.location = form_output.location.data if form_output.i2c_location.data: mod_output.i2c_location = form_output.i2c_location.data if form_output.ftdi_location.data: mod_output.ftdi_location = form_output.ftdi_location.data if form_output.uart_location.data: mod_output.uart_location = form_output.uart_location.data if form_output.gpio_location.data: if not is_int(form_output.gpio_location.data): error.append("BCM GPIO Pin must be an integer") else: mod_output.pin = form_output.gpio_location.data if form_output.i2c_bus.data is not None: mod_output.i2c_bus = form_output.i2c_bus.data if form_output.baud_rate.data: mod_output.baud_rate = form_output.baud_rate.data mod_output.log_level_debug = form_output.log_level_debug.data # Parse pre-save custom options for output device and its channels try: custom_options_dict_presave = json.loads(mod_output.custom_options) except: logger.error("Malformed JSON") custom_options_dict_presave = {} custom_options_channels_dict_presave = {} for each_channel in channels: if each_channel.custom_options and each_channel.custom_options != "{}": custom_options_channels_dict_presave[ each_channel.channel] = json.loads( each_channel.custom_options) else: custom_options_channels_dict_presave[each_channel.channel] = {} # Parse post-save custom options for output device and its channels error, custom_options_json_postsave = custom_options_return_json( error, dict_outputs, request_form, device=mod_output.output_type) custom_options_dict_postsave = json.loads(custom_options_json_postsave) custom_options_channels_dict_postsave = {} for each_channel in channels: error, custom_options_channels_json_postsave_tmp = custom_channel_options_return_json( error, dict_outputs, request_form, form_output.output_id.data, each_channel.channel, device=mod_output.output_type, use_defaults=True) custom_options_channels_dict_postsave[ each_channel.channel] = json.loads( custom_options_channels_json_postsave_tmp) if 'execute_at_modification' in dict_outputs[mod_output.output_type]: # pass custom options to module prior to saving to database (allow_saving, mod_output, custom_options_dict, custom_options_channels_dict) = dict_outputs[ mod_output.output_type]['execute_at_modification']( mod_output, request_form, custom_options_dict_presave, custom_options_channels_dict_presave, custom_options_dict_postsave, custom_options_channels_dict_postsave) custom_options = json.dumps( custom_options_dict) # Convert from dict to JSON string custom_channel_options = custom_options_channels_dict if not allow_saving: error.append( "execute_at_modification() would not allow output options to be saved" ) else: # Don't pass custom options to module custom_options = json.dumps(custom_options_dict_postsave) custom_channel_options = custom_options_channels_dict_postsave # Finally, save custom options for both output and channels mod_output.custom_options = custom_options for each_channel in channels: if 'name' in custom_channel_options[each_channel.channel]: each_channel.name = custom_channel_options[ each_channel.channel]['name'] each_channel.custom_options = json.dumps( custom_channel_options[each_channel.channel]) if not error: db.session.commit() manipulate_output('Modify', form_output.output_id.data) except Exception as except_msg: logger.exception(1) error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_output'))
def output_add(form_add): action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['output']['title']) error = [] dict_outputs = parse_output_information() output_types_dict = output_types() # only one comma should be in the output_type string if form_add.output_type.data.count(',') > 1: error.append("Invalid output module formatting. It appears there is " "a comma in either 'output_name_unique' or 'interfaces'.") if form_add.output_type.data.count(',') == 1: output_type = form_add.output_type.data.split(',')[0] output_interface = form_add.output_type.data.split(',')[1] else: output_type = '' output_interface = '' error.append("Invalid output string (must be a comma-separated string)") if current_app.config['TESTING']: dep_unmet = False else: dep_unmet, _ = return_dependencies(form_add.output_type.data.split(',')[0]) if dep_unmet: list_unmet_deps = [] for each_dep in dep_unmet: list_unmet_deps.append(each_dep[0]) error.append( "The {dev} device you're trying to add has unmet dependencies: " "{dep}".format(dev=form_add.output_type.data, dep=', '.join(list_unmet_deps))) if not is_int(form_add.output_quantity.data, check_range=[1, 20]): error.append("{error}. {accepted_values}: 1-20".format( error=gettext("Invalid quantity"), accepted_values=gettext("Acceptable values") )) if not error: for _ in range(0, form_add.output_quantity.data): try: new_output = Output() try: from RPi import GPIO if GPIO.RPI_INFO['P1_REVISION'] == 1: new_output.i2c_bus = 0 else: new_output.i2c_bus = 1 except: logger.error( "RPi.GPIO and Raspberry Pi required for this action") new_output.name = "Name" new_output.output_type = output_type new_output.interface = output_interface # # Set default values for new input being added # # input add options if output_type in dict_outputs: def dict_has_value(key): if (key in dict_outputs[output_type] and dict_outputs[output_type][key] is not None): return True # # Interfacing options # if output_interface == 'I2C': if dict_has_value('i2c_address_default'): new_output.i2c_location = dict_outputs[output_type]['i2c_address_default'] elif dict_has_value('i2c_location'): new_output.i2c_location = dict_outputs[output_type]['i2c_location'][0] # First list entry if output_interface == 'FTDI': if dict_has_value('ftdi_location'): new_output.ftdi_location = dict_outputs[output_type]['ftdi_location'] if output_interface == 'UART': if dict_has_value('uart_location'): new_output.uart_location = dict_outputs[output_type]['uart_location'] # UART options if dict_has_value('uart_baud_rate'): new_output.baud_rate = dict_outputs[output_type]['uart_baud_rate'] if dict_has_value('pin_cs'): new_output.pin_cs = dict_outputs[output_type]['pin_cs'] if dict_has_value('pin_miso'): new_output.pin_miso = dict_outputs[output_type]['pin_miso'] if dict_has_value('pin_mosi'): new_output.pin_mosi = dict_outputs[output_type]['pin_mosi'] if dict_has_value('pin_clock'): new_output.pin_clock = dict_outputs[output_type]['pin_clock'] # Bluetooth (BT) options elif output_interface == 'BT': if dict_has_value('bt_location'): new_output.location = dict_outputs[output_type]['bt_location'] if dict_has_value('bt_adapter'): new_output.bt_adapter = dict_outputs[output_type]['bt_adapter'] # GPIO options elif output_interface == 'GPIO': if dict_has_value('gpio_pin'): new_output.pin = dict_outputs[output_type]['gpio_pin'] # Custom location location elif dict_has_value('location'): new_output.location = dict_outputs[output_type]['location']['options'][0][0] # First entry in list # # Custom Options # list_options = [] if 'custom_options' in dict_outputs[output_type]: for each_option in dict_outputs[output_type]['custom_options']: if each_option['default_value'] is False: default_value = '' else: default_value = each_option['default_value'] option = '{id},{value}'.format( id=each_option['id'], value=default_value) list_options.append(option) new_output.custom_options = ';'.join(list_options) if output_type in output_types_dict['pwm']: new_output.pwm_hertz = 22000 new_output.pwm_library = 'pigpio_any' if output_type in output_types_dict['volume']: new_output.output_mode = 'fastest_flow_rate' new_output.flow_rate = 10 if output_type == 'atlas_ezo_pmp': if output_interface == 'FTDI': new_output.location = '/dev/ttyUSB0' elif output_interface == 'I2C': new_output.location = '0x67' new_output.i2c_bus = 1 elif output_interface == 'UART': new_output.location = '/dev/ttyAMA0' new_output.baud_rate = 9600 if output_type == 'wired': new_output.state_startup = '0' new_output.state_shutdown = '0' elif output_type == 'wireless_rpi_rf': new_output.pin = None new_output.protocol = 1 new_output.pulse_length = 189 new_output.on_command = '22559' new_output.off_command = '22558' new_output.force_command = True elif output_type == 'command': new_output.linux_command_user = '******' new_output.on_command = '/home/pi/script_on.sh' new_output.off_command = '/home/pi/script_off.sh' new_output.force_command = True elif output_type == 'command_pwm': new_output.linux_command_user = '******' new_output.pwm_command = '/home/pi/script_pwm.sh ((duty_cycle))' elif output_type == 'python': new_output.on_command = """ import datetime timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_string = "{ts}: ID: {id}: ON".format(id=output_id, ts=timestamp) self.logger.info(log_string)""" new_output.off_command = """ import datetime timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_string = "{ts}: ID: {id}: OFF".format(id=output_id, ts=timestamp) self.logger.info(log_string)""" new_output.force_command = True elif output_type == 'python_pwm': new_output.pwm_command = """ import datetime timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_string = "{ts}: ID: {id}: {dc} % Duty Cycle".format( dc=duty_cycle, id=output_id, ts=timestamp) self.logger.info(log_string)""" if not error: new_output.save() display_order = csv_to_list_of_str( DisplayOrder.query.first().output) DisplayOrder.query.first().output = add_display_order( display_order, new_output.unique_id) # # If measurements defined in the Output Module # if ('measurements_dict' in dict_outputs[output_type] and dict_outputs[output_type]['measurements_dict'] != []): for each_channel in dict_outputs[output_type]['measurements_dict']: measure_info = dict_outputs[output_type]['measurements_dict'][each_channel] new_measurement = DeviceMeasurements() if 'name' in measure_info: new_measurement.name = measure_info['name'] new_measurement.device_id = new_output.unique_id new_measurement.measurement = measure_info['measurement'] new_measurement.unit = measure_info['unit'] new_measurement.channel = each_channel new_measurement.save() db.session.commit() if not current_app.config['TESTING']: manipulate_output('Add', new_output.unique_id) except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_output')) if dep_unmet: return 1
def import_influxdb(form): """ Receive a zip file contatining influx metastore and database that was exported with export_influxdb(), then import the metastore and database in InfluxDB. """ action = '{action} {controller}'.format( action=TRANSLATIONS['import']['title'], controller="Influxdb") error = [] try: correct_format = 'Mycodo_MYCODOVERSION_Influxdb_INFLUXVERSION_HOST_DATETIME.zip' upload_folder = os.path.join(INSTALL_DIRECTORY, 'upload') tmp_folder = os.path.join(upload_folder, 'mycodo_influx_tmp') full_path = None if not form.influxdb_import_file.data: error.append('No file present') elif form.influxdb_import_file.data.filename == '': error.append('No file name') else: # Split the uploaded file into parts file_name = form.influxdb_import_file.data.filename name = file_name.rsplit('.', 1)[0] extension = file_name.rsplit('.', 1)[1].lower() name_split = name.split('_') # Split the correctly-formatted filename into parts correct_name = correct_format.rsplit('.', 1)[0] correct_name_1 = correct_name.split('_')[0] correct_name_2 = correct_name.split('_')[2] correct_extension = correct_format.rsplit('.', 1)[1].lower() # Compare the uploaded filename parts to the correct parts try: if name_split[0] != correct_name_1: error.append( "Invalid file name: {n}: {fn} != {cn}.".format( n=file_name, fn=name_split[0], cn=correct_name_1)) error.append("Correct format is: {fmt}".format( fmt=correct_format)) elif name_split[2] != correct_name_2: error.append( "Invalid file name: {n}: {fn} != {cn}".format( n=file_name, fn=name_split[2], cn=correct_name_2)) error.append("Correct format is: {fmt}".format( fmt=correct_format)) elif extension != correct_extension: error.append("Extension not 'zip'") except Exception as err: error.append( "Exception while verifying file name: " "{err}".format(err=err)) if not error: # Save file to upload directory filename = secure_filename( form.influxdb_import_file.data.filename) full_path = os.path.join(tmp_folder, filename) assure_path_exists(tmp_folder) form.influxdb_import_file.data.save( os.path.join(tmp_folder, filename)) # Check if contents of zip file are correct try: file_list = zipfile.ZipFile(full_path, 'r').namelist() if not any(".meta" in s for s in file_list): error.append("No '.meta' file found in archive") elif not any(".manifest" in s for s in file_list): error.append("No '.manifest' file found in archive") except Exception as err: error.append("Exception while opening zip file: " "{err}".format(err=err)) if not error: # Unzip file try: zip_ref = zipfile.ZipFile(full_path, 'r') zip_ref.extractall(tmp_folder) zip_ref.close() except Exception as err: error.append("Exception while extracting zip file: " "{err}".format(err=err)) if not error: try: import_settings_db = threading.Thread( target=thread_import_influxdb, args=(tmp_folder,)) import_settings_db.start() return "Initiated" except Exception as err: error.append( "Exception while importing database: " "{err}".format(err=err)) return None except Exception as err: error.append("Exception: {}".format(err)) flash_success_errors(error, action, url_for('routes_page.page_export'))
def output_mod(form_output, request_form): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['output']['title']) error = [] dict_outputs = parse_output_information() try: mod_output = Output.query.filter( Output.unique_id == form_output.output_id.data).first() if (form_output.uart_location.data and not os.path.exists(form_output.uart_location.data)): error.append(gettext( "Invalid device or improper permissions to read device")) mod_output.name = form_output.name.data if form_output.location.data: mod_output.location = form_output.location.data if form_output.i2c_location.data: mod_output.i2c_location = form_output.i2c_location.data if form_output.ftdi_location.data: mod_output.ftdi_location = form_output.ftdi_location.data if form_output.uart_location.data: mod_output.uart_location = form_output.uart_location.data if form_output.gpio_location.data: if not is_int(form_output.gpio_location.data): error.append("BCM GPIO Pin must be an integer") else: mod_output.pin = form_output.gpio_location.data mod_output.i2c_bus = form_output.i2c_bus.data mod_output.baud_rate = form_output.baud_rate.data mod_output.log_level_debug = form_output.log_level_debug.data mod_output.amps = form_output.amps.data mod_output.trigger_functions_at_start = form_output.trigger_functions_at_start.data mod_output.location = form_output.location.data mod_output.output_mode = form_output.output_mode.data if form_output.on_state.data in ["0", "1"]: mod_output.on_state = bool(int(form_output.on_state.data)) # Wireless options mod_output.protocol = form_output.protocol.data mod_output.pulse_length = form_output.pulse_length.data # Command options mod_output.on_command = form_output.on_command.data mod_output.off_command = form_output.off_command.data mod_output.force_command = form_output.force_command.data # PWM options mod_output.pwm_hertz = form_output.pwm_hertz.data mod_output.pwm_library = form_output.pwm_library.data mod_output.pwm_invert_signal = form_output.pwm_invert_signal.data # Pump options if form_output.flow_rate.data: if (mod_output.output_type == 'atlas_ezo_pmp' and (form_output.flow_rate.data > 105 or form_output.flow_rate.data < 0.5)): error.append("The Atlas Scientific Flow Rate must be between 0.5 and 105 ml/min") elif form_output.flow_rate.data <= 0: error.append("Flow Rate must be a positive value") else: mod_output.flow_rate = form_output.flow_rate.data mod_output.pwm_command = form_output.pwm_command.data mod_output.pwm_invert_signal = form_output.pwm_invert_signal.data mod_output.linux_command_user = form_output.linux_command_user.data if form_output.state_startup.data == '-1': mod_output.state_startup = None elif form_output.state_startup.data is not None: mod_output.state_startup = form_output.state_startup.data if (hasattr(form_output, 'startup_value') and form_output.startup_value.data): mod_output.startup_value = form_output.startup_value.data if form_output.state_shutdown.data == '-1': mod_output.state_shutdown = None elif form_output.state_shutdown.data is not None: mod_output.state_shutdown = form_output.state_shutdown.data if (hasattr(form_output, 'shutdown_value') and form_output.shutdown_value.data): mod_output.shutdown_value = form_output.shutdown_value.data if 'execute_at_modification' in dict_outputs[mod_output.output_type]: (constraints_pass, constraints_errors, mod_input) = dict_outputs[mod_output.output_type]['execute_at_modification']( mod_output, request_form) if constraints_pass: pass elif constraints_errors: for each_error in constraints_errors: flash(each_error, 'error') # Generate string to save from custom options error, custom_options = custom_options_return_string( error, dict_outputs, mod_output, request_form) if not error: mod_output.custom_options = custom_options db.session.commit() manipulate_output('Modify', form_output.output_id.data) except Exception as except_msg: logger.exception(1) error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_output'))
def import_settings(form): """ Receive a zip file containing a Mycodo settings database that was exported with export_settings(), then back up the current Mycodo settings database and implement the one form the zip in its's place. """ action = '{action} {controller}'.format( action=TRANSLATIONS['import']['title'], controller=TRANSLATIONS['settings']['title']) error = [] try: correct_format = 'Mycodo_MYCODOVERSION_Settings_DBVERSION_HOST_DATETIME.zip' upload_folder = os.path.join(INSTALL_DIRECTORY, 'upload') tmp_folder = os.path.join(upload_folder, 'mycodo_db_tmp') mycodo_database_name = 'mycodo.db' full_path = None if not form.settings_import_file.data: error.append('No file present') elif form.settings_import_file.data.filename == '': error.append('No file name') else: # Split the uploaded file into parts file_name = form.settings_import_file.data.filename name = file_name.rsplit('.', 1)[0] extension = file_name.rsplit('.', 1)[1].lower() name_split = name.split('_') # Split the correctly-formatted filename into parts correct_name = correct_format.rsplit('.', 1)[0] correct_name_1 = correct_name.split('_')[0] correct_name_2 = correct_name.split('_')[2] correct_extension = correct_format.rsplit('.', 1)[1].lower() # Compare the uploaded filename parts to the correct parts try: if name_split[0] != correct_name_1: error.append( "Invalid file name: {n}: {fn} != {cn}.".format( n=file_name, fn=name_split[0], cn=correct_name_1)) error.append("Correct format is: {fmt}".format( fmt=correct_format)) elif name_split[2] != correct_name_2: error.append( "Invalid file name: {n}: {fn} != {cn}".format( n=file_name, fn=name_split[2], cn=correct_name_2)) error.append("Correct format is: {fmt}".format( fmt=correct_format)) elif extension != correct_extension: error.append("Extension not 'zip'") elif name_split[1] > MYCODO_VERSION: error.append( "Invalid Mycodo version: {fv} > {mv}. " "Only databases <= {mver} can only be imported".format( fv=name_split[1], mv=MYCODO_VERSION, mver=name_split[1])) except Exception as err: error.append( "Exception while verifying file name: {err}".format(err=err)) if not error: # Save file to upload directory filename = secure_filename( form.settings_import_file.data.filename) full_path = os.path.join(tmp_folder, filename) assure_path_exists(upload_folder) assure_path_exists(tmp_folder) form.settings_import_file.data.save( os.path.join(tmp_folder, filename)) # Check if contents of zip file are correct try: file_list = zipfile.ZipFile(full_path, 'r').namelist() if len(file_list) > 1: error.append("Incorrect number of files in zip: " "{an} != 1".format(an=len(file_list))) elif file_list[0] != mycodo_database_name: error.append("Incorrect file in zip: {af} != {cf}".format( af=file_list[0], cf=mycodo_database_name)) except Exception as err: error.append("Exception while opening zip file: " "{err}".format(err=err)) if not error: # Unzip file try: zip_ref = zipfile.ZipFile(full_path, 'r') zip_ref.extractall(tmp_folder) zip_ref.close() except Exception as err: error.append("Exception while extracting zip file: " "{err}".format(err=err)) if not error: try: # Stop Mycodo daemon (backend) cmd = "{pth}/mycodo/scripts/mycodo_wrapper " \ "daemon_stop".format( pth=INSTALL_DIRECTORY) _, _, _ = cmd_output(cmd) # Backup current database and replace with extracted mycodo.db imported_database = os.path.join( tmp_folder, mycodo_database_name) backup_name = ( SQL_DATABASE_MYCODO + '.backup_' + datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")) os.rename(SQL_DATABASE_MYCODO, backup_name) os.rename(imported_database, SQL_DATABASE_MYCODO) import_settings_db = threading.Thread( target=thread_import_settings, args=(tmp_folder,)) import_settings_db.start() return backup_name except Exception as err: error.append("Exception while replacing database: " "{err}".format(err=err)) return None except Exception as err: error.append("Exception: {}".format(err)) flash_success_errors(error, action, url_for('routes_page.page_export'))
def action_mod(form): """Modify a Conditional Action""" error = [] action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller='{} {}'.format(TRANSLATIONS['conditional']['title'], TRANSLATIONS['actions']['title'])) error = check_form_actions(form, error) try: mod_action = Actions.query.filter( Actions.unique_id == form.function_action_id.data).first() if mod_action.action_type == 'pause_actions': mod_action.pause_duration = form.pause_duration.data elif mod_action.action_type == 'output': mod_action.do_unique_id = form.do_unique_id.data mod_action.do_output_state = form.do_output_state.data mod_action.do_output_duration = form.do_output_duration.data elif mod_action.action_type == 'output_pwm': mod_action.do_unique_id = form.do_unique_id.data mod_action.do_output_pwm = form.do_output_pwm.data elif mod_action.action_type == 'output_ramp_pwm': mod_action.do_unique_id = form.do_unique_id.data mod_action.do_output_pwm = form.do_output_pwm.data mod_action.do_output_pwm2 = form.do_output_pwm2.data mod_action.do_action_string = form.do_action_string.data mod_action.do_output_duration = form.do_output_duration.data elif mod_action.action_type in ['activate_controller', 'deactivate_controller', 'activate_pid', 'deactivate_pid', 'resume_pid', 'pause_pid' 'activate_timer', 'deactivate_timer', 'clear_total_volume', 'input_force_measurements']: mod_action.do_unique_id = form.do_unique_id.data elif mod_action.action_type in ['setpoint_pid', 'setpoint_pid_raise', 'setpoint_pid_lower']: if not str_is_float(form.do_action_string.data): error.append("Setpoint value must be an integer or float value") mod_action.do_unique_id = form.do_unique_id.data mod_action.do_action_string = form.do_action_string.data elif mod_action.action_type == 'method_pid': mod_action.do_unique_id = form.do_unique_id.data mod_action.do_action_string = form.do_action_string.data elif mod_action.action_type == 'infrared_send': mod_action.remote = form.remote.data mod_action.code = form.code.data mod_action.send_times = form.send_times.data elif mod_action.action_type in ['email', 'email_multiple']: mod_action.do_action_string = form.do_action_string.data elif mod_action.action_type in ['photo_email', 'video_email']: mod_action.do_action_string = form.do_action_string.data mod_action.do_unique_id = form.do_unique_id.data mod_action.do_camera_duration = form.do_camera_duration.data elif mod_action.action_type in ['flash_lcd_on', 'flash_lcd_off', 'lcd_backlight_off', 'lcd_backlight_on']: mod_action.do_unique_id = form.do_unique_id.data elif mod_action.action_type == 'photo': mod_action.do_unique_id = form.do_unique_id.data elif mod_action.action_type == 'video': mod_action.do_unique_id = form.do_unique_id.data mod_action.do_camera_duration = form.do_camera_duration.data elif mod_action.action_type in ['command', 'create_note']: mod_action.do_action_string = form.do_action_string.data if not error: db.session.commit() except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def lcd_display_mod(form): action = '{action} {controller}'.format(action=gettext("Mod"), controller=gettext("Display")) error = [] lcd = LCD.query.filter(LCD.unique_id == form.lcd_id.data).first() if lcd.is_activated: error.append( gettext("Deactivate LCD controller before modifying" " its settings.")) if not error: try: mod_lcd = LCD.query.filter( LCD.unique_id == form.lcd_id.data).first() if mod_lcd.is_activated: flash( gettext("Deactivate LCD controller before modifying" " its settings."), "error") return redirect('/lcd') mod_lcd_data = LCDData.query.filter( LCDData.unique_id == form.lcd_data_id.data).first() if form.line_1_display.data: mod_lcd_data.line_1_id = form.line_1_display.data.split(",")[0] mod_lcd_data.line_1_measurement = form.line_1_display.data.split( ",")[1] mod_lcd_data.line_1_max_age = form.line_1_max_age.data mod_lcd_data.line_1_decimal_places = form.line_1_decimal_places.data else: mod_lcd_data.line_1_id = '' mod_lcd_data.line_1_measurement = '' if form.line_2_display.data: mod_lcd_data.line_2_id = form.line_2_display.data.split(",")[0] mod_lcd_data.line_2_measurement = form.line_2_display.data.split( ",")[1] mod_lcd_data.line_2_max_age = form.line_2_max_age.data mod_lcd_data.line_2_decimal_places = form.line_2_decimal_places.data else: mod_lcd_data.line_2_id = '' mod_lcd_data.line_2_measurement = '' if form.line_3_display.data: mod_lcd_data.line_3_id = form.line_3_display.data.split(",")[0] mod_lcd_data.line_3_measurement = form.line_3_display.data.split( ",")[1] mod_lcd_data.line_3_max_age = form.line_3_max_age.data mod_lcd_data.line_3_decimal_places = form.line_3_decimal_places.data else: mod_lcd_data.line_3_id = '' mod_lcd_data.line_3_measurement = '' if form.line_4_display.data: mod_lcd_data.line_4_id = form.line_4_display.data.split(",")[0] mod_lcd_data.line_4_measurement = form.line_4_display.data.split( ",")[1] mod_lcd_data.line_4_max_age = form.line_4_max_age.data mod_lcd_data.line_4_decimal_places = form.line_4_decimal_places.data else: mod_lcd_data.line_4_id = '' mod_lcd_data.line_4_measurement = '' db.session.commit() except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_lcd'))