def loadEdfFile(self): filePath = QFileDialog.getOpenFileName(self, u'Choose edf to load', "./output/", filter="*.edf", selectedFilter="*.edf") if filePath: try: self.tabCount += 1 fileName = ntpath.basename(unicode(filePath)) jobWidget = JobWidget(self.getParams()) jobWidget.jobProgressWidget.hide() jobWidget.runtimeWidget.hide() tabIndex = self.jobTabs.addTab(jobWidget, u"{0}".format(fileName)) self.jobs[self.tabCount] = jobWidget self.showJobGroup(True) self.jobTabs.setCurrentIndex(tabIndex) jobWidget.sigCloseJob.connect( lambda jobIndex=self.tabCount: self.closeJob(jobIndex)) self.uiFinishWait() jobWidget.status = STATUS_FINISHED jobWidget.displayOutput(unicode(filePath)) except Exception as e: message = QErrorMessage(self) message.showMessage( u"Unable to load {0}. Error message: {1}".format( filePath, e.message)) jobWidget.closeJob()
def accept(self): """Acepta el dialogo. Coge la operacion con la que esta trabajando el usuario e inicia el procedimiento de calculo""" from pyrqt.excepciones import OpcionesIncorrectaException import rpy nombre = unicode(self.ui.treeWidget.currentItem().text(0)) widget = self.__widgets["operaciones"][nombre] try: resultado = self.__gestoroperaciones[nombre].procedimiento(widget.seleccion(), widget.opciones()) except OpcionesIncorrectaException: errormessage = QErrorMessage(self) errormessage.showMessage(u"Las opciones no son correctas") #except IndexError: # errormessage = QErrorMessage(self) # errormessage.showMessage(u"Seleccion incorrecta") # LOG.exception("excepcion capturada") except KeyError: QErrorMessage(self).showMessage(u"Hay elementos de la salida sin definir(o mal definidos) en la operación") LOG.exception("Excepción Generada por un módulo de operaciones") except rpy.RException: QErrorMessage(self).showMessage(u"R devolvio un error") log.exception("Excepción de RPY") except AssertionError: QErrorMessage(self).showMessage(u"Error desconocido") else: self.__vsalida.ana_res(resultado) #Añadir a la salida el resultado self.__vsalida.hide() #TODO averiguar como hacer para que recupere el foco sin ocultar la ventana self.__vsalida.show()
def input_device_changed(self, index): success, index = self.audio_device.select_input_device(index) self.ui.DeviceList.setCurrentIndex(index) self.fft_plot.must_plot = True if not success: # Note: the error message is a child of the settings dialog, so that # that dialog remains on top when the error message is closed error_message = QErrorMessage(self.settings_dialog) error_message.setWindowTitle("Input device error") error_message.showMessage("Impossible to use the selected input" " device, reverting to the previous one")
def second_channel_changed(self, index): self.ui.actionStart.setChecked(False) success, index = self.audiobackend.select_second_channel(index) self.settings_dialog.comboBox_secondChannel.setCurrentIndex(index) if not success: # Note: the error message is a child of the settings dialog, so that # that dialog remains on top when the error message is closed error_message = QErrorMessage(self.settings_dialog) error_message.setWindowTitle("Input device error") error_message.showMessage("Impossible to use the selected channel as the second channel, reverting to the previous one") self.ui.actionStart.setChecked(True)
def loadParameterSet(self): s = QSettings() name = self.configCombo.currentText() s.beginGroup('ParameterSets') if not name in s.childGroups(): dlg = QErrorMessage(self) dlg.setWindowTitle('Error') dlg.showMessage('No saved parameters available for %s' % name) return s.beginGroup(name) for item in self.parameterItems: item.setValue(s.value(item.objectName(), item.value(), type=float)) self.adjustExcitationCb.setChecked(s.value('adjustExcitation', False, type=bool)) self.sensorNameLe.setText(s.value('sensorName', '', type=QString)) self.visaCombo.setCurrentIndex(self.visaCombo.findText(s.value('sr830Visa', 'GPIB0::12', type=QString))) self.autoRangingCb.setChecked(s.value('autoRanging', True, type=bool)) self.minSensitivityCombo.setCurrentCodeSilently(s.value('minSensitivity', 0, type=int)) s.endGroup() s.endGroup()
def addScanNumbers(self): result = self.range_dialog.exec_() if result == QDialog.Accepted: text = self.range_ui.range_edit.text() if text: not_found = [] numbers = mythen.parse_range_list(text) year, visit = self.getYearAndVisit() progress = QProgressDialog( "Locating scan files from numbers...", "Stop", 0, len(numbers), self) progress.setWindowModality(Qt.WindowModal) progress.forceShow() progress.setValue(0) for n in numbers: progress.setValue(progress.value() + 1) if progress.wasCanceled(): break files = mythen.find_mythen_files( n, visit=visit, year=year) # FIXME needs to be in separate thread(!) if files: files = [f for f in files if f not in self.scans] self.scans.extend(files) self.scans_model.setStringList(self.scans) else: not_found.append(n) progress.setValue(progress.maximum()) if not_found: error = QErrorMessage(self) msg = "The following numbers were not found: " for n in not_found: msg = msg + str(n) + ", " error.showMessage(msg[:-2])
class DC(PluginBase, Ui_DC): qtcb_position_reached = pyqtSignal(int) qtcb_under_voltage = pyqtSignal(int) qtcb_emergency_shutdown = pyqtSignal() def __init__(self, ipcon, uid, version): PluginBase.__init__(self, ipcon, uid, 'DC Brick', version) self.setupUi(self) self.encoder_hide_all() self.dc = BrickDC(uid, ipcon) self.device = self.dc self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_data) self.speedometer = SpeedoMeter() self.vertical_layout_right.insertWidget(4, self.speedometer) self.new_value = 0 self.update_counter = 0 self.full_brake_time = 0 self.velocity_slider.sliderReleased.connect(self.velocity_slider_released) self.velocity_slider.valueChanged.connect(self.velocity_spin.setValue) self.velocity_spin.editingFinished.connect(self.velocity_spin_finished) self.acceleration_slider.sliderReleased.connect(self.acceleration_slider_released) self.acceleration_slider.valueChanged.connect(self.acceleration_spin.setValue) self.acceleration_spin.editingFinished.connect(self.acceleration_spin_finished) self.frequency_slider.sliderReleased.connect(self.frequency_slider_released) self.frequency_slider.valueChanged.connect(self.frequency_spin.setValue) self.frequency_spin.editingFinished.connect(self.frequency_spin_finished) self.radio_mode_brake.toggled.connect(self.brake_value_changed) self.radio_mode_coast.toggled.connect(self.coast_value_changed) self.minimum_voltage_button.pressed.connect(self.minimum_voltage_button_pressed) self.full_brake_button.pressed.connect(self.full_brake_pressed) self.enable_checkbox.stateChanged.connect(self.enable_state_changed) self.emergency_signal = None self.under_signal = None self.current_velocity_signal = None self.velocity_reached_signal = None self.qem = QErrorMessage(self) self.qtcb_under_voltage.connect(self.cb_under_voltage) self.dc.register_callback(self.dc.CALLBACK_UNDER_VOLTAGE, self.qtcb_under_voltage.emit) self.qtcb_emergency_shutdown.connect(self.cb_emergency_shutdown) self.dc.register_callback(self.dc.CALLBACK_EMERGENCY_SHUTDOWN, self.qtcb_emergency_shutdown.emit) self.qtcb_position_reached.connect(self.update_velocity) self.dc.register_callback(self.dc.CALLBACK_VELOCITY_REACHED, self.qtcb_position_reached.emit) self.dc.register_callback(self.dc.CALLBACK_CURRENT_VELOCITY, self.qtcb_position_reached.emit) # if self.version >= (2, 0, 1): # self.enable_encoder_checkbox.stateChanged.connect(self.enable_encoder_state_changed) # self.encoder_show() # else: # self.enable_encoder_checkbox.setText('Enable Encoder (Firmware >= 2.01 required)') # self.enable_encoder_checkbox.setEnabled(False) def start(self): self.update_timer.start(1000) async_call(self.dc.set_current_velocity_period, 100, None, self.increase_error_count) self.update_start() self.update_data() def stop(self): self.update_timer.stop() async_call(self.dc.set_current_velocity_period, 0, None, self.increase_error_count) def has_reset_device(self): return self.version >= (1, 1, 3) def reset_device(self): if self.has_reset_device(): self.dc.reset() def is_brick(self): return True def get_url_part(self): return 'dc' @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickDC.DEVICE_IDENTIFIER def cb_emergency_shutdown(self): if not self.qem.isVisible(): self.qem.setWindowTitle("Emergency Shutdown") self.qem.showMessage("Emergency Shutdown: Short-Circuit or Over-Temperature") def cb_under_voltage(self, ov): mv_str = self.minimum_voltage_label.text() ov_str = "%gV" % round(ov/1000.0, 1) if not self.qem.isVisible(): self.qem.setWindowTitle("Under Voltage") self.qem.showMessage("Under Voltage: Output Voltage of " + ov_str + " is below minimum voltage of " + mv_str, "DC_UnderVoltage") def encoder_hide_all(self): self.enable_encoder_checkbox.hide() self.encoder_hide() def encoder_hide(self): self.p_label.hide() self.p_spinbox.hide() self.i_label.hide() self.i_spinbox.hide() self.d_label.hide() self.d_spinbox.hide() self.st_label.hide() self.st_spinbox.hide() self.cpr_label.hide() self.cpr_spinbox.hide() self.encoder_spacer.hide() def encoder_show(self): self.p_label.show() self.p_spinbox.show() self.i_label.show() self.i_spinbox.show() self.d_label.show() self.d_spinbox.show() self.st_label.show() self.st_spinbox.show() self.cpr_label.show() self.cpr_spinbox.show() self.encoder_spacer.show() def enable_encoder_state_changed(self, state): try: if state == Qt.Checked: self.dc.enable_encoder() self.update_encoder() elif state == Qt.Unchecked: self.dc.disable_encoder() except ip_connection.Error: return def enable_state_changed(self, state): try: if state == Qt.Checked: self.dc.enable() elif state == Qt.Unchecked: self.dc.disable() except ip_connection.Error: return def brake_value_changed(self, checked): if checked: try: self.dc.set_drive_mode(0) except ip_connection.Error: return def coast_value_changed(self, checked): if checked: try: self.dc.set_drive_mode(1) except ip_connection.Error: return def full_brake_pressed(self): try: self.dc.full_brake() except ip_connection.Error: return def minimum_voltage_selected(self, value): try: self.dc.set_minimum_voltage(value) except ip_connection.Error: return def minimum_voltage_button_pressed(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(5000) qid.setIntMaximum(0xFFFF) qid.setIntStep(100) async_call(self.dc.get_minimum_voltage, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.minimum_voltage_selected) qid.setLabelText("Choose minimum motor voltage in mV.") qid.open() def stack_input_voltage_update(self, sv): sv_str = "%gV" % round(sv/1000.0, 1) self.stack_voltage_label.setText(sv_str) def external_input_voltage_update(self, ev): ev_str = "%gV" % round(ev/1000.0, 1) self.external_voltage_label.setText(ev_str) def minimum_voltage_update(self, mv): mv_str = "%gV" % round(mv/1000.0, 1) self.minimum_voltage_label.setText(mv_str) def drive_mode_update(self, dm): if dm == 0: self.radio_mode_brake.setChecked(True) self.radio_mode_coast.setChecked(False) else: self.radio_mode_brake.setChecked(False) self.radio_mode_coast.setChecked(True) def current_consumption_update(self, cc): if cc >= 1000: cc_str = "%gA" % round(cc/1000.0, 1) else: cc_str = "%gmA" % cc self.current_label.setText(cc_str) def update_velocity(self, value): if value != self.speedometer.value(): self.speedometer.set_velocity(value) def get_velocity_async(self, velocity): if not self.velocity_slider.isSliderDown(): if velocity != self.velocity_slider.sliderPosition(): self.velocity_slider.setSliderPosition(velocity) self.velocity_spin.setValue(velocity) def get_acceleration_async(self, acceleration): if not self.acceleration_slider.isSliderDown(): if acceleration != self.acceleration_slider.sliderPosition(): self.acceleration_slider.setSliderPosition(acceleration) self.acceleration_spin.setValue(acceleration) def get_pwm_frequency_async(self, frequency): if not self.frequency_slider.isSliderDown(): if frequency != self.frequency_slider.sliderPosition(): self.frequency_slider.setSliderPosition(frequency) self.frequency_spin.setValue(frequency) def is_enabled_async(self, enabled): if enabled: self.enable_checkbox.setCheckState(Qt.Checked) else: self.enable_checkbox.setCheckState(Qt.Unchecked) def is_encoder_enabled_async(self, enabled): if enabled: self.enable_encoder_checkbox.setCheckState(Qt.Checked) else: self.enable_encoder_checkbox.setCheckState(Qt.Unchecked) def get_encoder_config_async(self, cpr): self.cpr_spinbox.setValue(cpr) def get_encoder_pid_config_async(self, pid_config): self.p_spinbox.setValue(pid_config.p) self.i_spinbox.setValue(pid_config.i) self.d_spinbox.setValue(pid_config.d) self.st_spinbox.setValue(pid_config.sample_time) def update_encoder(self): async_call(self.dc.get_encoder_config, None, self.get_encoder_config_async, self.increase_error_count) async_call(self.dc.get_encoder_pid_config, None, self.get_encoder_pid_config_async, self.increase_error_count) async_call(self.dc.is_encoder_enabled, None, self.is_encoder_enabled_async, self.increase_error_count) def update_start(self): async_call(self.dc.get_drive_mode, None, self.drive_mode_update, self.increase_error_count) async_call(self.dc.get_velocity, None, self.get_velocity_async, self.increase_error_count) async_call(self.dc.get_acceleration, None, self.get_acceleration_async, self.increase_error_count) async_call(self.dc.get_pwm_frequency, None, self.get_pwm_frequency_async, self.increase_error_count) async_call(self.dc.is_enabled, None, self.is_enabled_async, self.increase_error_count) # if self.version >= (2, 0, 1): # self.update_encoder() def update_data(self): async_call(self.dc.get_stack_input_voltage, None, self.stack_input_voltage_update, self.increase_error_count) async_call(self.dc.get_external_input_voltage, None, self.external_input_voltage_update, self.increase_error_count) async_call(self.dc.get_minimum_voltage, None, self.minimum_voltage_update, self.increase_error_count) async_call(self.dc.get_current_consumption, None, self.current_consumption_update, self.increase_error_count) def acceleration_slider_released(self): value = self.acceleration_slider.value() self.acceleration_spin.setValue(value) try: self.dc.set_acceleration(value) except ip_connection.Error: return def acceleration_spin_finished(self): value = self.acceleration_spin.value() self.acceleration_slider.setValue(value) try: self.dc.set_acceleration(value) except ip_connection.Error: return def velocity_slider_released(self): value = self.velocity_slider.value() self.velocity_spin.setValue(value) try: self.dc.set_velocity(value) except ip_connection.Error: return def velocity_spin_finished(self): value = self.velocity_spin.value() self.velocity_slider.setValue(value) try: self.dc.set_velocity(value) except ip_connection.Error: return def frequency_slider_released(self): value = self.frequency_slider.value() self.frequency_spin.setValue(value) try: self.dc.set_pwm_frequency(value) except ip_connection.Error: return def frequency_spin_finished(self): value = self.frequency_spin.value() self.frequency_slider.setValue(value) try: self.dc.set_pwm_frequency(value) except ip_connection.Error: return
class ImagesWidget(QWidget, Ui_Images): images = None def __init__(self, parent, app): super(QWidget, self).__init__() self.app = app self.setupUi(self) self.error_msg = QErrorMessage() self.error_msg.setWindowTitle("Starter Kit: Blinkenlights Demo " + config.DEMO_VERSION) self.slider_frame_rate.valueChanged.connect(self.slider_frame_rate_changed) self.spinbox_frame_rate.valueChanged.connect(self.spinbox_frame_rate_changed) self.button_choose.pressed.connect(self.choose_pressed) self.button_show.pressed.connect(self.show_pressed) self.button_default.pressed.connect(self.default_pressed) self.update_frame_rate_timer = QTimer(self) self.update_frame_rate_timer.timeout.connect(self.update_frame_rate) self.default_pressed() def start(self): self.images = Images(self.app.ipcon) self.update_frame_rate() self.images.frame_rendered(0) def stop(self): if self.images: self.images.stop_rendering() self.images = None def spinbox_frame_rate_changed(self, frame_rate): self.slider_frame_rate.setValue(frame_rate) self.update_frame_rate_timer.start(100) def slider_frame_rate_changed(self, frame_rate): self.spinbox_frame_rate.setValue(frame_rate) def show_pressed(self): if self.images: files = unicode(self.text_edit_files.toPlainText()).strip() if len(files) > 0: new_images = files.split('\n') try: self.images.set_new_images(new_images) except Exception as e: self.error_msg.showMessage(str(e)) self.images.frame_prepare_next() self.images.frame_rendered(0) def choose_pressed(self): for filename in QFileDialog.getOpenFileNames(self, 'Choose Images', QDir.homePath()): self.text_edit_files.append(filename) def default_pressed(self): self.spinbox_frame_rate.setValue(1) def update_frame_rate(self): self.update_frame_rate_timer.stop() config.IMAGES_FRAME_RATE = self.spinbox_frame_rate.value() if self.images: self.images.update_frame_rate()
class SilentStepper(PluginBase, Ui_SilentStepper): qtcb_position_reached = pyqtSignal(int) qtcb_under_voltage = pyqtSignal(int) def __init__(self, *args): PluginBase.__init__(self, BrickSilentStepper, *args) self.setupUi(self) self.silent_stepper = self.device self.endis_all(False) self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_data) self.speedometer = SpeedoMeter() self.vertical_layout_right.insertWidget(5, self.speedometer) self.new_value = 0 self.update_counter = 0 self.full_brake_time = 0 self.qem = QErrorMessage(self) self.qem.setWindowTitle("Under Voltage") self.velocity_syncer = SliderSpinSyncer(self.velocity_slider, self.velocity_spin, self.velocity_changed) self.acceleration_syncer = SliderSpinSyncer(self.acceleration_slider, self.acceleration_spin, self.acceleration_changed) self.deceleration_syncer = SliderSpinSyncer(self.deceleration_slider, self.deceleration_spin, self.deceleration_changed) self.enable_checkbox.stateChanged.connect(self.enable_state_changed) self.forward_button.clicked.connect(self.forward_clicked) self.stop_button.clicked.connect(self.stop_clicked) self.full_brake_button.clicked.connect(self.full_brake_clicked) self.backward_button.clicked.connect(self.backward_clicked) self.to_button.clicked.connect(self.to_button_clicked) self.steps_button.clicked.connect(self.steps_button_clicked) self.motor_current_button.clicked.connect(self.motor_current_button_clicked) self.minimum_motor_voltage_button.clicked.connect(self.minimum_motor_voltage_button_clicked) self.qtcb_position_reached.connect(self.cb_position_reached) self.silent_stepper.register_callback(self.silent_stepper.CALLBACK_POSITION_REACHED, self.qtcb_position_reached.emit) self.qtcb_under_voltage.connect(self.cb_under_voltage) self.silent_stepper.register_callback(self.silent_stepper.CALLBACK_UNDER_VOLTAGE, self.qtcb_under_voltage.emit) # Step Configuration self.step_resolution_dropbox.currentIndexChanged.connect(self.step_configuration_changed) self.interpolate_checkbox.stateChanged.connect(self.step_configuration_changed) # Basic Configuration self.standstill_current_spin.valueChanged.connect(self.basic_configuration_changed) self.motor_run_current_spin.valueChanged.connect(self.basic_configuration_changed) self.standstill_delay_time_spin.valueChanged.connect(self.basic_configuration_changed) self.power_down_time_spin.valueChanged.connect(self.basic_configuration_changed) self.stealth_threshold_spin.valueChanged.connect(self.basic_configuration_changed) self.coolstep_threashold_spin.valueChanged.connect(self.basic_configuration_changed) self.classic_threshold_spin.valueChanged.connect(self.basic_configuration_changed) self.high_velocity_chopper_mode_checkbox.stateChanged.connect(self.basic_configuration_changed) # Spreadcycle Configuration self.slow_decay_duration_spin.valueChanged.connect(self.spreadcycle_configuration_changed) self.enable_random_slow_decay_checkbox.stateChanged.connect(self.spreadcycle_configuration_changed) self.fast_decay_duration_spin.valueChanged.connect(self.spreadcycle_configuration_changed) self.hysteresis_start_value_spin.valueChanged.connect(self.spreadcycle_configuration_changed) self.hysteresis_end_value_spin.valueChanged.connect(self.spreadcycle_configuration_changed) self.sine_wave_offset_spin.valueChanged.connect(self.spreadcycle_configuration_changed) self.chopper_mode_combo.currentIndexChanged.connect(self.spreadcycle_configuration_changed) self.comparator_blank_time_combo.currentIndexChanged.connect(self.spreadcycle_configuration_changed) self.fast_decay_without_comparator_checkbox.stateChanged.connect(self.spreadcycle_configuration_changed) # Stealth Configuration self.enable_stealth_checkbox.stateChanged.connect(self.stealth_configuration_changed) self.amplitude_spin.valueChanged.connect(self.stealth_configuration_changed) self.gradient_spin.valueChanged.connect(self.stealth_configuration_changed) self.enable_autoscale_checkbox.stateChanged.connect(self.stealth_configuration_changed) self.force_symmetric_checkbox.stateChanged.connect(self.stealth_configuration_changed) self.freewheel_mode_combo.currentIndexChanged.connect(self.stealth_configuration_changed) # Coolstep Configuration self.minimum_stallguard_value_spin.valueChanged.connect(self.coolstep_configuration_changed) self.maximum_stallguard_value_spin.valueChanged.connect(self.coolstep_configuration_changed) self.current_up_step_width_combo.currentIndexChanged.connect(self.coolstep_configuration_changed) self.current_down_step_width_combo.currentIndexChanged.connect(self.coolstep_configuration_changed) self.minimum_current_combo.currentIndexChanged.connect(self.coolstep_configuration_changed) self.stallguard_threshold_value_spin.valueChanged.connect(self.coolstep_configuration_changed) self.stallguard_mode_combo.currentIndexChanged.connect(self.coolstep_configuration_changed) # Misc Configuration self.disable_short_to_ground_protection_checkbox.stateChanged.connect(self.misc_configuration_changed) self.synchronize_phase_frequency_spin.valueChanged.connect(self.misc_configuration_changed) self.ste = 0 self.pos = 0 self.current_velocity = 0 self.cur = 0 self.sv = 0 self.ev = 0 self.mv = 0 self.mod = 0 self.status_led_action = QAction('Status LED', self) self.status_led_action.setCheckable(True) self.status_led_action.toggled.connect(lambda checked: self.silent_stepper.enable_status_led() if checked else self.silent_stepper.disable_status_led()) self.set_configs([(0, None, [self.status_led_action])]) reset = QAction('Reset', self) reset.triggered.connect(lambda: self.silent_stepper.reset()) self.set_actions([(0, None, [reset])]) def start(self): async_call(self.silent_stepper.is_status_led_enabled, None, self.status_led_action.setChecked, self.increase_error_count) self.update_timer.start(100) self.update_start() def stop(self): self.update_timer.stop() def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickSilentStepper.DEVICE_IDENTIFIER def cb_position_reached(self, position): self.position_update(position) self.endis_all(True) def disable_list(self, button_list): for button in button_list: button.setEnabled(False) def endis_all(self, value): self.forward_button.setEnabled(value) self.stop_button.setEnabled(value) self.backward_button.setEnabled(value) self.to_button.setEnabled(value) self.steps_button.setEnabled(value) self.full_brake_button.setEnabled(value) def step_configuration_changed(self, _): step_resolution = self.step_resolution_dropbox.currentIndex() interpolation = self.interpolate_checkbox.isChecked() try: self.silent_stepper.set_step_configuration(step_resolution, interpolation) except ip_connection.Error: return def basic_configuration_changed(self, _): standstill_current = self.standstill_current_spin.value() motor_run_current = self.motor_run_current_spin.value() standstill_delay_time = self.standstill_delay_time_spin.value() power_down_time = self.power_down_time_spin.value() stealth_threshold = self.stealth_threshold_spin.value() coolstep_threshold = self.coolstep_threashold_spin.value() classic_threshold = self.classic_threshold_spin.value() high_velocity_chopper_mode = self.high_velocity_chopper_mode_checkbox.isChecked() try: self.silent_stepper.set_basic_configuration(standstill_current, motor_run_current, standstill_delay_time, power_down_time, stealth_threshold, coolstep_threshold, classic_threshold, high_velocity_chopper_mode) except ip_connection.Error: return def spreadcycle_configuration_changed(self, _): slow_decay_duration = self.slow_decay_duration_spin.value() enable_random_slow_decay = self.enable_random_slow_decay_checkbox.isChecked() fast_decay_duration = self.fast_decay_duration_spin.value() hysteresis_start_value = self.hysteresis_start_value_spin.value() hysteresis_end_value = self.hysteresis_end_value_spin.value() sine_wave_offset = self.sine_wave_offset_spin.value() chopper_mode = self.chopper_mode_combo.currentIndex() comparator_blank_time = self.comparator_blank_time_combo.currentIndex() fast_decay_without_comparator = self.fast_decay_without_comparator_checkbox.isChecked() try: self.silent_stepper.set_spreadcycle_configuration(slow_decay_duration, enable_random_slow_decay, fast_decay_duration, hysteresis_start_value, hysteresis_end_value, sine_wave_offset, chopper_mode, comparator_blank_time, fast_decay_without_comparator) except ip_connection.Error: return def stealth_configuration_changed(self, _): enable_stealth = self.enable_stealth_checkbox.isChecked() amplitude = self.amplitude_spin.value() gradient = self.gradient_spin.value() enable_autoscale = self.enable_autoscale_checkbox.isChecked() force_symmetric = self.force_symmetric_checkbox.isChecked() freewheel_mode = self.freewheel_mode_combo.currentIndex() try: self.silent_stepper.set_stealth_configuration(enable_stealth, amplitude, gradient, enable_autoscale, force_symmetric, freewheel_mode) except ip_connection.Error: return def coolstep_configuration_changed(self, _): minimum_stallguard_value = self.minimum_stallguard_value_spin.value() maximum_stallguard_value = self.maximum_stallguard_value_spin.value() current_up_step_width = self.current_up_step_width_combo.currentIndex() current_down_step_width = self.current_down_step_width_combo.currentIndex() minimum_current = self.minimum_current_combo.currentIndex() stallguard_threshold_value = self.stallguard_threshold_value_spin.value() stallguard_mode = self.stallguard_mode_combo.currentIndex() try: self.silent_stepper.set_coolstep_configuration(minimum_stallguard_value, maximum_stallguard_value, current_up_step_width, current_down_step_width, minimum_current, stallguard_threshold_value, stallguard_mode) except ip_connection.Error: return def misc_configuration_changed(self, _): disable_short_to_ground_protection = self.disable_short_to_ground_protection_checkbox.isChecked() synchronize_phase_frequency = self.synchronize_phase_frequency_spin.value() try: self.silent_stepper.set_misc_configuration(disable_short_to_ground_protection, synchronize_phase_frequency) except ip_connection.Error: return def forward_clicked(self): try: self.silent_stepper.drive_forward() except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button]) def backward_clicked(self): try: self.silent_stepper.drive_backward() except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button]) def stop_clicked(self): try: self.silent_stepper.stop() except ip_connection.Error: return self.endis_all(True) def full_brake_clicked(self): try: self.silent_stepper.full_brake() except ip_connection.Error: return self.endis_all(True) def to_button_clicked(self): drive_to = self.to_spin.value() try: self.silent_stepper.set_target_position(drive_to) except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button, self.forward_button, self.backward_button]) def steps_button_clicked(self): drive_steps = self.steps_spin.value() try: self.silent_stepper.set_steps(drive_steps) except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button, self.forward_button, self.backward_button]) def motor_current_button_clicked(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(360) qid.setIntMaximum(1640) qid.setIntStep(100) async_call(self.silent_stepper.get_motor_current, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.motor_current_selected) qid.setLabelText("Choose motor current in mA.") qid.open() def minimum_motor_voltage_button_clicked(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(0) qid.setIntMaximum(40000) qid.setIntStep(100) async_call(self.silent_stepper.get_minimum_voltage, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.minimum_motor_voltage_selected) qid.setLabelText("Choose minimum motor voltage in mV.") qid.open() def motor_current_selected(self, value): try: self.silent_stepper.set_motor_current(value) except ip_connection.Error: return def minimum_motor_voltage_selected(self, value): try: self.silent_stepper.set_minimum_voltage(value) except ip_connection.Error: return def cb_under_voltage(self, ov): mv_str = self.minimum_voltage_label.text() ov_str = "%gV" % round(ov/1000.0, 1) if not self.qem.isVisible(): self.qem.showMessage("Under Voltage: Output Voltage of " + ov_str + " is below minimum voltage of " + mv_str, "SilentStepper_UnderVoltage") def enable_state_changed(self, state): try: if state == Qt.Checked: self.endis_all(True) self.silent_stepper.enable() elif state == Qt.Unchecked: self.endis_all(False) self.silent_stepper.disable() except ip_connection.Error: return def stack_input_voltage_update(self, sv): sv_str = "%gV" % round(sv/1000.0, 1) self.stack_voltage_label.setText(sv_str) def external_input_voltage_update(self, ev): ev_str = "%gV" % round(ev/1000.0, 1) self.external_voltage_label.setText(ev_str) def minimum_voltage_update(self, mv): mv_str = "%gV" % round(mv/1000.0, 1) self.minimum_voltage_label.setText(mv_str) def maximum_current_update(self, cur): cur_str = "%gA" % round(cur/1000.0, 1) self.maximum_current_label.setText(cur_str) def position_update(self, pos): pos_str = "%d" % pos self.position_label.setText(pos_str) def remaining_steps_update(self, ste): ste_str = "%d" % ste self.remaining_steps_label.setText(ste_str) def driver_status_update(self, update): if update.open_load == 0: self.status_open_load.setText('No') elif update.open_load == 1: self.status_open_load.setText('Phase A') elif update.open_load == 2: self.status_open_load.setText('Phase B') elif update.open_load == 3: self.status_open_load.setText('Phase A and B') else: self.status_open_load.setText('Unknown') if update.short_to_ground == 0: self.status_short_to_ground.setText('No') elif update.short_to_ground == 1: self.status_short_to_ground.setText('Phase A') elif update.short_to_ground == 2: self.status_short_to_ground.setText('Phase B') elif update.short_to_ground == 3: self.status_short_to_ground.setText('Phase A and B') else: self.status_short_to_ground.setText('Unknown') if update.over_temperature == 0: self.status_over_temperature.setText('No') elif update.over_temperature == 1: self.status_over_temperature.setText('<font color=yellow>Warning</font>') elif update.over_temperature == 2: self.status_over_temperature.setText('<font color=red>Limit</font>') if update.motor_stalled: self.status_motor_stalled.setText('Yes') else: self.status_motor_stalled.setText('No') self.status_actual_motor_current.setText(str(update.actual_motor_current)) if update.full_step_active: self.status_full_step_active.setText('Yes') else: self.status_full_step_active.setText('No') self.status_stallguard_result.setText(str(update.stallguard_result)) self.status_stealth_voltage_amplitude.setText(str(update.stealth_voltage_amplitude)) def get_max_velocity_async(self, velocity): if not self.velocity_slider.isSliderDown(): if velocity != self.velocity_slider.sliderPosition(): self.velocity_slider.setSliderPosition(velocity) self.velocity_spin.setValue(velocity) def get_speed_ramping_async(self, ramp): acc, dec = ramp if not self.acceleration_slider.isSliderDown() and \ not self.deceleration_slider.isSliderDown(): if acc != self.acceleration_slider.sliderPosition(): self.acceleration_slider.setSliderPosition(acc) self.acceleration_spin.setValue(acc) if dec != self.deceleration_slider.sliderPosition(): self.deceleration_slider.setSliderPosition(dec) self.deceleration_spin.setValue(dec) def is_enabled_async(self, enabled): if enabled: if not self.enable_checkbox.isChecked(): self.endis_all(True) self.enable_checkbox.blockSignals(True) self.enable_checkbox.setChecked(True) self.enable_checkbox.blockSignals(False) else: if self.enable_checkbox.isChecked(): self.endis_all(False) self.enable_checkbox.blockSignals(True) self.enable_checkbox.setChecked(False) self.enable_checkbox.blockSignals(False) def get_step_configuration_async(self, conf): self.step_resolution_dropbox.blockSignals(True) self.step_resolution_dropbox.setCurrentIndex(conf.step_resolution) self.step_resolution_dropbox.blockSignals(False) self.interpolate_checkbox.blockSignals(True) self.interpolate_checkbox.setChecked(conf.interpolation) self.interpolate_checkbox.blockSignals(False) def get_basic_configuration_async(self, conf): self.standstill_current_spin.blockSignals(True) self.standstill_current_spin.setValue(conf.standstill_current) self.standstill_current_spin.blockSignals(False) self.motor_run_current_spin.blockSignals(True) self.motor_run_current_spin.setValue(conf.motor_run_current) self.motor_run_current_spin.blockSignals(False) self.standstill_delay_time_spin.blockSignals(True) self.standstill_delay_time_spin.setValue(conf.standstill_delay_time) self.standstill_delay_time_spin.blockSignals(False) self.power_down_time_spin.blockSignals(True) self.power_down_time_spin.setValue(conf.power_down_time) self.power_down_time_spin.blockSignals(False) self.stealth_threshold_spin.blockSignals(True) self.stealth_threshold_spin.setValue(conf.stealth_threshold) self.stealth_threshold_spin.blockSignals(False) self.coolstep_threashold_spin.blockSignals(True) self.coolstep_threashold_spin.setValue(conf.coolstep_threshold) self.coolstep_threashold_spin.blockSignals(False) self.classic_threshold_spin.blockSignals(True) self.classic_threshold_spin.setValue(conf.classic_threshold) self.classic_threshold_spin.blockSignals(False) self.high_velocity_chopper_mode_checkbox.blockSignals(True) self.high_velocity_chopper_mode_checkbox.setChecked(conf.high_velocity_chopper_mode) self.high_velocity_chopper_mode_checkbox.blockSignals(False) def get_spreadcycle_configuration_async(self, conf): self.slow_decay_duration_spin.blockSignals(True) self.slow_decay_duration_spin.setValue(conf.slow_decay_duration) self.slow_decay_duration_spin.blockSignals(False) self.enable_random_slow_decay_checkbox.blockSignals(True) self.enable_random_slow_decay_checkbox.setChecked(conf.enable_random_slow_decay) self.enable_random_slow_decay_checkbox.blockSignals(False) self.fast_decay_duration_spin.blockSignals(True) self.fast_decay_duration_spin.setValue(conf.fast_decay_duration) self.fast_decay_duration_spin.blockSignals(False) self.hysteresis_start_value_spin.blockSignals(True) self.hysteresis_start_value_spin.setValue(conf.hysteresis_start_value) self.hysteresis_start_value_spin.blockSignals(False) self.hysteresis_end_value_spin.blockSignals(True) self.hysteresis_end_value_spin.setValue(conf.hysteresis_end_value) self.hysteresis_end_value_spin.blockSignals(False) self.sine_wave_offset_spin.blockSignals(True) self.sine_wave_offset_spin.setValue(conf.sine_wave_offset) self.sine_wave_offset_spin.blockSignals(False) self.chopper_mode_combo.blockSignals(True) self.chopper_mode_combo.setCurrentIndex(conf.chopper_mode) self.chopper_mode_combo.blockSignals(False) self.standstill_current_spin.blockSignals(True) self.comparator_blank_time_combo.setCurrentIndex(conf.comparator_blank_time) self.standstill_current_spin.blockSignals(False) self.fast_decay_without_comparator_checkbox.blockSignals(True) self.fast_decay_without_comparator_checkbox.setChecked(conf.fast_decay_without_comparator) self.fast_decay_without_comparator_checkbox.blockSignals(False) def get_stealth_configuration_async(self, conf): self.enable_stealth_checkbox.blockSignals(True) self.enable_stealth_checkbox.setChecked(conf.enable_stealth) self.enable_stealth_checkbox.blockSignals(False) self.amplitude_spin.blockSignals(True) self.amplitude_spin.setValue(conf.amplitude) self.amplitude_spin.blockSignals(False) self.gradient_spin.blockSignals(True) self.gradient_spin.setValue(conf.gradient) self.gradient_spin.blockSignals(False) self.enable_autoscale_checkbox.blockSignals(True) self.enable_autoscale_checkbox.setChecked(conf.enable_autoscale) self.enable_autoscale_checkbox.blockSignals(False) self.force_symmetric_checkbox.blockSignals(True) self.force_symmetric_checkbox.setChecked(conf.force_symmetric) self.force_symmetric_checkbox.blockSignals(False) self.freewheel_mode_combo.blockSignals(True) self.freewheel_mode_combo.setCurrentIndex(conf.freewheel_mode) self.freewheel_mode_combo.blockSignals(False) def get_coolstep_configuration_async(self, conf): self.minimum_stallguard_value_spin.blockSignals(True) self.minimum_stallguard_value_spin.setValue(conf.minimum_stallguard_value) self.minimum_stallguard_value_spin.blockSignals(False) self.maximum_stallguard_value_spin.blockSignals(True) self.maximum_stallguard_value_spin.setValue(conf.maximum_stallguard_value) self.maximum_stallguard_value_spin.blockSignals(False) self.current_up_step_width_combo.blockSignals(True) self.current_up_step_width_combo.setCurrentIndex(conf.current_up_step_width) self.current_up_step_width_combo.blockSignals(False) self.current_down_step_width_combo.blockSignals(True) self.current_down_step_width_combo.setCurrentIndex(conf.current_down_step_width) self.current_down_step_width_combo.blockSignals(False) self.minimum_current_combo.blockSignals(True) self.minimum_current_combo.setCurrentIndex(conf.minimum_current) self.minimum_current_combo.blockSignals(False) self.stallguard_threshold_value_spin.blockSignals(True) self.stallguard_threshold_value_spin.setValue(conf.stallguard_threshold_value) self.stallguard_threshold_value_spin.blockSignals(False) self.stallguard_mode_combo.blockSignals(True) self.stallguard_mode_combo.setCurrentIndex(conf.stallguard_mode) self.stallguard_mode_combo.blockSignals(False) def get_misc_configuration_async(self, conf): self.disable_short_to_ground_protection_checkbox.blockSignals(True) self.disable_short_to_ground_protection_checkbox.setChecked(conf.disable_short_to_ground_protection) self.disable_short_to_ground_protection_checkbox.blockSignals(False) self.synchronize_phase_frequency_spin.blockSignals(True) self.synchronize_phase_frequency_spin.setValue(conf.synchronize_phase_frequency) self.synchronize_phase_frequency_spin.blockSignals(False) def update_start(self): async_call(self.silent_stepper.get_max_velocity, None, self.get_max_velocity_async, self.increase_error_count) async_call(self.silent_stepper.get_speed_ramping, None, self.get_speed_ramping_async, self.increase_error_count) async_call(self.silent_stepper.is_enabled, None, self.is_enabled_async, self.increase_error_count) async_call(self.silent_stepper.get_step_configuration, None, self.get_step_configuration_async, self.increase_error_count) async_call(self.silent_stepper.get_basic_configuration, None, self.get_basic_configuration_async, self.increase_error_count) async_call(self.silent_stepper.get_spreadcycle_configuration, None, self.get_spreadcycle_configuration_async, self.increase_error_count) async_call(self.silent_stepper.get_stealth_configuration, None, self.get_stealth_configuration_async, self.increase_error_count) async_call(self.silent_stepper.get_coolstep_configuration, None, self.get_coolstep_configuration_async, self.increase_error_count) async_call(self.silent_stepper.get_misc_configuration, None, self.get_misc_configuration_async, self.increase_error_count) def update_data(self): async_call(self.silent_stepper.get_remaining_steps, None, self.remaining_steps_update, self.increase_error_count) async_call(self.silent_stepper.get_current_position, None, self.position_update, self.increase_error_count) async_call(self.silent_stepper.get_current_velocity, None, self.speedometer.set_velocity, self.increase_error_count) self.update_counter += 1 if self.update_counter % 10 == 0: async_call(self.silent_stepper.get_motor_current, None, self.maximum_current_update, self.increase_error_count) async_call(self.silent_stepper.get_stack_input_voltage, None, self.stack_input_voltage_update, self.increase_error_count) async_call(self.silent_stepper.get_external_input_voltage, None, self.external_input_voltage_update, self.increase_error_count) async_call(self.silent_stepper.get_minimum_voltage, None, self.minimum_voltage_update, self.increase_error_count) async_call(self.silent_stepper.get_driver_status, None, self.driver_status_update, self.increase_error_count) def velocity_changed(self, value): try: self.silent_stepper.set_max_velocity(value) except ip_connection.Error: return def acceleration_changed(self, value): dec = self.deceleration_spin.value() try: self.silent_stepper.set_speed_ramping(value, dec) except ip_connection.Error: return def deceleration_changed(self, value): acc = self.acceleration_slider.value() try: self.silent_stepper.set_speed_ramping(acc, value) except ip_connection.Error: return
class WeatherStation(QApplication): HOST = "localhost" PORT = 4223 ipcon = None lcd = None al = None al_v2 = None hum = None baro = None projects = [] active_project = None error_msg = None def __init__(self, args): super(QApplication, self).__init__(args) self.error_msg = QErrorMessage() self.ipcon = IPConnection() signal.signal(signal.SIGINT, self.exit_demo) signal.signal(signal.SIGTERM, self.exit_demo) timer = QTimer(self) timer.setSingleShot(True) timer.timeout.connect(self.connect) timer.start(1) self.lcd_timer = QTimer(self) self.lcd_timer.timeout.connect(self.mute_lcd) self.lcd_timer.start(10000) def exit_demo(self, signl=None, frme=None): try: self.ipcon.disconnect() self.timer.stop() self.tabs.destroy() except: pass sys.exit() def open_gui(self): self.main = MainWindow(self) self.main.setFixedSize(930, 530) self.main.setWindowIcon( QIcon(load_pixmap('starter_kit_weather_station_demo-icon.png'))) self.tabs = QTabWidget() widget = QWidget() layout = QVBoxLayout() layout.addWidget(self.tabs) widget.setLayout(layout) self.main.setCentralWidget(widget) self.projects.append(ProjectEnvDisplay(self.tabs, self)) self.projects.append(ProjectStatistics(self.tabs, self)) self.projects.append(ProjectXively(self.tabs, self)) self.tabs.addTab(self.projects[0], "Display Environment Measurements") self.tabs.addTab(self.projects[1], "Show Statistics with Button Control") self.tabs.addTab(self.projects[2], "Connect to Xively") self.active_project = self.projects[0] self.tabs.currentChanged.connect(self.tabChangedSlot) self.tabs.setCurrentIndex(1) self.main.setWindowTitle("Starter Kit: Weather Station Demo " + DEMO_VERSION) self.main.show() def connect(self): try: self.ipcon.connect(WeatherStation.HOST, WeatherStation.PORT) except Error as e: self.error_msg.showMessage('Connection Error: ' + str(e.description) + "\nBrickd installed and running?") return except socket.error as e: self.error_msg.showMessage('Socket error: ' + str(e) + "\nBrickd installed and running?") return self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE, self.cb_enumerate) self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED, self.cb_connected) try: self.ipcon.enumerate() except Error as e: self.error_msg.showMessage('Enumerate Error: ' + str(e.description)) return self.open_gui() def tabChangedSlot(self, tabIndex): if self.lcd is not None: self.lcd.clear_display() self.active_project = self.projects[tabIndex] def cb_illuminance(self, illuminance): for p in self.projects: p.update_illuminance(illuminance / 10.0) def cb_illuminance_v2(self, illuminance): for p in self.projects: p.update_illuminance(illuminance / 100.0) def cb_humidity(self, humidity): for p in self.projects: p.update_humidity(humidity / 10.0) def cb_air_pressure(self, air_pressure): for p in self.projects: p.update_air_pressure(air_pressure / 1000.0) try: temperature = self.baro.get_chip_temperature() except Error as e: print('Could not get temperature: ' + str(e.description)) return for p in self.projects: p.update_temperature(temperature / 100.0) def configure_custom_chars(self): c = [[0x00 for x in range(8)] for y in range(8)] c[0] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff] c[1] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff] c[2] = [0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff] c[3] = [0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff] c[4] = [0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff] c[5] = [0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] c[6] = [0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] c[7] = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] for i in range(len(c)): self.lcd.set_custom_character(i, c[i]) def cb_button_pressed(self, button): if self.lcd.is_backlight_on(): for p in self.projects: p.button_pressed(button) else: self.lcd.backlight_on() self.lcd_timer.start() def mute_lcd(self): self.lcd.backlight_off() def cb_enumerate(self, uid, connected_uid, position, hardware_version, firmware_version, device_identifier, enumeration_type): if enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED or \ enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE: if device_identifier == LCD20x4.DEVICE_IDENTIFIER: try: self.lcd = LCD20x4(uid, self.ipcon) self.lcd.clear_display() self.lcd.backlight_on() self.lcd.register_callback( self.lcd.CALLBACK_BUTTON_PRESSED, self.cb_button_pressed) self.configure_custom_chars() except Error as e: self.error_msg.showMessage('LCD 20x4 init failed: ' + str(e.description)) self.lcd = None elif device_identifier == AmbientLight.DEVICE_IDENTIFIER: try: self.al = AmbientLight(uid, self.ipcon) self.al.set_illuminance_callback_period(1000) self.al.register_callback(self.al.CALLBACK_ILLUMINANCE, self.cb_illuminance) except Error as e: self.error_msg.showMessage('Ambient Light init failed: ' + str(e.description)) self.al = None elif device_identifier == AmbientLightV2.DEVICE_IDENTIFIER: try: self.al_v2 = AmbientLightV2(uid, self.ipcon) self.al_v2.set_configuration( AmbientLightV2.ILLUMINANCE_RANGE_64000LUX, AmbientLightV2.INTEGRATION_TIME_200MS) self.al_v2.set_illuminance_callback_period(1000) self.al_v2.register_callback( self.al_v2.CALLBACK_ILLUMINANCE, self.cb_illuminance_v2) except Error as e: self.error_msg.showMessage( 'Ambient Light 2.0 init failed: ' + str(e.description)) self.al = None elif device_identifier == Humidity.DEVICE_IDENTIFIER: try: self.hum = Humidity(uid, self.ipcon) self.hum.set_humidity_callback_period(1000) self.hum.register_callback(self.hum.CALLBACK_HUMIDITY, self.cb_humidity) except Error as e: self.error_msg.showMessage('Humidity init failed: ' + str(e.description)) self.hum = None elif device_identifier == Barometer.DEVICE_IDENTIFIER: try: self.baro = Barometer(uid, self.ipcon) self.baro.set_air_pressure_callback_period(1000) self.baro.register_callback( self.baro.CALLBACK_AIR_PRESSURE, self.cb_air_pressure) except Error as e: self.error_msg.showMessage('Barometer init failed: ' + str(e.description)) self.baro = None def cb_connected(self, connected_reason): if connected_reason == IPConnection.CONNECT_REASON_AUTO_RECONNECT: while True: try: self.ipcon.enumerate() break except Error as e: self.error_msg.showMessage('Enumerate Error: ' + str(e.description)) time.sleep(1)
class SilentStepper(PluginBase, Ui_SilentStepper): qtcb_position_reached = pyqtSignal(int) qtcb_under_voltage = pyqtSignal(int) def __init__(self, *args): PluginBase.__init__(self, BrickSilentStepper, *args) self.setupUi(self) self.silent_stepper = self.device self.endis_all(False) self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_data) self.speedometer = SpeedoMeter() self.vertical_layout_right.insertWidget(5, self.speedometer) self.new_value = 0 self.update_counter = 0 self.full_brake_time = 0 self.qem = QErrorMessage(self) self.qem.setWindowTitle("Under Voltage") self.velocity_syncer = SliderSpinSyncer(self.velocity_slider, self.velocity_spin, self.velocity_changed) self.acceleration_syncer = SliderSpinSyncer(self.acceleration_slider, self.acceleration_spin, self.acceleration_changed) self.deceleration_syncer = SliderSpinSyncer(self.deceleration_slider, self.deceleration_spin, self.deceleration_changed) self.enable_checkbox.stateChanged.connect(self.enable_state_changed) self.forward_button.clicked.connect(self.forward_clicked) self.stop_button.clicked.connect(self.stop_clicked) self.full_brake_button.clicked.connect(self.full_brake_clicked) self.backward_button.clicked.connect(self.backward_clicked) self.to_button.clicked.connect(self.to_button_clicked) self.steps_button.clicked.connect(self.steps_button_clicked) self.motor_current_button.clicked.connect(self.motor_current_button_clicked) self.minimum_motor_voltage_button.clicked.connect(self.minimum_motor_voltage_button_clicked) self.qtcb_position_reached.connect(self.cb_position_reached) self.silent_stepper.register_callback(self.silent_stepper.CALLBACK_POSITION_REACHED, self.qtcb_position_reached.emit) self.qtcb_under_voltage.connect(self.cb_under_voltage) self.silent_stepper.register_callback(self.silent_stepper.CALLBACK_UNDER_VOLTAGE, self.qtcb_under_voltage.emit) # Step Configuration self.step_resolution_dropbox.currentIndexChanged.connect(self.step_configuration_changed) self.interpolate_checkbox.stateChanged.connect(self.step_configuration_changed) # Basic Configuration self.standstill_current_spin.valueChanged.connect(self.basic_configuration_changed) self.motor_run_current_spin.valueChanged.connect(self.basic_configuration_changed) self.standstill_delay_time_spin.valueChanged.connect(self.basic_configuration_changed) self.power_down_time_spin.valueChanged.connect(self.basic_configuration_changed) self.stealth_threshold_spin.valueChanged.connect(self.basic_configuration_changed) self.coolstep_threashold_spin.valueChanged.connect(self.basic_configuration_changed) self.classic_threshold_spin.valueChanged.connect(self.basic_configuration_changed) self.high_velocity_chopper_mode_checkbox.stateChanged.connect(self.basic_configuration_changed) # Spreadcycle Configuration self.slow_decay_duration_spin.valueChanged.connect(self.spreadcycle_configuration_changed) self.enable_random_slow_decay_checkbox.stateChanged.connect(self.spreadcycle_configuration_changed) self.fast_decay_duration_spin.valueChanged.connect(self.spreadcycle_configuration_changed) self.hysteresis_start_value_spin.valueChanged.connect(self.spreadcycle_configuration_changed) self.hysteresis_end_value_spin.valueChanged.connect(self.spreadcycle_configuration_changed) self.sinewave_offset_spin.valueChanged.connect(self.spreadcycle_configuration_changed) self.chopper_mode_combo.currentIndexChanged.connect(self.spreadcycle_configuration_changed) self.comperator_blank_time_combo.currentIndexChanged.connect(self.spreadcycle_configuration_changed) self.fast_decay_without_comperator_checkbox.stateChanged.connect(self.spreadcycle_configuration_changed) # Stealth Configuration self.enable_stealth_checkbox.stateChanged.connect(self.stealth_configuration_changed) self.amplitude_spin.valueChanged.connect(self.stealth_configuration_changed) self.gradient_spin.valueChanged.connect(self.stealth_configuration_changed) self.enable_autoscale_checkbox.stateChanged.connect(self.stealth_configuration_changed) self.force_symmetric_checkbox.stateChanged.connect(self.stealth_configuration_changed) self.freewheel_mode_combo.currentIndexChanged.connect(self.stealth_configuration_changed) # Coolstep Configuration self.minimum_stallguard_value_spin.valueChanged.connect(self.coolstep_configuration_changed) self.maximum_stallguard_value_spin.valueChanged.connect(self.coolstep_configuration_changed) self.current_up_step_width_combo.currentIndexChanged.connect(self.coolstep_configuration_changed) self.current_down_step_width_combo.currentIndexChanged.connect(self.coolstep_configuration_changed) self.minimum_current_combo.currentIndexChanged.connect(self.coolstep_configuration_changed) self.stallguard_threshold_value_spin.valueChanged.connect(self.coolstep_configuration_changed) self.stallguard_mode_combo.currentIndexChanged.connect(self.coolstep_configuration_changed) # Misc Configuration self.disable_short_to_ground_protection_checkbox.stateChanged.connect(self.misc_configuration_changed) self.synchronize_phase_frequency_spin.valueChanged.connect(self.misc_configuration_changed) self.ste = 0 self.pos = 0 self.current_velocity = 0 self.cur = 0 self.sv = 0 self.ev = 0 self.mv = 0 self.mod = 0 reset = QAction('Reset', self) reset.triggered.connect(lambda: self.silent_stepper.reset()) self.set_actions(reset) def start(self): self.update_timer.start(100) self.update_start() def stop(self): self.update_timer.stop() def destroy(self): pass def get_url_part(self): return 'silent_stepper' @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickSilentStepper.DEVICE_IDENTIFIER def cb_position_reached(self, position): self.position_update(position) self.endis_all(True) def disable_list(self, button_list): for button in button_list: button.setEnabled(False) def endis_all(self, value): self.forward_button.setEnabled(value) self.stop_button.setEnabled(value) self.backward_button.setEnabled(value) self.to_button.setEnabled(value) self.steps_button.setEnabled(value) self.full_brake_button.setEnabled(value) def step_configuration_changed(self, _): step_resolution = self.step_resolution_dropbox.currentIndex() interpolation = self.interpolate_checkbox.isChecked() try: self.silent_stepper.set_step_configuration(step_resolution, interpolation) except ip_connection.Error: return def basic_configuration_changed(self, _): standstill_current = self.standstill_current_spin.value() motor_run_current = self.motor_run_current_spin.value() standstill_delay_time = self.standstill_delay_time_spin.value() power_down_time = self.power_down_time_spin.value() stealth_threshold = self.stealth_threshold_spin.value() coolstep_threshold = self.coolstep_threashold_spin.value() classic_threshold = self.classic_threshold_spin.value() high_velocity_chopper_mode = self.high_velocity_chopper_mode_checkbox.isChecked() try: self.silent_stepper.set_basic_configuration(standstill_current, motor_run_current, standstill_delay_time, power_down_time, stealth_threshold, coolstep_threshold, classic_threshold, high_velocity_chopper_mode) except ip_connection.Error: return def spreadcycle_configuration_changed(self, _): slow_decay_duration = self.slow_decay_duration_spin.value() enable_random_slow_decay = self.enable_random_slow_decay_checkbox.isChecked() fast_decay_duration = self.fast_decay_duration_spin.value() hysteresis_start_value = self.hysteresis_start_value_spin.value() hysteresis_end_value = self.hysteresis_end_value_spin.value() sinewave_offset = self.sinewave_offset_spin.value() chopper_mode = self.chopper_mode_combo.currentIndex() comperator_blank_time = self.comperator_blank_time_combo.currentIndex() fast_decay_without_comperator = self.fast_decay_without_comperator_checkbox.isChecked() try: self.silent_stepper.set_spreadcycle_configuration(slow_decay_duration, enable_random_slow_decay, fast_decay_duration, hysteresis_start_value, hysteresis_end_value, sinewave_offset, chopper_mode, comperator_blank_time, fast_decay_without_comperator) except ip_connection.Error: return def stealth_configuration_changed(self, _): enable_stealth = self.enable_stealth_checkbox.isChecked() amplitude = self.amplitude_spin.value() gradient = self.gradient_spin.value() enable_autoscale = self.enable_autoscale_checkbox.isChecked() force_symmetric = self.force_symmetric_checkbox.isChecked() freewheel_mode = self.freewheel_mode_combo.currentIndex() try: self.silent_stepper.set_stealth_configuration(enable_stealth, amplitude, gradient, enable_autoscale, force_symmetric, freewheel_mode) except ip_connection.Error: return def coolstep_configuration_changed(self, _): minimum_stallguard_value = self.minimum_stallguard_value_spin.value() maximum_stallguard_value = self.maximum_stallguard_value_spin.value() current_up_step_width = self.current_up_step_width_combo.currentIndex() current_down_step_width = self.current_down_step_width_combo.currentIndex() minimum_current = self.minimum_current_combo.currentIndex() stallguard_threshold_value = self.stallguard_threshold_value_spin.value() stallguard_mode = self.stallguard_mode_combo.currentIndex() try: self.silent_stepper.set_coolstep_configuration(minimum_stallguard_value, maximum_stallguard_value, current_up_step_width, current_down_step_width, minimum_current, stallguard_threshold_value, stallguard_mode) except ip_connection.Error: return def misc_configuration_changed(self, _): disable_short_to_ground_protection = self.disable_short_to_ground_protection_checkbox.isChecked() synchronize_phase_frequency = self.synchronize_phase_frequency_spin.value() try: self.silent_stepper.set_misc_configuration(disable_short_to_ground_protection, synchronize_phase_frequency) except ip_connection.Error: return def forward_clicked(self): try: self.silent_stepper.drive_forward() except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button]) def backward_clicked(self): try: self.silent_stepper.drive_backward() except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button]) def stop_clicked(self): try: self.silent_stepper.stop() except ip_connection.Error: return self.endis_all(True) def full_brake_clicked(self): try: self.silent_stepper.full_brake() except ip_connection.Error: return self.endis_all(True) def to_button_clicked(self): drive_to = self.to_spin.value() try: self.silent_stepper.set_target_position(drive_to) except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button, self.forward_button, self.backward_button]) def steps_button_clicked(self): drive_steps = self.steps_spin.value() try: self.silent_stepper.set_steps(drive_steps) except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button, self.forward_button, self.backward_button]) def motor_current_button_clicked(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(0) qid.setIntMaximum(2500) qid.setIntStep(100) async_call(self.silent_stepper.get_motor_current, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.motor_current_selected) qid.setLabelText("Choose motor current in mA.") qid.open() def minimum_motor_voltage_button_clicked(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(0) qid.setIntMaximum(40000) qid.setIntStep(100) async_call(self.silent_stepper.get_minimum_voltage, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.minimum_motor_voltage_selected) qid.setLabelText("Choose minimum motor voltage in mV.") qid.open() def motor_current_selected(self, value): try: self.silent_stepper.set_motor_current(value) except ip_connection.Error: return def minimum_motor_voltage_selected(self, value): try: self.silent_stepper.set_minimum_voltage(value) except ip_connection.Error: return def cb_under_voltage(self, ov): mv_str = self.minimum_voltage_label.text() ov_str = "%gV" % round(ov/1000.0, 1) if not self.qem.isVisible(): self.qem.showMessage("Under Voltage: Output Voltage of " + ov_str + " is below minimum voltage of " + mv_str, "SilentStepper_UnderVoltage") def enable_state_changed(self, state): try: if state == Qt.Checked: self.endis_all(True) self.silent_stepper.enable() elif state == Qt.Unchecked: self.endis_all(False) self.silent_stepper.disable() except ip_connection.Error: return def stack_input_voltage_update(self, sv): sv_str = "%gV" % round(sv/1000.0, 1) self.stack_voltage_label.setText(sv_str) def external_input_voltage_update(self, ev): ev_str = "%gV" % round(ev/1000.0, 1) self.external_voltage_label.setText(ev_str) def minimum_voltage_update(self, mv): mv_str = "%gV" % round(mv/1000.0, 1) self.minimum_voltage_label.setText(mv_str) def maximum_current_update(self, cur): cur_str = "%gA" % round(cur/1000.0, 1) self.maximum_current_label.setText(cur_str) def position_update(self, pos): pos_str = "%d" % pos self.position_label.setText(pos_str) def remaining_steps_update(self, ste): ste_str = "%d" % ste self.remaining_steps_label.setText(ste_str) def driver_status_update(self, update): if update.open_load == 0: self.status_open_load.setText('No') elif update.open_load == 1: self.status_open_load.setText('Phase A') elif update.open_load == 2: self.status_open_load.setText('Phase B') elif update.open_load == 3: self.status_open_load.setText('Phase A and B') else: self.status_open_load.setText('Unkown') if update.short_to_ground == 0: self.status_short_to_ground.setText('No') elif update.short_to_ground == 1: self.status_short_to_ground.setText('Phase A') elif update.short_to_ground == 2: self.status_short_to_ground.setText('Phase B') elif update.short_to_ground == 3: self.status_short_to_ground.setText('Phase A and B') else: self.status_short_to_ground.setText('Unkown') if update.over_temperature == 0: self.status_over_temperature.setText('No') elif update.over_temperature == 1: self.status_over_temperature.setText('<font color=yellow>Warning</font>') elif update.over_temperature == 2: self.status_over_temperature.setText('<font color=red>Limit</font>') if update.motor_stalled: self.status_motor_stalled.setText('Yes') else: self.status_motor_stalled.setText('No') self.status_actual_motor_current.setText(str(update.actual_motor_current)) if update.full_step_active: self.status_full_step_active.setText('Yes') else: self.status_full_step_active.setText('No') self.status_stallguard_result.setText(str(update.stallguard_result)) self.status_stealth_voltage_amplitude.setText(str(update.stealth_voltage_amplitude)) def get_max_velocity_async(self, velocity): if not self.velocity_slider.isSliderDown(): if velocity != self.velocity_slider.sliderPosition(): self.velocity_slider.setSliderPosition(velocity) self.velocity_spin.setValue(velocity) def get_speed_ramping_async(self, ramp): acc, dec = ramp if not self.acceleration_slider.isSliderDown() and \ not self.deceleration_slider.isSliderDown(): if acc != self.acceleration_slider.sliderPosition(): self.acceleration_slider.setSliderPosition(acc) self.acceleration_spin.setValue(acc) if dec != self.deceleration_slider.sliderPosition(): self.deceleration_slider.setSliderPosition(dec) self.deceleration_spin.setValue(dec) def is_enabled_async(self, enabled): if enabled: if not self.enable_checkbox.isChecked(): self.endis_all(True) self.enable_checkbox.blockSignals(True) self.enable_checkbox.setChecked(True) self.enable_checkbox.blockSignals(False) else: if self.enable_checkbox.isChecked(): self.endis_all(False) self.enable_checkbox.blockSignals(True) self.enable_checkbox.setChecked(False) self.enable_checkbox.blockSignals(False) def get_step_configuration_async(self, conf): self.step_resolution_dropbox.blockSignals(True) self.step_resolution_dropbox.setCurrentIndex(conf.step_resolution) self.step_resolution_dropbox.blockSignals(False) self.interpolate_checkbox.blockSignals(True) self.interpolate_checkbox.setChecked(conf.interpolation) self.interpolate_checkbox.blockSignals(False) def get_basic_configuration_async(self, conf): self.standstill_current_spin.blockSignals(True) self.standstill_current_spin.setValue(conf.standstill_current) self.standstill_current_spin.blockSignals(False) self.motor_run_current_spin.blockSignals(True) self.motor_run_current_spin.setValue(conf.motor_run_current) self.motor_run_current_spin.blockSignals(False) self.standstill_delay_time_spin.blockSignals(True) self.standstill_delay_time_spin.setValue(conf.standstill_delay_time) self.standstill_delay_time_spin.blockSignals(False) self.power_down_time_spin.blockSignals(True) self.power_down_time_spin.setValue(conf.power_down_time) self.power_down_time_spin.blockSignals(False) self.stealth_threshold_spin.blockSignals(True) self.stealth_threshold_spin.setValue(conf.stealth_threshold) self.stealth_threshold_spin.blockSignals(False) self.coolstep_threashold_spin.blockSignals(True) self.coolstep_threashold_spin.setValue(conf.coolstep_threshold) self.coolstep_threashold_spin.blockSignals(False) self.classic_threshold_spin.blockSignals(True) self.classic_threshold_spin.setValue(conf.classic_threshold) self.classic_threshold_spin.blockSignals(False) self.high_velocity_chopper_mode_checkbox.blockSignals(True) self.high_velocity_chopper_mode_checkbox.setChecked(conf.high_velocity_chopper_mode) self.high_velocity_chopper_mode_checkbox.blockSignals(False) def get_spreadcycle_configuration_async(self, conf): self.slow_decay_duration_spin.blockSignals(True) self.slow_decay_duration_spin.setValue(conf.slow_decay_duration) self.slow_decay_duration_spin.blockSignals(False) self.enable_random_slow_decay_checkbox.blockSignals(True) self.enable_random_slow_decay_checkbox.setChecked(conf.enable_random_slow_decay) self.enable_random_slow_decay_checkbox.blockSignals(False) self.fast_decay_duration_spin.blockSignals(True) self.fast_decay_duration_spin.setValue(conf.fast_decay_duration) self.fast_decay_duration_spin.blockSignals(False) self.hysteresis_start_value_spin.blockSignals(True) self.hysteresis_start_value_spin.setValue(conf.hysteresis_start_value) self.hysteresis_start_value_spin.blockSignals(False) self.hysteresis_end_value_spin.blockSignals(True) self.hysteresis_end_value_spin.setValue(conf.hysteresis_end_value) self.hysteresis_end_value_spin.blockSignals(False) self.sinewave_offset_spin.blockSignals(True) self.sinewave_offset_spin.setValue(conf.sinewave_offset) self.sinewave_offset_spin.blockSignals(False) self.chopper_mode_combo.blockSignals(True) self.chopper_mode_combo.setCurrentIndex(conf.chopper_mode) self.chopper_mode_combo.blockSignals(False) self.standstill_current_spin.blockSignals(True) self.comperator_blank_time_combo.setCurrentIndex(conf.comperator_blank_time) self.standstill_current_spin.blockSignals(False) self.fast_decay_without_comperator_checkbox.blockSignals(True) self.fast_decay_without_comperator_checkbox.setChecked(conf.fast_decay_without_comperator) self.fast_decay_without_comperator_checkbox.blockSignals(False) def get_stealth_configuration_async(self, conf): self.enable_stealth_checkbox.blockSignals(True) self.enable_stealth_checkbox.setChecked(conf.enable_stealth) self.enable_stealth_checkbox.blockSignals(False) self.amplitude_spin.blockSignals(True) self.amplitude_spin.setValue(conf.amplitude) self.amplitude_spin.blockSignals(False) self.gradient_spin.blockSignals(True) self.gradient_spin.setValue(conf.gradient) self.gradient_spin.blockSignals(False) self.enable_autoscale_checkbox.blockSignals(True) self.enable_autoscale_checkbox.setChecked(conf.enable_autoscale) self.enable_autoscale_checkbox.blockSignals(False) self.force_symmetric_checkbox.blockSignals(True) self.force_symmetric_checkbox.setChecked(conf.force_symmetric) self.force_symmetric_checkbox.blockSignals(False) self.freewheel_mode_combo.blockSignals(True) self.freewheel_mode_combo.setCurrentIndex(conf.freewheel_mode) self.freewheel_mode_combo.blockSignals(False) def get_coolstep_configuration_async(self, conf): self.minimum_stallguard_value_spin.blockSignals(True) self.minimum_stallguard_value_spin.setValue(conf.minimum_stallguard_value) self.minimum_stallguard_value_spin.blockSignals(False) self.maximum_stallguard_value_spin.blockSignals(True) self.maximum_stallguard_value_spin.setValue(conf.maximum_stallguard_value) self.maximum_stallguard_value_spin.blockSignals(False) self.current_up_step_width_combo.blockSignals(True) self.current_up_step_width_combo.setCurrentIndex(conf.current_up_step_width) self.current_up_step_width_combo.blockSignals(False) self.current_down_step_width_combo.blockSignals(True) self.current_down_step_width_combo.setCurrentIndex(conf.current_down_step_width) self.current_down_step_width_combo.blockSignals(False) self.minimum_current_combo.blockSignals(True) self.minimum_current_combo.setCurrentIndex(conf.minimum_current) self.minimum_current_combo.blockSignals(False) self.stallguard_threshold_value_spin.blockSignals(True) self.stallguard_threshold_value_spin.setValue(conf.stallguard_threshold_value) self.stallguard_threshold_value_spin.blockSignals(False) self.stallguard_mode_combo.blockSignals(True) self.stallguard_mode_combo.setCurrentIndex(conf.stallguard_mode) self.stallguard_mode_combo.blockSignals(False) def get_misc_configuration_async(self, conf): self.disable_short_to_ground_protection_checkbox.blockSignals(True) self.disable_short_to_ground_protection_checkbox.setChecked(conf.disable_short_to_ground_protection) self.disable_short_to_ground_protection_checkbox.blockSignals(False) self.synchronize_phase_frequency_spin.blockSignals(True) self.synchronize_phase_frequency_spin.setValue(conf.synchronize_phase_frequency) self.synchronize_phase_frequency_spin.blockSignals(False) def update_start(self): async_call(self.silent_stepper.get_max_velocity, None, self.get_max_velocity_async, self.increase_error_count) async_call(self.silent_stepper.get_speed_ramping, None, self.get_speed_ramping_async, self.increase_error_count) async_call(self.silent_stepper.is_enabled, None, self.is_enabled_async, self.increase_error_count) async_call(self.silent_stepper.get_step_configuration, None, self.get_step_configuration_async, self.increase_error_count) async_call(self.silent_stepper.get_basic_configuration, None, self.get_basic_configuration_async, self.increase_error_count) async_call(self.silent_stepper.get_spreadcycle_configuration, None, self.get_spreadcycle_configuration_async, self.increase_error_count) async_call(self.silent_stepper.get_stealth_configuration, None, self.get_stealth_configuration_async, self.increase_error_count) async_call(self.silent_stepper.get_coolstep_configuration, None, self.get_coolstep_configuration_async, self.increase_error_count) async_call(self.silent_stepper.get_misc_configuration, None, self.get_misc_configuration_async, self.increase_error_count) def update_data(self): async_call(self.silent_stepper.get_remaining_steps, None, self.remaining_steps_update, self.increase_error_count) async_call(self.silent_stepper.get_current_position, None, self.position_update, self.increase_error_count) async_call(self.silent_stepper.get_current_velocity, None, self.speedometer.set_velocity, self.increase_error_count) self.update_counter += 1 if self.update_counter % 10 == 0: async_call(self.silent_stepper.get_motor_current, None, self.maximum_current_update, self.increase_error_count) async_call(self.silent_stepper.get_stack_input_voltage, None, self.stack_input_voltage_update, self.increase_error_count) async_call(self.silent_stepper.get_external_input_voltage, None, self.external_input_voltage_update, self.increase_error_count) async_call(self.silent_stepper.get_minimum_voltage, None, self.minimum_voltage_update, self.increase_error_count) async_call(self.silent_stepper.get_driver_status, None, self.driver_status_update, self.increase_error_count) def velocity_changed(self, value): try: self.silent_stepper.set_max_velocity(value) except ip_connection.Error: return def acceleration_changed(self, value): dec = self.deceleration_spin.value() try: self.silent_stepper.set_speed_ramping(value, dec) except ip_connection.Error: return def deceleration_changed(self, value): acc = self.acceleration_slider.value() try: self.silent_stepper.set_speed_ramping(acc, value) except ip_connection.Error: return
class Stepper(PluginBase, Ui_Stepper): qtcb_position_reached = pyqtSignal(int) qtcb_under_voltage = pyqtSignal(int) def __init__(self, *args): PluginBase.__init__(self, BrickStepper, *args) self.setupUi(self) self.stepper = self.device self.endis_all(False) self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_data) self.new_value = 0 self.update_counter = 0 self.full_brake_time = 0 self.qem = QErrorMessage(self) self.qem.setWindowTitle("Under Voltage") self.decay_widget.hide() self.setting_sync_rect_checkbox = False self.velocity_syncer = SliderSpinSyncer(self.velocity_slider, self.velocity_spin, self.velocity_changed) self.acceleration_syncer = SliderSpinSyncer(self.acceleration_slider, self.acceleration_spin, self.acceleration_changed) self.deceleration_syncer = SliderSpinSyncer(self.deceleration_slider, self.deceleration_spin, self.deceleration_changed) self.decay_syncer = SliderSpinSyncer(self.decay_slider, self.decay_spin, self.decay_changed) self.enable_checkbox.toggled.connect(self.enable_toggled) self.forward_button.clicked.connect(self.forward_clicked) self.stop_button.clicked.connect(self.stop_clicked) self.full_brake_button.clicked.connect(self.full_brake_clicked) self.backward_button.clicked.connect(self.backward_clicked) self.to_button.clicked.connect(self.to_button_clicked) self.steps_button.clicked.connect(self.steps_button_clicked) self.motor_current_button.clicked.connect( self.motor_current_button_clicked) self.minimum_motor_voltage_button.clicked.connect( self.minimum_motor_voltage_button_clicked) self.sync_rect_checkbox.toggled.connect(self.sync_rect_toggled) self.mode_dropbox.currentIndexChanged.connect(self.mode_changed) self.qtcb_position_reached.connect(self.cb_position_reached) self.stepper.register_callback(self.stepper.CALLBACK_POSITION_REACHED, self.qtcb_position_reached.emit) self.qtcb_under_voltage.connect(self.cb_under_voltage) self.stepper.register_callback(self.stepper.CALLBACK_UNDER_VOLTAGE, self.qtcb_under_voltage.emit) self.ste = 0 self.pos = 0 self.current_velocity = 0 self.cur = 0 self.sv = 0 self.ev = 0 self.mv = 0 self.mod = 0 if self.firmware_version >= (2, 3, 1): self.status_led_action = QAction('Status LED', self) self.status_led_action.setCheckable(True) self.status_led_action.toggled.connect( lambda checked: self.stepper.enable_status_led() if checked else self.stepper.disable_status_led()) self.set_configs([(0, None, [self.status_led_action])]) else: self.status_led_action = None if self.firmware_version >= (1, 1, 4): reset = QAction('Reset', self) reset.triggered.connect(lambda: self.stepper.reset()) self.set_actions([(0, None, [reset])]) def start(self): if self.firmware_version >= (2, 3, 1): async_call(self.stepper.is_status_led_enabled, None, self.status_led_action.setChecked, self.increase_error_count) self.update_timer.start(100) self.update_start() def stop(self): self.update_timer.stop() def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickStepper.DEVICE_IDENTIFIER def cb_position_reached(self, position): self.position_update(position) self.endis_all(True) def disable_list(self, button_list): for button in button_list: button.setEnabled(False) def endis_all(self, value): self.forward_button.setEnabled(value) self.stop_button.setEnabled(value) self.backward_button.setEnabled(value) self.to_button.setEnabled(value) self.steps_button.setEnabled(value) self.full_brake_button.setEnabled(value) def mode_changed(self, index): try: self.stepper.set_step_mode(1 << index) self.mod = 1 << index except ip_connection.Error: return def forward_clicked(self): try: self.stepper.drive_forward() except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button]) def backward_clicked(self): try: self.stepper.drive_backward() except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button]) def stop_clicked(self): try: self.stepper.stop() except ip_connection.Error: return self.endis_all(True) def full_brake_clicked(self): try: self.stepper.full_brake() except ip_connection.Error: return self.endis_all(True) def to_button_clicked(self): drive_to = self.to_spin.value() try: self.stepper.set_target_position(drive_to) except ip_connection.Error: return self.disable_list([ self.to_button, self.steps_button, self.forward_button, self.backward_button ]) def steps_button_clicked(self): drive_steps = self.steps_spin.value() try: self.stepper.set_steps(drive_steps) except ip_connection.Error: return self.disable_list([ self.to_button, self.steps_button, self.forward_button, self.backward_button ]) def motor_current_button_clicked(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(0) qid.setIntMaximum(2500) qid.setIntStep(100) async_call(self.stepper.get_motor_current, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.motor_current_selected) qid.setLabelText("Choose motor current in mA.") # "<font color=red>Setting this too high can destroy your Motor.</font>") qid.open() def minimum_motor_voltage_button_clicked(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(0) qid.setIntMaximum(40000) qid.setIntStep(100) async_call(self.stepper.get_minimum_voltage, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.minimum_motor_voltage_selected) qid.setLabelText("Choose minimum motor voltage in mV.") qid.open() def motor_current_selected(self, value): try: self.stepper.set_motor_current(value) except ip_connection.Error: return def minimum_motor_voltage_selected(self, value): try: self.stepper.set_minimum_voltage(value) except ip_connection.Error: return def cb_under_voltage(self, ov): mv_str = self.minimum_voltage_label.text() ov_str = "%gV" % round(ov / 1000.0, 1) if not self.qem.isVisible(): self.qem.showMessage( "Under Voltage: Output Voltage of " + ov_str + " is below minimum voltage of " + mv_str, "Stepper_UnderVoltage") def enable_toggled(self, checked): try: if checked: if not self.stepper.is_enabled(): self.endis_all(True) self.stepper.enable() else: if self.stepper.is_enabled(): self.endis_all(False) self.stepper.disable() except ip_connection.Error: return def sync_rect_toggled(self, checked): if not self.setting_sync_rect_checkbox and checked: rc = QMessageBox.warning( get_main_window(), 'Synchronous Rectification', 'If you want to use high speeds (> 10000 steps/s) for a large stepper motor with a ' + 'large inductivity we strongly suggest that you do not enable synchronous rectification. ' + 'Otherwise the Brick may not be able to cope with the load and overheat.', QMessageBox.Ok | QMessageBox.Cancel) if rc != QMessageBox.Ok: self.sync_rect_checkbox.setChecked(False) return try: self.stepper.set_sync_rect(checked) except ip_connection.Error: return self.decay_widget.setVisible(checked) def stack_input_voltage_update(self, sv): sv_str = "%gV" % round(sv / 1000.0, 1) self.stack_voltage_label.setText(sv_str) def external_input_voltage_update(self, ev): ev_str = "%gV" % round(ev / 1000.0, 1) self.external_voltage_label.setText(ev_str) def minimum_voltage_update(self, mv): mv_str = "%gV" % round(mv / 1000.0, 1) self.minimum_voltage_label.setText(mv_str) def maximum_current_update(self, cur): cur_str = "%gA" % round(cur / 1000.0, 1) self.maximum_current_label.setText(cur_str) def position_update(self, pos): pos_str = "%d" % pos self.position_label.setText(pos_str) def remaining_steps_update(self, ste): ste_str = "%d" % ste self.remaining_steps_label.setText(ste_str) def current_velocity_update(self, velocity): velocity_str = "%d" % velocity self.current_velocity_label.setText(velocity_str) self.speedometer.set_velocity(velocity) def mode_update(self, mod): if mod == 8: index = 3 elif mod == 4: index = 2 elif mod == 2: index = 1 else: index = 0 self.mode_dropbox.setCurrentIndex(index) def get_max_velocity_async(self, velocity): if not self.velocity_slider.isSliderDown(): if velocity != self.velocity_slider.sliderPosition(): self.velocity_slider.setSliderPosition(velocity) self.velocity_spin.setValue(velocity) def get_speed_ramping_async(self, ramp): acc, dec = ramp if not self.acceleration_slider.isSliderDown() and \ not self.deceleration_slider.isSliderDown(): if acc != self.acceleration_slider.sliderPosition(): self.acceleration_slider.setSliderPosition(acc) self.acceleration_spin.setValue(acc) if dec != self.deceleration_slider.sliderPosition(): self.deceleration_slider.setSliderPosition(dec) self.deceleration_spin.setValue(dec) def get_decay_async(self, decay): if not self.decay_slider.isSliderDown(): if decay != self.decay_slider.sliderPosition(): self.decay_slider.setSliderPosition(decay) self.decay_spin.setValue(decay) def is_enabled_async(self, enabled): if enabled: if not self.enable_checkbox.isChecked(): self.endis_all(True) self.enable_checkbox.setChecked(True) else: if self.enable_checkbox.isChecked(): self.endis_all(False) self.enable_checkbox.setChecked(False) def is_sync_rect_async(self, sync_rect): self.setting_sync_rect_checkbox = True self.sync_rect_checkbox.setChecked(sync_rect) self.setting_sync_rect_checkbox = False def update_start(self): async_call(self.stepper.get_max_velocity, None, self.get_max_velocity_async, self.increase_error_count) async_call(self.stepper.get_speed_ramping, None, self.get_speed_ramping_async, self.increase_error_count) async_call(self.stepper.get_decay, None, self.get_decay_async, self.increase_error_count) async_call(self.stepper.is_enabled, None, self.is_enabled_async, self.increase_error_count) async_call(self.stepper.is_sync_rect, None, self.is_sync_rect_async, self.increase_error_count) def update_data(self): async_call(self.stepper.get_remaining_steps, None, self.remaining_steps_update, self.increase_error_count) async_call(self.stepper.get_current_position, None, self.position_update, self.increase_error_count) async_call(self.stepper.get_current_velocity, None, self.current_velocity_update, self.increase_error_count) self.update_counter += 1 if self.update_counter % 10 == 0: async_call(self.stepper.get_motor_current, None, self.maximum_current_update, self.increase_error_count) async_call(self.stepper.get_stack_input_voltage, None, self.stack_input_voltage_update, self.increase_error_count) async_call(self.stepper.get_external_input_voltage, None, self.external_input_voltage_update, self.increase_error_count) async_call(self.stepper.get_minimum_voltage, None, self.minimum_voltage_update, self.increase_error_count) async_call(self.stepper.get_step_mode, None, self.mode_update, self.increase_error_count) def velocity_changed(self, value): try: self.stepper.set_max_velocity(value) except ip_connection.Error: return def acceleration_changed(self, value): dec = self.deceleration_spin.value() try: self.stepper.set_speed_ramping(value, dec) except ip_connection.Error: return def deceleration_changed(self, value): acc = self.acceleration_slider.value() try: self.stepper.set_speed_ramping(acc, value) except ip_connection.Error: return def decay_changed(self, value): try: self.stepper.set_decay(value) except ip_connection.Error: return
listener = create_listener() except socket.error: # Good si is correct (on UNIX) otherinstance = True else: # On windows only singleinstance can be trusted otherinstance = True if iswindows else False if not otherinstance and not opts.shutdown_running_calibre: return run_gui(opts, args, listener, app, gui_debug=gui_debug) communicate(opts, args) return 0 if __name__ == '__main__': try: sys.exit(main()) except Exception as err: if not iswindows: raise tb = traceback.format_exc() from PyQt4.QtGui import QErrorMessage logfile = os.path.join(os.path.expanduser('~'), 'calibre.log') if os.path.exists(logfile): log = open(logfile).read().decode('utf-8', 'ignore') d = QErrorMessage() d.showMessage( ('<b>Error:</b>%s<br><b>Traceback:</b><br>' '%s<b>Log:</b><br>%s') % (unicode(err), unicode(tb).replace( '\n', '<br>'), log.replace('\n', '<br>')))
class MainWindow(QMainWindow, Ui_MainWindow): """The Main window of Luma. """ logger = logging.getLogger(__name__) languages = {} translator = None languageHandler = None currentLanguage = '' def __init__(self, parent=None): """The constructor sets up the MainWindow widget, and connects all necessary signals and slots """ super(MainWindow, self).__init__(parent) self.setupUi(self) # We store the window size to make sure the previous window size # is restored when leaving fullscreen mode. This varible is used # in the toggleFullscreen slot. self.__tmpWinSize = self.size() self.eventFilter = LumaEventFilter(self) self.mainTabs.installEventFilter(self.eventFilter) self.translator = QTranslator() self.languageHandler = LanguageHandler() self.languages = self.languageHandler.availableLanguages #self.__createPluginToolBar() self.__createLoggerWidget() self.__loadSettings() self.__createLanguageOptions() self.setStatusBar(self.statusBar) self.mainTabs.setTabsClosable(True) self.mainTabs.setContextMenuPolicy(Qt.CustomContextMenu) self.mainTabs.customContextMenuRequested.connect( self.__mainTabsContextMenu) self.defaultTabStyle = '' self.lumaHeadStyle = 'background: url(:/icons/luma-gray);\n' + \ 'background-position: bottom right;\n' + \ 'background-attachment: fixed;\n' + \ 'background-repeat: no-repeat;' #Sets up pluginWidget #self in parameter is used to call pluginSelected here... self.pluginWidget = PluginListWidget(self) self.showPlugins() self.welcomeTab = WelcomeTab() self.welcomeTab.textBrowser.setStyleSheet(self.lumaHeadStyle) #This value comes from __loadSettings() #Its a checkbox set in WelcomeTab if self.showWelcomeSettings == 2: self.showWelcome() else: # Let's do some styling of the tab widget when no tabs are opened if self.mainTabs.currentIndex() == -1: self.__setTabWidgetStyle(self.lumaHeadStyle) self.actionShowWelcomeTab.setEnabled(True) self.serversChangedMessage = QErrorMessage(self) def __mainTabsContextMenu(self, pos): menu = QMenu() if self.mainTabs.count() > 0: return # The menu is displayed even when the rightclick is not # done over the actual tabs so to avoid confusion the # function is disabled entirey #menu.addAction(QApplication.translate( # "MainWindow", "Close all plugin-tabs"), self.tabCloseAll) else: # If there's no tabs, offer to display the pluginlist menu.addAction(self.actionShowPluginList) menu.exec_(self.mainTabs.mapToGlobal(pos)) def __createPluginToolBar(self): """Creates the pluign toolbar. """ self.pluginToolBar = PluginToolBar(self) self.pluginToolBar.setWindowTitle( QApplication.translate('MainWindow', 'Plugintoolbar', None, QApplication.UnicodeUTF8)) self.pluginToolBar.setObjectName('pluginToolBar') self.addToolBar(self.pluginToolBar) self.pluginToolBar.hide() def __createLoggerWidget(self): """Creates the logger widget. """ self.loggerDockWindow = QDockWidget(self) self.loggerDockWindow.setObjectName('loggerDockWindow') self.loggerDockWindow.visibilityChanged[bool].connect( self.actionShowLogger.setChecked) self.loggerDockWindow.setWindowTitle( QApplication.translate('MainWindow', 'Logger', None, QApplication.UnicodeUTF8)) self.loggerWidget = LoggerWidget(self.loggerDockWindow) self.loggerDockWindow.setWidget(self.loggerWidget) self.addDockWidget(Qt.BottomDockWidgetArea, self.loggerDockWindow) self.loggerDockWindow.hide() def __createLanguageOptions(self): """Creates the language selection in the menubar. """ self.langGroup = QActionGroup(self) self.langGroup.setExclusive(True) self.langGroup.triggered['QAction*'].connect(self.languageChanged) for key, name in self.languages.iteritems(): action = QAction(self) action.setCheckable(True) action.setData(key) action.setText(name[0]) action.setStatusTip(name[1]) action.setActionGroup(self.langGroup) self.menuLanguage.addAction(action) if key == self.currentLanguage: action.setChecked(True) def __loadSettings(self, mainWin=True): """Loads settings from file. :param mainWin: If set to ``False``, neither the values for the window size or the window position will be loaded. This is i.e done when the settings dialog returns 1. :type mainWin: bool """ settings = Settings() # We might want to use these methods to restore the # application state and geometry. if mainWin: self.restoreGeometry(settings.geometry) #self.restoreState(settings.state) # If the geometry saved inticates fullscreen mode, # we need to explicitly set the fullscreen menuaction checkbox if self.isFullScreen(): self.actionFullscreen.setChecked(True) # Logger # Logger # The `allwaysShowLoggerOnStart` a precedence on the # `showLogger` value. if settings.showLoggerOnStart: self.actionShowLogger.setChecked(True) else: self.actionShowLogger.setChecked(settings.showLogger) self.loggerWidget.errorBox.setChecked(settings.showErrors) self.loggerWidget.debugBox.setChecked(settings.showDebug) self.loggerWidget.infoBox.setChecked(settings.showInfo) self.toggleLoggerWindow(self.actionShowLogger.isChecked()) # Language self.loadLanguage(settings.language) #Tabs self.showWelcomeSettings = settings.value("showWelcome", 2).toInt()[0] def __writeSettings(self): """Save settings to file. """ settings = Settings() # We might want to use these methods to restore the # application state and geometry. settings.geometry = self.saveGeometry() #settings.state = self.saveState() # Mainwin #max = self.isMaximized() #settings.maximize = max #if not max: # settings.size = self.size() # settings.position = self.pos() # The global logger settings is managed from the settings dialog. # Logger settings.showLogger = self.actionShowLogger.isChecked() settings.showErrors = self.loggerWidget.errorBox.isChecked() settings.showDebug = self.loggerWidget.debugBox.isChecked() settings.showInfo = self.loggerWidget.infoBox.isChecked() # Language settings.language = self.currentLanguage def __switchTranslator(self, translator, qmFile): """Called when a new language is loaded. :param translator: The translator object to install. :type translator: QTranslator :qmFile: The translation file for the loaded language. :type qmFile: string """ qApp.removeTranslator(translator) if translator.load(qmFile): qApp.installTranslator(translator) def __setTabWidgetStyle(self, stylesheet): self.mainTabs.setStyleSheet(stylesheet) @pyqtSlot('QAction*') @pyqtSlot(int) def languageChanged(self, value): """This slot is called by actions and signals related to application translations. The slot contains validation for those parameters defined by the pyqtSlot meta info in the method header. :param value: Can be either a ``QAction`` or an integer value. I.e. menu actions provide ``QActions`` but a ``QCombobox`` might send it's index. :type value: QAction/int """ locale = None if isinstance(value, int): locale = self.languageSelector.itemData(value).toString() elif isinstance(value, QAction): locale = value.data().toString() #else: # locale = value if locale: self.loadLanguage(locale) def loadLanguage(self, locale): """Loads a language by the given language iso code. :param locale: A twoletter lowercase ISO 639 language code and possibly a twoletter uppercase ISO 3166 country code separeted by a underscore. :type locale: string """ if self.currentLanguage != locale: self.currentLanguage = locale qmFile = self.languageHandler.getQmFile(locale) self.__switchTranslator(self.translator, qmFile) def changeEvent(self, event): """This event is called when a new translator is loaded or the system language (locale) is changed. :param event: The event that generated the `changeEvent`. :type event: QEvent """ if None != event: type = event.type() if QEvent.LanguageChange == type or QEvent.LocaleChange == type: self.retranslateUi(self) self.loggerWidget.retranslateUi(self.loggerWidget) def showAboutLuma(self): """Slot for displaying the about dialog. """ AboutDialog().exec_() @pyqtSlot(bool) def toggleLoggerWindow(self, show): """Slot for toggling the logger window. :param show: a boolean value indicating whether the logger window should be shown or not. :type show: bool """ if show: self.loggerDockWindow.show() else: self.loggerDockWindow.hide() @pyqtSlot(bool) def toggleStatusbar(self, show): """Slot for toggling the logger window. :param show: a boolean value indicating whether the statusbar should be shown or not. :type show: bool """ if show: self.statusBar.show() else: self.statusBar.hide() @pyqtSlot(bool) def toggleFullscreen(self, fullscreen): """Slot for toggling the logger window. :param fullscreen: a boolean value indicating whether to enter fullscreenmode or not. :type fullcreen: bool """ if fullscreen: self.__tmpWinSize = self.size() self.showFullScreen() else: self.showNormal() self.resize(self.__tmpWinSize) def showServerEditor(self): """Slot to display the server editor dialog. """ serverEditor = ServerDialog() r = serverEditor.exec_() if r: #TODO -- only display if plugins open: self.serversChangedMessage.showMessage( QApplication.translate( "MainWindow", "You may need to restart plugins for changes to take effect." )) def showTempPasswordDialog(self): """ Sets overridePassword for a server. Using this one doesn't actually have to enter the password in the ServerDialog (and by extension save to disk). """ serverList = ServerList() # Create a stringlist to be used by the qinputdialog stringList = [] for server in serverList.getTable(): stringList.append(server.name) # Display list of servers (serverString, ok) = QInputDialog.getItem( self, QApplication.translate("MainWindow", "Select server"), QApplication.translate("MainWindow", "Server:"), stringList, editable=False) if ok: server = serverList.getServerObjectByName(serverString) if server != None: # Ask for password (value, ok) = QInputDialog.getText( self, QApplication.translate("MainWindow", "Temporary password"), QApplication.translate("MainWindow", "Enter password:"******"""Slot to display the settings dialog. If the settings dialog returns 1, i.e. the user has clicked the ok button, the loadSettings method is called with mainWin=False, to load the (assumed) newly changed settings. :param tab: The index of the tab to display in the settings dialog. :type tab: int """ #settingsDialog = SettingsDialog(self.currentLanguage, self.languages) settingsDialog = SettingsDialog() if tab < 0: tab = 0 settingsDialog.tabWidget.setCurrentIndex(tab) if settingsDialog.exec_(): self.reloadPlugins() # # We assume that some settings is changed # # if the user clicked the ok button, and # # reloads the application settings # self.__loadSettings(mainWin=False) # # A Hack but it'll do for now # for a in self.langGroup.actions(): # if a.data().toString() == self.currentLanguage: # a.setChecked(True) def configurePlugins(self): """Slot to display the plugins configuration. This currently calls `showSettingsDialog` with tab index set to 2. """ self.showSettingsDialog(1) def reloadPlugins(self): """Slot to reload plugins. """ self.pluginWidget.updatePlugins() def pluginSelected(self, item): """This method will be called from the `PluginListWidget`. """ # Clear the stylesheet when a tab is opened self.__setTabWidgetStyle(self.defaultTabStyle) widget = item.plugin.getPluginWidget(None, self) if platform.system() == "Windows": scroll = QScrollArea() scroll.setWidget(widget) scroll.setWidgetResizable(True) index = self.mainTabs.addTab(scroll, item.icon(), item.plugin.pluginUserString) else: index = self.mainTabs.addTab(widget, item.icon(), item.plugin.pluginUserString) self.mainTabs.setCurrentIndex(index) def tabClose(self, index): """Slot for the signal `tabCloseRequest(int)` for the tabMains. """ widget = self.mainTabs.widget(index) # If the tab closed is one of these, enable the toggle-action if widget == self.pluginWidget: self.actionShowPluginList.setEnabled(True) if widget == self.welcomeTab: self.actionShowWelcomeTab.setEnabled(True) self.mainTabs.removeTab(index) # Unparent the widget since it was reparented by the QTabWidget # so it's garbage collected widget.setParent(None) # In case the widget contained circular references # -- force GC to take care of the objects since there can be # quite many if it was BrowserWidget that was closed. # Can't call it directly since that'll be too soon QTimer.singleShot(1000, self.gc) # Let's do some styling of the tab widget when no tabs are opened if self.mainTabs.currentIndex() == -1: self.__setTabWidgetStyle(self.lumaHeadStyle) def gc(self): """Runs Python's garbage-collection manually. Used to make sure circular references are taken care of *now*. """ gc.collect() def showWelcome(self): """Shows the Welcome-tab """ self.__setTabWidgetStyle(self.defaultTabStyle) index = self.mainTabs.addTab( self.welcomeTab, QApplication.translate("MainWindow", "Welcome")) self.mainTabs.setCurrentIndex(index) self.actionShowWelcomeTab.setEnabled(False) def showPlugins(self): """Will show the pluginlistwidget-tab """ self.__setTabWidgetStyle(self.defaultTabStyle) if self.mainTabs.indexOf(self.pluginWidget) == -1: index = self.mainTabs.addTab( self.pluginWidget, QApplication.translate("MainWindow", "Plugins")) self.mainTabs.setCurrentIndex(index) self.actionShowPluginList.setEnabled(False) def closeEvent(self, e): """Overrides the ``QMainWindow.closeEvent`` slot to save settings before we tear down the application. """ self.__writeSettings() QMainWindow.closeEvent(self, e)
class ProjectXively(QWidget): qtcb_update_illuminance = pyqtSignal(float) qtcb_update_air_pressure = pyqtSignal(float) qtcb_update_temperature = pyqtSignal(float) qtcb_update_humidity = pyqtSignal(float) qtcb_button_pressed = pyqtSignal(int) lcdwidget = None xively_host = "api.xively.com" xively_agent = "Tinkerforge Starter Kit Weather Station Demo" xively_channel = "Enter Feed ID here" xively_api_key = "Enter API Key here" xively_items = {} xively_headers = None xively_params = "" xively_update_rate = 5 # in minutes text_agent = None text_channel = None text_api_key = None number_update_rate = None save_button = None xively_timer = None error_message = None label_upload_active = None last_upload = None def __init__(self, parent, app): super(QWidget, self).__init__() self.lcdwidget = LCDWidget(self, app) self.lcdwidget.hide() self.text_agent = QLineEdit(self) self.text_agent.setText(self.xively_agent) self.text_channel = QLineEdit(self) self.text_channel.setText(self.xively_channel) self.text_api_key = QLineEdit(self) self.text_api_key.setText(self.xively_api_key) self.number_update_rate = QSpinBox(self) self.number_update_rate.setRange(1, 1440) self.number_update_rate.setSuffix(' min') self.number_update_rate.setValue(self.xively_update_rate) layout1 = QHBoxLayout() layout2 = QVBoxLayout() layout1.addStretch() layout1.addLayout(layout2) layout1.addStretch() layout2.addSpacerItem(QSpacerItem(LCDWidget.FIXED_WIDGTH, 0)) label = QLabel(self) label.setText( "Project: <b>Connect to Xively</b>. This project uploads the measured values to Xively. Please find documentation how to configure it and program sources in Python <a href=\"http://www.tinkerforge.com/en/doc/Kits/WeatherStation/WeatherStation.html#connect-to-xively\">here</a>.<br>" ) label.setTextFormat(Qt.RichText) label.setTextInteractionFlags(Qt.TextBrowserInteraction) label.setOpenExternalLinks(True) label.setWordWrap(True) label.setAlignment(Qt.AlignJustify) layout2.addSpacing(10) layout2.addWidget(label) layout2.addSpacing(10) layout3a = QHBoxLayout() label = QLabel("Agent Description:") label.setMinimumWidth(150) layout3a.addWidget(label) layout3a.addWidget(self.text_agent, 1) layout2.addLayout(layout3a) layout2.addSpacing(10) layout3b = QHBoxLayout() label = QLabel("Feed:") label.setMinimumWidth(150) layout3b.addWidget(label) layout3b.addWidget(self.text_channel, 1) layout2.addLayout(layout3b) layout2.addSpacing(10) layout3c = QHBoxLayout() label = QLabel("API Key:") label.setMinimumWidth(150) layout3c.addWidget(label) layout3c.addWidget(self.text_api_key, 1) layout2.addLayout(layout3c) layout2.addSpacing(10) layout3d = QHBoxLayout() label = QLabel("Update Rate:") label.setMinimumWidth(150) layout3d.addWidget(label) layout3d.addWidget(self.number_update_rate, 1) layout2.addLayout(layout3d) layout2.addSpacing(10) self.label_upload_active = QLabel("Not Active", self) self.label_upload_active.setMinimumWidth(150) font = QFont() font.setPixelSize(20) self.label_upload_active.setFont(font) self.set_active_label(False) self.save_button = QPushButton("Save/Activate") layout4 = QHBoxLayout() layout4.addWidget(self.label_upload_active) layout4.addWidget(self.save_button, 1) layout2.addLayout(layout4) layout2.addStretch() self.setLayout(layout1) self.qtcb_update_illuminance.connect(self.update_illuminance_data_slot) self.qtcb_update_air_pressure.connect( self.update_air_pressure_data_slot) self.qtcb_update_temperature.connect(self.update_temperature_data_slot) self.qtcb_update_humidity.connect(self.update_humidity_data_slot) self.qtcb_button_pressed.connect(self.button_pressed_slot) self.save_button.clicked.connect(self.save_configuration) self.lcdwidget.clear(self) self.error_message = QErrorMessage(self) def set_active_label(self, value): palette = self.label_upload_active.palette() if value: palette.setColor(self.foregroundRole(), Qt.darkGreen) self.label_upload_active.setText("Active") else: palette.setColor(self.foregroundRole(), Qt.red) self.label_upload_active.setText("Not Active") self.label_upload_active.setPalette(palette) def save_configuration(self): try: self.xively_agent = str(self.text_agent.text()).decode('ascii') self.xively_channel = str(self.text_channel.text()).decode('ascii') self.xively_api_key = str(self.text_api_key.text()).decode('ascii') except: self.error_message.showMessage( 'Agent, Feed and API Key can only contain ASCII characters') return self.xively_update_rate = self.number_update_rate.value() self.xively_headers = { "Content-Type": "application/x-www-form-urlencoded", "X-ApiKey": self.xively_api_key, "User-Agent": self.xively_agent, } self.xively_params = "/v2/feeds/" + self.xively_channel if self.xively_timer is None: self.xively_timer = QTimer(self) self.xively_timer.timeout.connect(self.update_xively) self.xively_timer.start(self.xively_update_rate * 60 * 1000) self.set_active_label(True) self.update_xively() def write_lcd(self): if self.last_upload == None: tmp = "Last: Never" else: tmp = "Last: " + self.last_upload self.lcdwidget.write_line(0, 0, "Xively Upload", self) self.lcdwidget.write_line(2, 0, tmp, self) def update_xively(self): if len(self.xively_items) == 0: return stream_items = [] for identifier, value in self.xively_items.items(): stream_items.append({ 'id': identifier, 'current_value': value[0], 'min_value': value[1], 'max_value': value[2] }) data = {'version': '1.0.0', 'datastreams': stream_items} self.xively_items = {} body = json.dumps(data) try: http = httplib.HTTPSConnection(self.xively_host) http.request('PUT', self.xively_params, body, self.xively_headers) response = http.getresponse() http.close() if response.status != 200: self.error_message.showMessage( 'Could not upload to xively -> Response:' + str(response.status) + ': ' + response.reason + '. Check your configuration.') self.xively_timer.stop() self.xively_timer = None self.set_active_label(False) return except Exception as e: self.error_message.showMessage('HTTP error: ' + str(e)) self.xively_timer.stop() self.xively_timer = None self.set_active_label(False) return # set upload time if upload was a success self.last_upload = time.strftime("%H:%M:%S") def put(self, identifier, value): self.write_lcd() try: _, min_value, max_value = self.xively_items[identifier] if value < min_value: min_value = value if value > max_value: max_value = value self.xively_items[identifier] = (value, min_value, max_value) except: self.xively_items[identifier] = (value, value, value) def update_illuminance_data_slot(self, illuminance): self.put('AmbientLight', illuminance) def update_illuminance(self, illuminance): self.qtcb_update_illuminance.emit(illuminance) def update_humidity_data_slot(self, humidity): self.put('Humidity', humidity) def update_humidity(self, humidity): self.qtcb_update_humidity.emit(humidity) def update_air_pressure_data_slot(self, air_pressure): self.put('AirPressure', air_pressure) def update_air_pressure(self, air_pressure): self.qtcb_update_air_pressure.emit(air_pressure) def update_temperature_data_slot(self, temperature): self.put('Temperature', temperature) def update_temperature(self, temperature): self.qtcb_update_temperature.emit(temperature) def button_pressed_slot(self, button): pass def button_pressed(self, button): self.qtcb_button_pressed.emit(button)
class MainWindow(QMainWindow, Ui_MainWindow): """The Main window of Luma. """ logger = logging.getLogger(__name__) languages = {} translator = None languageHandler = None currentLanguage = '' def __init__(self, parent=None): """The constructor sets up the MainWindow widget, and connects all necessary signals and slots """ super(MainWindow, self).__init__(parent) self.setupUi(self) # We store the window size to make sure the previous window size # is restored when leaving fullscreen mode. This varible is used # in the toggleFullscreen slot. self.__tmpWinSize = self.size() self.eventFilter = LumaEventFilter(self) self.mainTabs.installEventFilter(self.eventFilter) self.translator = QTranslator() self.languageHandler = LanguageHandler() self.languages = self.languageHandler.availableLanguages #self.__createPluginToolBar() self.__createLoggerWidget() self.__loadSettings() self.__createLanguageOptions() self.setStatusBar(self.statusBar) self.mainTabs.setTabsClosable(True) self.mainTabs.setContextMenuPolicy(Qt.CustomContextMenu) self.mainTabs.customContextMenuRequested.connect( self.__mainTabsContextMenu) self.defaultTabStyle = '' self.lumaHeadStyle = 'background: url(:/icons/luma-gray);\n' + \ 'background-position: bottom right;\n' + \ 'background-attachment: fixed;\n' + \ 'background-repeat: no-repeat;' #Sets up pluginWidget #self in parameter is used to call pluginSelected here... self.pluginWidget = PluginListWidget(self) self.showPlugins() self.welcomeTab = WelcomeTab() self.welcomeTab.textBrowser.setStyleSheet(self.lumaHeadStyle) #This value comes from __loadSettings() #Its a checkbox set in WelcomeTab if self.showWelcomeSettings == 2: self.showWelcome() else: # Let's do some styling of the tab widget when no tabs are opened if self.mainTabs.currentIndex() == -1: self.__setTabWidgetStyle(self.lumaHeadStyle) self.actionShowWelcomeTab.setEnabled(True) self.serversChangedMessage = QErrorMessage(self) def __mainTabsContextMenu(self, pos): menu = QMenu() if self.mainTabs.count() > 0: return # The menu is displayed even when the rightclick is not # done over the actual tabs so to avoid confusion the # function is disabled entirey #menu.addAction(QApplication.translate( # "MainWindow", "Close all plugin-tabs"), self.tabCloseAll) else: # If there's no tabs, offer to display the pluginlist menu.addAction(self.actionShowPluginList) menu.exec_(self.mainTabs.mapToGlobal(pos)) def __createPluginToolBar(self): """Creates the pluign toolbar. """ self.pluginToolBar = PluginToolBar(self) self.pluginToolBar.setWindowTitle(QApplication.translate( 'MainWindow', 'Plugintoolbar', None, QApplication.UnicodeUTF8)) self.pluginToolBar.setObjectName('pluginToolBar') self.addToolBar(self.pluginToolBar) self.pluginToolBar.hide() def __createLoggerWidget(self): """Creates the logger widget. """ self.loggerDockWindow = QDockWidget(self) self.loggerDockWindow.setObjectName('loggerDockWindow') self.loggerDockWindow.visibilityChanged[bool].connect( self.actionShowLogger.setChecked) self.loggerDockWindow.setWindowTitle(QApplication.translate( 'MainWindow', 'Logger', None, QApplication.UnicodeUTF8)) self.loggerWidget = LoggerWidget(self.loggerDockWindow) self.loggerDockWindow.setWidget(self.loggerWidget) self.addDockWidget(Qt.BottomDockWidgetArea, self.loggerDockWindow) self.loggerDockWindow.hide() def __createLanguageOptions(self): """Creates the language selection in the menubar. """ self.langGroup = QActionGroup(self) self.langGroup.setExclusive(True) self.langGroup.triggered['QAction*'].connect(self.languageChanged) for key, name in self.languages.iteritems(): action = QAction(self) action.setCheckable(True) action.setData(key) action.setText(name[0]) action.setStatusTip(name[1]) action.setActionGroup(self.langGroup) self.menuLanguage.addAction(action) if key == self.currentLanguage: action.setChecked(True) def __loadSettings(self, mainWin=True): """Loads settings from file. :param mainWin: If set to ``False``, neither the values for the window size or the window position will be loaded. This is i.e done when the settings dialog returns 1. :type mainWin: bool """ settings = Settings() # We might want to use these methods to restore the # application state and geometry. if mainWin: self.restoreGeometry(settings.geometry) #self.restoreState(settings.state) # If the geometry saved inticates fullscreen mode, # we need to explicitly set the fullscreen menuaction checkbox if self.isFullScreen(): self.actionFullscreen.setChecked(True) # Logger # Logger # The `allwaysShowLoggerOnStart` a precedence on the # `showLogger` value. if settings.showLoggerOnStart: self.actionShowLogger.setChecked(True) else: self.actionShowLogger.setChecked(settings.showLogger) self.loggerWidget.errorBox.setChecked(settings.showErrors) self.loggerWidget.debugBox.setChecked(settings.showDebug) self.loggerWidget.infoBox.setChecked(settings.showInfo) self.toggleLoggerWindow(self.actionShowLogger.isChecked()) # Language self.loadLanguage(settings.language) #Tabs self.showWelcomeSettings = settings.value("showWelcome", 2).toInt()[0] def __writeSettings(self): """Save settings to file. """ settings = Settings() # We might want to use these methods to restore the # application state and geometry. settings.geometry = self.saveGeometry() #settings.state = self.saveState() # Mainwin #max = self.isMaximized() #settings.maximize = max #if not max: # settings.size = self.size() # settings.position = self.pos() # The global logger settings is managed from the settings dialog. # Logger settings.showLogger = self.actionShowLogger.isChecked() settings.showErrors = self.loggerWidget.errorBox.isChecked() settings.showDebug = self.loggerWidget.debugBox.isChecked() settings.showInfo = self.loggerWidget.infoBox.isChecked() # Language settings.language = self.currentLanguage def __switchTranslator(self, translator, qmFile): """Called when a new language is loaded. :param translator: The translator object to install. :type translator: QTranslator :qmFile: The translation file for the loaded language. :type qmFile: string """ qApp.removeTranslator(translator) if translator.load(qmFile): qApp.installTranslator(translator) def __setTabWidgetStyle(self, stylesheet): self.mainTabs.setStyleSheet(stylesheet) @pyqtSlot('QAction*') @pyqtSlot(int) def languageChanged(self, value): """This slot is called by actions and signals related to application translations. The slot contains validation for those parameters defined by the pyqtSlot meta info in the method header. :param value: Can be either a ``QAction`` or an integer value. I.e. menu actions provide ``QActions`` but a ``QCombobox`` might send it's index. :type value: QAction/int """ locale = None if isinstance(value, int): locale = self.languageSelector.itemData(value).toString() elif isinstance(value, QAction): locale = value.data().toString() #else: # locale = value if locale: self.loadLanguage(locale) def loadLanguage(self, locale): """Loads a language by the given language iso code. :param locale: A twoletter lowercase ISO 639 language code and possibly a twoletter uppercase ISO 3166 country code separeted by a underscore. :type locale: string """ if self.currentLanguage != locale: self.currentLanguage = locale qmFile = self.languageHandler.getQmFile(locale) self.__switchTranslator(self.translator, qmFile) def changeEvent(self, event): """This event is called when a new translator is loaded or the system language (locale) is changed. :param event: The event that generated the `changeEvent`. :type event: QEvent """ if None != event: type = event.type() if QEvent.LanguageChange == type or QEvent.LocaleChange == type: self.retranslateUi(self) self.loggerWidget.retranslateUi(self.loggerWidget) def showAboutLuma(self): """Slot for displaying the about dialog. """ AboutDialog().exec_() @pyqtSlot(bool) def toggleLoggerWindow(self, show): """Slot for toggling the logger window. :param show: a boolean value indicating whether the logger window should be shown or not. :type show: bool """ if show: self.loggerDockWindow.show() else: self.loggerDockWindow.hide() @pyqtSlot(bool) def toggleStatusbar(self, show): """Slot for toggling the logger window. :param show: a boolean value indicating whether the statusbar should be shown or not. :type show: bool """ if show: self.statusBar.show() else: self.statusBar.hide() @pyqtSlot(bool) def toggleFullscreen(self, fullscreen): """Slot for toggling the logger window. :param fullscreen: a boolean value indicating whether to enter fullscreenmode or not. :type fullcreen: bool """ if fullscreen: self.__tmpWinSize = self.size() self.showFullScreen() else: self.showNormal() self.resize(self.__tmpWinSize) def showServerEditor(self): """Slot to display the server editor dialog. """ serverEditor = ServerDialog() r = serverEditor.exec_() if r: #TODO -- only display if plugins open: self.serversChangedMessage.showMessage(QApplication.translate( "MainWindow", "You may need to restart plugins for changes to take effect.")) def showTempPasswordDialog(self): """ Sets overridePassword for a server. Using this one doesn't actually have to enter the password in the ServerDialog (and by extension save to disk). """ serverList = ServerList() # Create a stringlist to be used by the qinputdialog stringList = [] for server in serverList.getTable(): stringList.append(server.name) # Display list of servers (serverString, ok) = QInputDialog.getItem( self, QApplication.translate("MainWindow", "Select server"), QApplication.translate("MainWindow", "Server:"), stringList, editable=False ) if ok: server = serverList.getServerObjectByName(serverString) if server != None: # Ask for password (value, ok) = QInputDialog.getText( self, QApplication.translate("MainWindow", "Temporary password"), QApplication.translate("MainWindow", "Enter password:"******"""Slot to display the settings dialog. If the settings dialog returns 1, i.e. the user has clicked the ok button, the loadSettings method is called with mainWin=False, to load the (assumed) newly changed settings. :param tab: The index of the tab to display in the settings dialog. :type tab: int """ #settingsDialog = SettingsDialog(self.currentLanguage, self.languages) settingsDialog = SettingsDialog() if tab < 0: tab = 0 settingsDialog.tabWidget.setCurrentIndex(tab) if settingsDialog.exec_(): self.reloadPlugins() # # We assume that some settings is changed # # if the user clicked the ok button, and # # reloads the application settings # self.__loadSettings(mainWin=False) # # A Hack but it'll do for now # for a in self.langGroup.actions(): # if a.data().toString() == self.currentLanguage: # a.setChecked(True) def configurePlugins(self): """Slot to display the plugins configuration. This currently calls `showSettingsDialog` with tab index set to 2. """ self.showSettingsDialog(1) def reloadPlugins(self): """Slot to reload plugins. """ self.pluginWidget.updatePlugins() def pluginSelected(self, item): """This method will be called from the `PluginListWidget`. """ # Clear the stylesheet when a tab is opened self.__setTabWidgetStyle(self.defaultTabStyle) widget = item.plugin.getPluginWidget(None, self) if platform.system() == "Windows": scroll = QScrollArea() scroll.setWidget(widget) scroll.setWidgetResizable(True) index = self.mainTabs.addTab( scroll, item.icon(), item.plugin.pluginUserString) else: index = self.mainTabs.addTab( widget, item.icon(), item.plugin.pluginUserString) self.mainTabs.setCurrentIndex(index) def tabClose(self, index): """Slot for the signal `tabCloseRequest(int)` for the tabMains. """ widget = self.mainTabs.widget(index) # If the tab closed is one of these, enable the toggle-action if widget == self.pluginWidget: self.actionShowPluginList.setEnabled(True) if widget == self.welcomeTab: self.actionShowWelcomeTab.setEnabled(True) self.mainTabs.removeTab(index) # Unparent the widget since it was reparented by the QTabWidget # so it's garbage collected widget.setParent(None) # In case the widget contained circular references # -- force GC to take care of the objects since there can be # quite many if it was BrowserWidget that was closed. # Can't call it directly since that'll be too soon QTimer.singleShot(1000, self.gc) # Let's do some styling of the tab widget when no tabs are opened if self.mainTabs.currentIndex() == -1: self.__setTabWidgetStyle(self.lumaHeadStyle) def gc(self): """Runs Python's garbage-collection manually. Used to make sure circular references are taken care of *now*. """ gc.collect() def showWelcome(self): """Shows the Welcome-tab """ self.__setTabWidgetStyle(self.defaultTabStyle) index = self.mainTabs.addTab(self.welcomeTab, QApplication.translate("MainWindow", "Welcome")) self.mainTabs.setCurrentIndex(index) self.actionShowWelcomeTab.setEnabled(False) def showPlugins(self): """Will show the pluginlistwidget-tab """ self.__setTabWidgetStyle(self.defaultTabStyle) if self.mainTabs.indexOf(self.pluginWidget) == -1: index = self.mainTabs.addTab( self.pluginWidget, QApplication.translate( "MainWindow", "Plugins")) self.mainTabs.setCurrentIndex(index) self.actionShowPluginList.setEnabled(False) def closeEvent(self, e): """Overrides the ``QMainWindow.closeEvent`` slot to save settings before we tear down the application. """ self.__writeSettings() QMainWindow.closeEvent(self, e)
class DC(PluginBase, Ui_DC): qtcb_position_reached = pyqtSignal(int) qtcb_under_voltage = pyqtSignal(int) qtcb_emergency_shutdown = pyqtSignal() def __init__ (self, ipcon, uid): PluginBase.__init__(self, ipcon, uid) self.setupUi(self) self.dc = brick_dc.DC(self.uid) self.device = self.dc self.ipcon.add_device(self.dc) self.version = '.'.join(map(str, self.dc.get_version()[1])) self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_data) self.speedometer = SpeedoMeter() self.vertical_layout_right.insertWidget(4, self.speedometer) self.new_value = 0 self.update_counter = 0 self.full_brake_time = 0 self.velocity_slider.sliderReleased.connect(self.velocity_slider_released) self.velocity_slider.valueChanged.connect(self.velocity_spin.setValue) self.velocity_spin.editingFinished.connect(self.velocity_spin_finished) self.acceleration_slider.sliderReleased.connect(self.acceleration_slider_released) self.acceleration_slider.valueChanged.connect(self.acceleration_spin.setValue) self.acceleration_spin.editingFinished.connect(self.acceleration_spin_finished) self.frequency_slider.sliderReleased.connect(self.frequency_slider_released) self.frequency_slider.valueChanged.connect(self.frequency_spin.setValue) self.frequency_spin.editingFinished.connect(self.frequency_spin_finished) self.radio_mode_brake.toggled.connect(self.brake_value_changed) self.radio_mode_coast.toggled.connect(self.coast_value_changed) self.minimum_voltage_button.pressed.connect(self.minimum_voltage_button_pressed) self.full_brake_button.pressed.connect(self.full_brake_pressed) self.enable_checkbox.stateChanged.connect(self.enable_state_changed) self.emergency_signal = None self.under_signal = None self.current_velocity_signal = None self.velocity_reached_signal = None self.qem = QErrorMessage(self) self.qtcb_under_voltage.connect(self.cb_under_voltage) self.dc.register_callback(self.dc.CALLBACK_UNDER_VOLTAGE, self.qtcb_under_voltage.emit) self.qtcb_emergency_shutdown.connect(self.cb_emergency_shutdown) self.dc.register_callback(self.dc.CALLBACK_EMERGENCY_SHUTDOWN, self.qtcb_emergency_shutdown.emit) self.qtcb_position_reached.connect(self.update_velocity) self.dc.register_callback(self.dc.CALLBACK_VELOCITY_REACHED, self.qtcb_position_reached.emit) self.dc.register_callback(self.dc.CALLBACK_CURRENT_VELOCITY, self.qtcb_position_reached.emit) def start(self): self.update_timer.start(1000) try: self.dc.set_current_velocity_period(100) self.update_start() self.update_data() except ip_connection.Error: return def stop(self): self.update_timer.stop() try: self.dc.set_current_velocity_period(0) except ip_connection.Error: return @staticmethod def has_name(name): return 'DC Brick' in name def cb_emergency_shutdown(self): if not self.qem.isVisible(): self.qem.setWindowTitle("Emergency Shutdown") self.qem.showMessage("Emergency Shutdown: Short-Circuit or Over-Temperature") def cb_under_voltage(self, ov): mv_str = self.minimum_voltage_label.text() ov_str = "%gV" % round(ov/1000.0, 1) if not self.qem.isVisible(): self.qem.setWindowTitle("Under Voltage") self.qem.showMessage("Under Voltage: Output Voltage of " + ov_str + " is below minimum voltage of " + mv_str) def enable_state_changed(self, state): try: if state == Qt.Checked: self.dc.enable() elif state == Qt.Unchecked: self.dc.disable() except ip_connection.Error: return def brake_value_changed(self, checked): if checked: try: self.dc.set_drive_mode(0) except ip_connection.Error: return def coast_value_changed(self, checked): if checked: try: self.dc.set_drive_mode(1) except ip_connection.Error: return def full_brake_pressed(self): try: self.dc.full_brake() except ip_connection.Error: return def minimum_voltage_selected(self, value): try: self.dc.set_minimum_voltage(value) except ip_connection.Error: return def minimum_voltage_button_pressed(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(5000) qid.setIntMaximum(0xFFFF) qid.setIntStep(100) try: qid.setIntValue(self.dc.get_minimum_voltage()) except ip_connection.Error: return qid.intValueSelected.connect(self.minimum_voltage_selected) qid.setLabelText("Choose minimum motor voltage in mV.") qid.open() def stack_input_voltage_update(self, sv): sv_str = "%gV" % round(sv/1000.0, 1) self.stack_voltage_label.setText(sv_str) def external_input_voltage_update(self, ev): ev_str = "%gV" % round(ev/1000.0, 1) self.external_voltage_label.setText(ev_str) def minimum_voltage_update(self, mv): mv_str = "%gV" % round(mv/1000.0, 1) self.minimum_voltage_label.setText(mv_str) def drive_mode_update(self, dm): if dm == 0: self.radio_mode_brake.setChecked(True) self.radio_mode_coast.setChecked(False) else: self.radio_mode_brake.setChecked(False) self.radio_mode_coast.setChecked(True) def current_consumption_update(self, cc): if cc >= 1000: cc_str = "%gA" % round(cc/1000.0, 1) else: cc_str = "%gmA" % cc self.current_label.setText(cc_str) def update_velocity(self, value): if value != self.speedometer.value(): self.speedometer.set_velocity(value) def update_start(self): try: dm = self.dc.get_drive_mode() self.drive_mode_update(dm) if not self.velocity_slider.isSliderDown(): velocity = self.dc.get_velocity() if velocity != self.velocity_slider.sliderPosition(): self.velocity_slider.setSliderPosition(velocity) self.velocity_spin.setValue(velocity) if not self.acceleration_slider.isSliderDown(): acceleration = self.dc.get_acceleration() if acceleration != self.acceleration_slider.sliderPosition(): self.acceleration_slider.setSliderPosition(acceleration) self.acceleration_spin.setValue(acceleration) if not self.frequency_slider.isSliderDown(): frequency = self.dc.get_pwm_frequency() if frequency != self.frequency_slider.sliderPosition(): self.frequency_slider.setSliderPosition(frequency) self.frequency_spin.setValue(frequency) enabled = self.dc.is_enabled() if enabled: self.enable_checkbox.setCheckState(Qt.Checked) else: self.enable_checkbox.setCheckState(Qt.Unchecked) except ip_connection.Error: return def update_data(self): try: sv = self.dc.get_stack_input_voltage() ev = self.dc.get_external_input_voltage() mv = self.dc.get_minimum_voltage() cc = self.dc.get_current_consumption() except ip_connection.Error: return self.stack_input_voltage_update(sv) self.external_input_voltage_update(ev) self.minimum_voltage_update(mv) self.current_consumption_update(cc) def acceleration_slider_released(self): value = self.acceleration_slider.value() self.acceleration_spin.setValue(value) try: self.dc.set_acceleration(value) except ip_connection.Error: return def acceleration_spin_finished(self): value = self.acceleration_spin.value() self.acceleration_slider.setValue(value) try: self.dc.set_acceleration(value) except ip_connection.Error: return def velocity_slider_released(self): value = self.velocity_slider.value() self.velocity_spin.setValue(value) try: self.dc.set_velocity(value) except ip_connection.Error: return def velocity_spin_finished(self): value = self.velocity_spin.value() self.velocity_slider.setValue(value) try: self.dc.set_velocity(value) except ip_connection.Error: return def frequency_slider_released(self): value = self.frequency_slider.value() self.frequency_spin.setValue(value) try: self.dc.set_pwm_frequency(value) except ip_connection.Error: return def frequency_spin_finished(self): value = self.frequency_spin.value() self.frequency_slider.setValue(value) try: self.dc.set_pwm_frequency(value) except ip_connection.Error: return
class Stepper(PluginBase, Ui_Stepper): qtcb_position_reached = pyqtSignal(int) qtcb_under_voltage = pyqtSignal(int) def __init__(self, ipcon, uid): PluginBase.__init__(self, ipcon, uid) self.setupUi(self) self.stepper = brick_stepper.Stepper(self.uid) self.device = self.stepper self.ipcon.add_device(self.stepper) self.version = '.'.join(map(str, self.stepper.get_version()[1])) self.endis_all(False) self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_data) self.speedometer = SpeedoMeter() self.vertical_layout_right.insertWidget(5, self.speedometer) self.new_value = 0 self.update_counter = 0 self.full_brake_time = 0 self.qem = QErrorMessage(self) self.qem.setWindowTitle("Under Voltage") self.velocity_slider.sliderReleased.connect( self.velocity_slider_released) self.velocity_slider.valueChanged.connect(self.velocity_spin.setValue) self.velocity_spin.editingFinished.connect(self.velocity_spin_finished) self.acceleration_slider.sliderReleased.connect( self.acceleration_slider_released) self.acceleration_slider.valueChanged.connect( self.acceleration_spin.setValue) self.acceleration_spin.editingFinished.connect( self.acceleration_spin_finished) self.deceleration_slider.sliderReleased.connect( self.deceleration_slider_released) self.deceleration_slider.valueChanged.connect( self.deceleration_spin.setValue) self.deceleration_spin.editingFinished.connect( self.deceleration_spin_finished) self.decay_slider.sliderReleased.connect(self.decay_slider_released) self.decay_slider.valueChanged.connect(self.decay_spin.setValue) self.decay_spin.editingFinished.connect(self.decay_spin_finished) self.enable_checkbox.stateChanged.connect(self.enable_state_changed) self.forward_button.pressed.connect(self.forward_pressed) self.stop_button.pressed.connect(self.stop_pressed) self.full_brake_button.pressed.connect(self.full_brake_pressed) self.backward_button.pressed.connect(self.backward_pressed) self.to_button.pressed.connect(self.to_button_pressed) self.steps_button.pressed.connect(self.steps_button_pressed) self.motor_current_button.pressed.connect( self.motor_current_button_pressed) self.minimum_motor_voltage_button.pressed.connect( self.minimum_motor_voltage_button_pressed) self.mode_dropbox.currentIndexChanged.connect(self.mode_changed) self.qtcb_position_reached.connect(self.cb_position_reached) self.stepper.register_callback(self.stepper.CALLBACK_POSITION_REACHED, self.qtcb_position_reached.emit) self.qtcb_under_voltage.connect(self.cb_under_voltage) self.stepper.register_callback(self.stepper.CALLBACK_UNDER_VOLTAGE, self.qtcb_under_voltage.emit) def start(self): self.update_timer.start(100) self.update_start() def stop(self): self.update_timer.stop() @staticmethod def has_name(name): return 'Stepper Brick' in name def cb_position_reached(self, position): self.position_update(position) self.endis_all(True) def disable_list(self, button_list): for button in button_list: button.setEnabled(False) def endis_all(self, value): self.forward_button.setEnabled(value) self.stop_button.setEnabled(value) self.backward_button.setEnabled(value) self.to_button.setEnabled(value) self.steps_button.setEnabled(value) self.full_brake_button.setEnabled(value) def mode_changed(self, index): try: self.stepper.set_step_mode(1 << index) except ip_connection.Error: return def forward_pressed(self): try: self.stepper.drive_forward() except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button]) def backward_pressed(self): try: self.stepper.drive_backward() except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button]) def stop_pressed(self): try: self.stepper.stop() except ip_connection.Error: return self.endis_all(True) def full_brake_pressed(self): try: self.stepper.full_brake() except ip_connection.Error: return self.endis_all(True) def to_button_pressed(self): drive_to = self.to_spin.value() try: self.stepper.set_target_position(drive_to) except ip_connection.Error: return self.disable_list([ self.to_button, self.steps_button, self.forward_button, self.backward_button ]) def steps_button_pressed(self): drive_steps = self.steps_spin.value() try: self.stepper.set_steps(drive_steps) except ip_connection.Error: return self.disable_list([ self.to_button, self.steps_button, self.forward_button, self.backward_button ]) def motor_current_button_pressed(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(0) qid.setIntMaximum(2500) qid.setIntStep(100) try: qid.setIntValue(self.stepper.get_motor_current()) except ip_connection.Error: return qid.intValueSelected.connect(self.motor_current_selected) qid.setLabelText("Choose motor current in mA.") # "<font color=red>Setting this too high can destroy your Motor.</font>") qid.open() def minimum_motor_voltage_button_pressed(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(0) qid.setIntMaximum(40000) qid.setIntStep(100) try: qid.setIntValue(self.stepper.get_minimum_voltage()) except ip_connection.Error: return qid.intValueSelected.connect(self.minimum_motor_voltage_selected) qid.setLabelText("Choose minimum motor voltage in mV.") qid.open() def motor_current_selected(self, value): try: self.stepper.set_motor_current(value) except ip_connection.Error: return def minimum_motor_voltage_selected(self, value): try: self.stepper.set_minimum_voltage(value) except ip_connection.Error: return def cb_under_voltage(self, ov): mv_str = self.minimum_voltage_label.text() ov_str = "%gV" % round(ov / 1000.0, 1) if not self.qem.isVisible(): self.qem.showMessage("Under Voltage: Output Voltage of " + ov_str + " is below minimum voltage of " + mv_str) def enable_state_changed(self, state): try: if state == Qt.Checked: self.endis_all(True) self.stepper.enable() elif state == Qt.Unchecked: self.endis_all(False) self.stepper.disable() except ip_connection.Error: return def stack_input_voltage_update(self, sv): sv_str = "%gV" % round(sv / 1000.0, 1) self.stack_voltage_label.setText(sv_str) def external_input_voltage_update(self, ev): ev_str = "%gV" % round(ev / 1000.0, 1) self.external_voltage_label.setText(ev_str) def minimum_voltage_update(self, mv): mv_str = "%gV" % round(mv / 1000.0, 1) self.minimum_voltage_label.setText(mv_str) def maximum_current_update(self, cur): cur_str = "%gA" % round(cur / 1000.0, 1) self.maximum_current_label.setText(cur_str) def position_update(self, pos): pos_str = "%g" % pos self.position_label.setText(pos_str) def remaining_steps_update(self, ste): ste_str = "%g" % ste self.remaining_steps_label.setText(ste_str) def mode_update(self, mod): if mod == 8: index = 3 elif mod == 4: index = 2 elif mod == 2: index = 1 else: index = 0 self.mode_dropbox.setCurrentIndex(index) def update_start(self): try: if not self.velocity_slider.isSliderDown(): velocity = self.stepper.get_max_velocity() if velocity != self.velocity_slider.sliderPosition(): self.velocity_slider.setSliderPosition(velocity) self.velocity_spin.setValue(velocity) if not self.acceleration_slider.isSliderDown() and \ not self.deceleration_slider.isSliderDown(): acc, dec = self.stepper.get_speed_ramping() if acc != self.acceleration_slider.sliderPosition(): self.acceleration_slider.setSliderPosition(acc) self.acceleration_spin.setValue(acc) if dec != self.deceleration_slider.sliderPosition(): self.deceleration_slider.setSliderPosition(dec) self.deceleration_spin.setValue(dec) if not self.decay_slider.isSliderDown(): dec = self.stepper.get_decay() if dec != self.decay_slider.sliderPosition(): self.decay_slider.setSliderPosition(dec) self.decay_spin.setValue(dec) enabled = self.stepper.is_enabled() if enabled: if self.enable_checkbox.checkState() != Qt.Checked: self.endis_all(True) self.enable_checkbox.setCheckState(Qt.Checked) else: if self.enable_checkbox.checkState() != Qt.Unchecked: self.endis_all(False) self.enable_checkbox.setCheckState(Qt.Unchecked) except ip_connection.Error: return def update_infos(self): try: cur = self.stepper.get_motor_current() sv = self.stepper.get_stack_input_voltage() ev = self.stepper.get_external_input_voltage() mv = self.stepper.get_minimum_voltage() mod = self.stepper.get_step_mode() except ip_connection.Error: return self.maximum_current_update(cur) self.stack_input_voltage_update(sv) self.external_input_voltage_update(ev) self.minimum_voltage_update(mv) self.mode_update(mod) def update_values(self): try: ste = self.stepper.get_remaining_steps() pos = self.stepper.get_current_position() self.remaining_steps_update(ste) self.position_update(pos) current_velocity = self.stepper.get_current_velocity() if current_velocity != self.speedometer.value(): self.speedometer.set_velocity(current_velocity) except ip_connection.Error: return def update_data(self): try: ste = self.stepper.get_remaining_steps() pos = self.stepper.get_current_position() self.remaining_steps_update(ste) self.position_update(pos) current_velocity = self.stepper.get_current_velocity() if current_velocity != self.speedometer.value(): self.speedometer.set_velocity(current_velocity) except ip_connection.Error: return self.update_counter += 1 if self.update_counter % 10 == 0: self.update_infos() self.update_values() def velocity_slider_released(self): value = self.velocity_slider.value() self.velocity_spin.setValue(value) try: self.stepper.set_max_velocity(value) except ip_connection.Error: return def velocity_spin_finished(self): value = self.velocity_spin.value() self.velocity_slider.setValue(value) try: self.stepper.set_max_velocity(value) except ip_connection.Error: return def acceleration_slider_released(self): acc = self.acceleration_slider.value() dec = self.deceleration_slider.value() self.acceleration_spin.setValue(acc) try: self.stepper.set_speed_ramping(acc, dec) except ip_connection.Error: return def acceleration_spin_finished(self): acc = self.acceleration_spin.value() dec = self.deceleration_spin.value() self.acceleration_slider.setValue(acc) try: self.stepper.set_speed_ramping(acc, dec) except ip_connection.Error: return def deceleration_slider_released(self): acc = self.acceleration_slider.value() dec = self.deceleration_slider.value() self.deceleration_spin.setValue(dec) try: self.stepper.set_speed_ramping(acc, dec) except ip_connection.Error: return def deceleration_spin_finished(self): acc = self.acceleration_spin.value() dec = self.deceleration_spin.value() self.deceleration_slider.setValue(dec) try: self.stepper.set_speed_ramping(acc, dec) except ip_connection.Error: return def decay_slider_released(self): value = self.decay_slider.value() self.decay_spin.setValue(value) try: self.stepper.set_decay(value) except ip_connection.Error: return def decay_spin_finished(self): value = self.decay_spin.value() self.decay_slider.setValue(value) try: self.stepper.set_decay(value) except ip_connection.Error: return
class ImagesWidget(QWidget, Ui_Images): images = None def __init__(self, parent, app): super(QWidget, self).__init__() self.app = app self.setupUi(self) self.error_msg = QErrorMessage() self.error_msg.setWindowTitle("Starter Kit: Blinkenlights Demo " + config.DEMO_VERSION) self.slider_frame_rate.valueChanged.connect( self.slider_frame_rate_changed) self.spinbox_frame_rate.valueChanged.connect( self.spinbox_frame_rate_changed) self.button_choose.pressed.connect(self.choose_pressed) self.button_show.pressed.connect(self.show_pressed) self.button_default.pressed.connect(self.default_pressed) self.update_frame_rate_timer = QTimer(self) self.update_frame_rate_timer.timeout.connect(self.update_frame_rate) self.default_pressed() def start(self): self.images = Images(self.app.ipcon) self.update_frame_rate() self.images.frame_rendered(0) def stop(self): if self.images: self.images.stop_rendering() self.images = None def spinbox_frame_rate_changed(self, frame_rate): self.slider_frame_rate.setValue(frame_rate) self.update_frame_rate_timer.start(100) def slider_frame_rate_changed(self, frame_rate): self.spinbox_frame_rate.setValue(frame_rate) def show_pressed(self): if self.images: files = unicode(self.text_edit_files.toPlainText()).strip() if len(files) > 0: new_images = files.split('\n') try: self.images.set_new_images(new_images) except Exception as e: self.error_msg.showMessage(str(e)) self.images.frame_prepare_next() self.images.frame_rendered(0) def choose_pressed(self): dialog = QFileDialog() dialog.setDirectory(QDir.homePath()) dialog.setFileMode(QFileDialog.ExistingFiles) if dialog.exec_(): filenames = dialog.selectedFiles() for filename in filenames: self.text_edit_files.append(filename) def default_pressed(self): self.spinbox_frame_rate.setValue(1) def update_frame_rate(self): self.update_frame_rate_timer.stop() config.IMAGES_FRAME_RATE = self.spinbox_frame_rate.value() if self.images: self.images.update_frame_rate()
class Stepper(PluginBase, Ui_Stepper): qtcb_position_reached = pyqtSignal(int) qtcb_under_voltage = pyqtSignal(int) def __init__(self, *args): PluginBase.__init__(self, BrickStepper, *args) self.setupUi(self) self.stepper = self.device self.endis_all(False) self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_data) self.new_value = 0 self.update_counter = 0 self.full_brake_time = 0 self.qem = QErrorMessage(self) self.qem.setWindowTitle("Under Voltage") self.decay_widget.hide() self.setting_sync_rect_checkbox = False self.velocity_syncer = SliderSpinSyncer(self.velocity_slider, self.velocity_spin, self.velocity_changed) self.acceleration_syncer = SliderSpinSyncer(self.acceleration_slider, self.acceleration_spin, self.acceleration_changed) self.deceleration_syncer = SliderSpinSyncer(self.deceleration_slider, self.deceleration_spin, self.deceleration_changed) self.decay_syncer = SliderSpinSyncer(self.decay_slider, self.decay_spin, self.decay_changed) self.enable_checkbox.toggled.connect(self.enable_toggled) self.forward_button.clicked.connect(self.forward_clicked) self.stop_button.clicked.connect(self.stop_clicked) self.full_brake_button.clicked.connect(self.full_brake_clicked) self.backward_button.clicked.connect(self.backward_clicked) self.to_button.clicked.connect(self.to_button_clicked) self.steps_button.clicked.connect(self.steps_button_clicked) self.motor_current_button.clicked.connect(self.motor_current_button_clicked) self.minimum_motor_voltage_button.clicked.connect(self.minimum_motor_voltage_button_clicked) self.sync_rect_checkbox.toggled.connect(self.sync_rect_toggled) self.mode_dropbox.currentIndexChanged.connect(self.mode_changed) self.qtcb_position_reached.connect(self.cb_position_reached) self.stepper.register_callback(self.stepper.CALLBACK_POSITION_REACHED, self.qtcb_position_reached.emit) self.qtcb_under_voltage.connect(self.cb_under_voltage) self.stepper.register_callback(self.stepper.CALLBACK_UNDER_VOLTAGE, self.qtcb_under_voltage.emit) self.ste = 0 self.pos = 0 self.current_velocity = 0 self.cur = 0 self.sv = 0 self.ev = 0 self.mv = 0 self.mod = 0 if self.firmware_version >= (1, 1, 4): reset = QAction('Reset', self) reset.triggered.connect(lambda: self.stepper.reset()) self.set_actions(reset) def start(self): self.update_timer.start(100) self.update_start() def stop(self): self.update_timer.stop() def destroy(self): pass def get_url_part(self): return 'stepper' @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickStepper.DEVICE_IDENTIFIER def cb_position_reached(self, position): self.position_update(position) self.endis_all(True) def disable_list(self, button_list): for button in button_list: button.setEnabled(False) def endis_all(self, value): self.forward_button.setEnabled(value) self.stop_button.setEnabled(value) self.backward_button.setEnabled(value) self.to_button.setEnabled(value) self.steps_button.setEnabled(value) self.full_brake_button.setEnabled(value) def mode_changed(self, index): try: self.stepper.set_step_mode(1 << index) self.mod = 1 << index except ip_connection.Error: return def forward_clicked(self): try: self.stepper.drive_forward() except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button]) def backward_clicked(self): try: self.stepper.drive_backward() except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button]) def stop_clicked(self): try: self.stepper.stop() except ip_connection.Error: return self.endis_all(True) def full_brake_clicked(self): try: self.stepper.full_brake() except ip_connection.Error: return self.endis_all(True) def to_button_clicked(self): drive_to = self.to_spin.value() try: self.stepper.set_target_position(drive_to) except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button, self.forward_button, self.backward_button]) def steps_button_clicked(self): drive_steps = self.steps_spin.value() try: self.stepper.set_steps(drive_steps) except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button, self.forward_button, self.backward_button]) def motor_current_button_clicked(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(0) qid.setIntMaximum(2500) qid.setIntStep(100) async_call(self.stepper.get_motor_current, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.motor_current_selected) qid.setLabelText("Choose motor current in mA.") # "<font color=red>Setting this too high can destroy your Motor.</font>") qid.open() def minimum_motor_voltage_button_clicked(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(0) qid.setIntMaximum(40000) qid.setIntStep(100) async_call(self.stepper.get_minimum_voltage, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.minimum_motor_voltage_selected) qid.setLabelText("Choose minimum motor voltage in mV.") qid.open() def motor_current_selected(self, value): try: self.stepper.set_motor_current(value) except ip_connection.Error: return def minimum_motor_voltage_selected(self, value): try: self.stepper.set_minimum_voltage(value) except ip_connection.Error: return def cb_under_voltage(self, ov): mv_str = self.minimum_voltage_label.text() ov_str = "%gV" % round(ov/1000.0, 1) if not self.qem.isVisible(): self.qem.showMessage("Under Voltage: Output Voltage of " + ov_str + " is below minimum voltage of " + mv_str, "Stepper_UnderVoltage") def enable_toggled(self, checked): try: if checked: if not self.stepper.is_enabled(): self.endis_all(True) self.stepper.enable() else: if self.stepper.is_enabled(): self.endis_all(False) self.stepper.disable() except ip_connection.Error: return def sync_rect_toggled(self, checked): if not self.setting_sync_rect_checkbox and checked: rc = QMessageBox.warning(get_main_window(), 'Synchronous Rectification', 'If you want to use high speeds (> 10000 steps/s) for a large stepper motor with a ' + 'large inductivity we strongly suggest that you do not enable synchronous rectification. ' + 'Otherwise the Brick may not be able to cope with the load and overheat.', QMessageBox.Ok | QMessageBox.Cancel) if rc != QMessageBox.Ok: self.sync_rect_checkbox.setChecked(False) return try: self.stepper.set_sync_rect(checked) except ip_connection.Error: return self.decay_widget.setVisible(checked) def stack_input_voltage_update(self, sv): sv_str = "%gV" % round(sv/1000.0, 1) self.stack_voltage_label.setText(sv_str) def external_input_voltage_update(self, ev): ev_str = "%gV" % round(ev/1000.0, 1) self.external_voltage_label.setText(ev_str) def minimum_voltage_update(self, mv): mv_str = "%gV" % round(mv/1000.0, 1) self.minimum_voltage_label.setText(mv_str) def maximum_current_update(self, cur): cur_str = "%gA" % round(cur/1000.0, 1) self.maximum_current_label.setText(cur_str) def position_update(self, pos): pos_str = "%d" % pos self.position_label.setText(pos_str) def remaining_steps_update(self, ste): ste_str = "%d" % ste self.remaining_steps_label.setText(ste_str) def current_velocity_update(self, velocity): velocity_str = "%d" % velocity self.current_velocity_label.setText(velocity_str) self.speedometer.set_velocity(velocity) def mode_update(self, mod): if mod == 8: index = 3 elif mod == 4: index = 2 elif mod == 2: index = 1 else: index = 0 self.mode_dropbox.setCurrentIndex(index) def get_max_velocity_async(self, velocity): if not self.velocity_slider.isSliderDown(): if velocity != self.velocity_slider.sliderPosition(): self.velocity_slider.setSliderPosition(velocity) self.velocity_spin.setValue(velocity) def get_speed_ramping_async(self, ramp): acc, dec = ramp if not self.acceleration_slider.isSliderDown() and \ not self.deceleration_slider.isSliderDown(): if acc != self.acceleration_slider.sliderPosition(): self.acceleration_slider.setSliderPosition(acc) self.acceleration_spin.setValue(acc) if dec != self.deceleration_slider.sliderPosition(): self.deceleration_slider.setSliderPosition(dec) self.deceleration_spin.setValue(dec) def get_decay_async(self, decay): if not self.decay_slider.isSliderDown(): if decay != self.decay_slider.sliderPosition(): self.decay_slider.setSliderPosition(decay) self.decay_spin.setValue(decay) def is_enabled_async(self, enabled): if enabled: if not self.enable_checkbox.isChecked(): self.endis_all(True) self.enable_checkbox.setChecked(True) else: if self.enable_checkbox.isChecked(): self.endis_all(False) self.enable_checkbox.setChecked(False) def is_sync_rect_async(self, sync_rect): self.setting_sync_rect_checkbox = True self.sync_rect_checkbox.setChecked(sync_rect) self.setting_sync_rect_checkbox = False def update_start(self): async_call(self.stepper.get_max_velocity, None, self.get_max_velocity_async, self.increase_error_count) async_call(self.stepper.get_speed_ramping, None, self.get_speed_ramping_async, self.increase_error_count) async_call(self.stepper.get_decay, None, self.get_decay_async, self.increase_error_count) async_call(self.stepper.is_enabled, None, self.is_enabled_async, self.increase_error_count) async_call(self.stepper.is_sync_rect, None, self.is_sync_rect_async, self.increase_error_count) def update_data(self): async_call(self.stepper.get_remaining_steps, None, self.remaining_steps_update, self.increase_error_count) async_call(self.stepper.get_current_position, None, self.position_update, self.increase_error_count) async_call(self.stepper.get_current_velocity, None, self.current_velocity_update, self.increase_error_count) self.update_counter += 1 if self.update_counter % 10 == 0: async_call(self.stepper.get_motor_current, None, self.maximum_current_update, self.increase_error_count) async_call(self.stepper.get_stack_input_voltage, None, self.stack_input_voltage_update, self.increase_error_count) async_call(self.stepper.get_external_input_voltage, None, self.external_input_voltage_update, self.increase_error_count) async_call(self.stepper.get_minimum_voltage, None, self.minimum_voltage_update, self.increase_error_count) async_call(self.stepper.get_step_mode, None, self.mode_update, self.increase_error_count) def velocity_changed(self, value): try: self.stepper.set_max_velocity(value) except ip_connection.Error: return def acceleration_changed(self, value): dec = self.deceleration_spin.value() try: self.stepper.set_speed_ramping(value, dec) except ip_connection.Error: return def deceleration_changed(self, value): acc = self.acceleration_slider.value() try: self.stepper.set_speed_ramping(acc, value) except ip_connection.Error: return def decay_changed(self, value): try: self.stepper.set_decay(value) except ip_connection.Error: return
class WeatherStation(QApplication): HOST = "localhost" PORT = 4223 ipcon = None lcd = None al = None hum = None baro = None projects = [] active_project = None error_msg = None def __init__(self, args): super(QApplication, self).__init__(args) self.error_msg = QErrorMessage() self.ipcon = IPConnection() signal.signal(signal.SIGINT, self.exit_demo) signal.signal(signal.SIGTERM, self.exit_demo) timer = QTimer(self) timer.setSingleShot(True) timer.timeout.connect(self.connect) timer.start(1) def exit_demo(self, signl=None, frme=None): try: self.ipcon.disconnect() self.timer.stop() self.tabs.destroy() except: pass sys.exit() def open_gui(self): self.main = MainWindow(self) self.main.setFixedSize(730, 430) self.main.setWindowIcon(QIcon(os.path.join(ProgramPath.program_path(), "demo-icon.png"))) self.tabs = QTabWidget() widget = QWidget() layout = QVBoxLayout() layout.addWidget(self.tabs) widget.setLayout(layout) self.main.setCentralWidget(widget) self.projects.append(ProjectEnvDisplay(self.tabs, self)) self.projects.append(ProjectStatistics(self.tabs, self)) self.projects.append(ProjectXively(self.tabs, self)) self.tabs.addTab(self.projects[0], "Display Environment Measurements") self.tabs.addTab(self.projects[1], "Show Statistics with Button Control") self.tabs.addTab(self.projects[2], "Connect to Xively") self.active_project = self.projects[0] self.tabs.currentChanged.connect(self.tabChangedSlot) self.main.setWindowTitle("Starter Kit: Weather Station Demo " + config.DEMO_VERSION) self.main.show() def connect(self): try: self.ipcon.connect(WeatherStation.HOST, WeatherStation.PORT) except Error as e: self.error_msg.showMessage('Connection Error: ' + str(e.description) + "\nBrickd installed and running?") return except socket.error as e: self.error_msg.showMessage('Socket error: ' + str(e) + "\nBrickd installed and running?") return self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE, self.cb_enumerate) self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED, self.cb_connected) try: self.ipcon.enumerate() except Error as e: self.error_msg.showMessage('Enumerate Error: ' + str(e.description)) return self.open_gui() def tabChangedSlot(self, tabIndex): if self.lcd is not None: self.lcd.clear_display() self.active_project = self.projects[tabIndex] def cb_illuminance(self, illuminance): for p in self.projects: p.update_illuminance(illuminance) def cb_humidity(self, humidity): for p in self.projects: p.update_humidity(humidity) def cb_air_pressure(self, air_pressure): for p in self.projects: p.update_air_pressure(air_pressure) try: temperature = self.baro.get_chip_temperature() except Error as e: print('Could not get temperature: ' + str(e.description)) return for p in self.projects: p.update_temperature(temperature) def configure_custom_chars(self): c = [[0x00 for x in range(8)] for y in range(8)] c[0] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff] c[1] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff] c[2] = [0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff] c[3] = [0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff] c[4] = [0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff] c[5] = [0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] c[6] = [0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] c[7] = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] for i in range(len(c)): self.lcd.set_custom_character(i, c[i]); def cb_button_pressed(self, button): for p in self.projects: p.button_pressed(button) def cb_enumerate(self, uid, connected_uid, position, hardware_version, firmware_version, device_identifier, enumeration_type): if enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED or \ enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE: if device_identifier == LCD20x4.DEVICE_IDENTIFIER: try: self.lcd = LCD20x4(uid, self.ipcon) self.lcd.clear_display() self.lcd.backlight_on() self.lcd.register_callback(self.lcd.CALLBACK_BUTTON_PRESSED, self.cb_button_pressed) self.configure_custom_chars() except Error as e: self.error_msg.showMessage('LCD 20x4 init failed: ' + str(e.description)) self.lcd = None elif device_identifier == AmbientLight.DEVICE_IDENTIFIER: try: self.al = AmbientLight(uid, self.ipcon) self.al.set_illuminance_callback_period(1000) self.al.register_callback(self.al.CALLBACK_ILLUMINANCE, self.cb_illuminance) except Error as e: self.error_msg.showMessage('Ambient Light init failed: ' + str(e.description)) self.al = None elif device_identifier == Humidity.DEVICE_IDENTIFIER: try: self.hum = Humidity(uid, self.ipcon) self.hum.set_humidity_callback_period(1000) self.hum.register_callback(self.hum.CALLBACK_HUMIDITY, self.cb_humidity) except Error as e: self.error_msg.showMessage('Humidity init failed: ' + str(e.description)) self.hum = None elif device_identifier == Barometer.DEVICE_IDENTIFIER: try: self.baro = Barometer(uid, self.ipcon) self.baro.set_air_pressure_callback_period(1000) self.baro.register_callback(self.baro.CALLBACK_AIR_PRESSURE, self.cb_air_pressure) except Error as e: self.error_msg.showMessage('Barometer init failed: ' + str(e.description)) self.baro = None def cb_connected(self, connected_reason): if connected_reason == IPConnection.CONNECT_REASON_AUTO_RECONNECT: while True: try: self.ipcon.enumerate() break except Error as e: self.error_msg.showMessage('Enumerate Error: ' + str(e.description)) time.sleep(1)
class Stepper(PluginBase, Ui_Stepper): qtcb_position_reached = pyqtSignal(int) qtcb_under_voltage = pyqtSignal(int) def __init__(self, ipcon, uid, version): PluginBase.__init__(self, ipcon, uid, 'Stepper Brick', version) self.setupUi(self) self.stepper = BrickStepper(uid, ipcon) self.device = self.stepper self.endis_all(False) self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_data) self.speedometer = SpeedoMeter() self.vertical_layout_right.insertWidget(5, self.speedometer) self.new_value = 0 self.update_counter = 0 self.full_brake_time = 0 self.qem = QErrorMessage(self) self.qem.setWindowTitle("Under Voltage") self.velocity_slider.sliderReleased.connect(self.velocity_slider_released) self.velocity_slider.valueChanged.connect(self.velocity_spin.setValue) self.velocity_spin.editingFinished.connect(self.velocity_spin_finished) self.acceleration_slider.sliderReleased.connect(self.acceleration_slider_released) self.acceleration_slider.valueChanged.connect(self.acceleration_spin.setValue) self.acceleration_spin.editingFinished.connect(self.acceleration_spin_finished) self.deceleration_slider.sliderReleased.connect(self.deceleration_slider_released) self.deceleration_slider.valueChanged.connect(self.deceleration_spin.setValue) self.deceleration_spin.editingFinished.connect(self.deceleration_spin_finished) # self.decay_slider.sliderReleased.connect(self.decay_slider_released) # self.decay_slider.valueChanged.connect(self.decay_spin.setValue) # self.decay_spin.editingFinished.connect(self.decay_spin_finished) self.enable_checkbox.stateChanged.connect(self.enable_state_changed) self.forward_button.pressed.connect(self.forward_pressed) self.stop_button.pressed.connect(self.stop_pressed) self.full_brake_button.pressed.connect(self.full_brake_pressed) self.backward_button.pressed.connect(self.backward_pressed) self.to_button.pressed.connect(self.to_button_pressed) self.steps_button.pressed.connect(self.steps_button_pressed) self.motor_current_button.pressed.connect(self.motor_current_button_pressed) self.minimum_motor_voltage_button.pressed.connect(self.minimum_motor_voltage_button_pressed) self.mode_dropbox.currentIndexChanged.connect(self.mode_changed) self.qtcb_position_reached.connect(self.cb_position_reached) self.stepper.register_callback(self.stepper.CALLBACK_POSITION_REACHED, self.qtcb_position_reached.emit) self.qtcb_under_voltage.connect(self.cb_under_voltage) self.stepper.register_callback(self.stepper.CALLBACK_UNDER_VOLTAGE, self.qtcb_under_voltage.emit) self.update_data_async_thread = None self.ste = 0 self.pos = 0 self.current_velocity = 0 self.cur = 0 self.sv = 0 self.ev = 0 self.mv = 0 self.mod = 0 def start(self): self.update_timer.start(100) self.update_start() def stop(self): self.update_timer.stop() def has_reset_device(self): return self.version >= (1, 1, 4) def reset_device(self): if self.has_reset_device(): self.stepper.reset() def is_brick(self): return True def get_url_part(self): return 'stepper' @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickStepper.DEVICE_IDENTIFIER def cb_position_reached(self, position): self.position_update(position) self.endis_all(True) def disable_list(self, button_list): for button in button_list: button.setEnabled(False) def endis_all(self, value): self.forward_button.setEnabled(value) self.stop_button.setEnabled(value) self.backward_button.setEnabled(value) self.to_button.setEnabled(value) self.steps_button.setEnabled(value) self.full_brake_button.setEnabled(value) def mode_changed(self, index): try: self.stepper.set_step_mode(1 << index) self.mod = 1 << index except ip_connection.Error: return def forward_pressed(self): try: self.stepper.drive_forward() except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button]) def backward_pressed(self): try: self.stepper.drive_backward() except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button]) def stop_pressed(self): try: self.stepper.stop() except ip_connection.Error: return self.endis_all(True) def full_brake_pressed(self): try: self.stepper.full_brake() except ip_connection.Error: return self.endis_all(True) def to_button_pressed(self): drive_to = self.to_spin.value() try: self.stepper.set_target_position(drive_to) except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button, self.forward_button, self.backward_button]) def steps_button_pressed(self): drive_steps = self.steps_spin.value() try: self.stepper.set_steps(drive_steps) except ip_connection.Error: return self.disable_list([self.to_button, self.steps_button, self.forward_button, self.backward_button]) def motor_current_button_pressed(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(0) qid.setIntMaximum(2500) qid.setIntStep(100) async_call(self.stepper.get_motor_current, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.motor_current_selected) qid.setLabelText("Choose motor current in mA.") # "<font color=red>Setting this too high can destroy your Motor.</font>") qid.open() def minimum_motor_voltage_button_pressed(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(0) qid.setIntMaximum(40000) qid.setIntStep(100) async_call(self.stepper.get_minimum_voltage, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.minimum_motor_voltage_selected) qid.setLabelText("Choose minimum motor voltage in mV.") qid.open() def motor_current_selected(self, value): try: self.stepper.set_motor_current(value) except ip_connection.Error: return def minimum_motor_voltage_selected(self, value): try: self.stepper.set_minimum_voltage(value) except ip_connection.Error: return def cb_under_voltage(self, ov): mv_str = self.minimum_voltage_label.text() ov_str = "%gV" % round(ov/1000.0, 1) if not self.qem.isVisible(): self.qem.showMessage("Under Voltage: Output Voltage of " + ov_str + " is below minimum voltage of " + mv_str, "Stepper_UnderVoltage") def enable_state_changed(self, state): try: if state == Qt.Checked: self.endis_all(True) self.stepper.enable() elif state == Qt.Unchecked: self.endis_all(False) self.stepper.disable() except ip_connection.Error: return def stack_input_voltage_update(self, sv): sv_str = "%gV" % round(sv/1000.0, 1) self.stack_voltage_label.setText(sv_str) def external_input_voltage_update(self, ev): ev_str = "%gV" % round(ev/1000.0, 1) self.external_voltage_label.setText(ev_str) def minimum_voltage_update(self, mv): mv_str = "%gV" % round(mv/1000.0, 1) self.minimum_voltage_label.setText(mv_str) def maximum_current_update(self, cur): cur_str = "%gA" % round(cur/1000.0, 1) self.maximum_current_label.setText(cur_str) def position_update(self, pos): pos_str = "%d" % pos self.position_label.setText(pos_str) def remaining_steps_update(self, ste): ste_str = "%d" % ste self.remaining_steps_label.setText(ste_str) def mode_update(self, mod): if mod == 8: index = 3 elif mod == 4: index = 2 elif mod == 2: index = 1 else: index = 0 self.mode_dropbox.setCurrentIndex(index) def get_max_velocity_async(self, velocity): if not self.velocity_slider.isSliderDown(): if velocity != self.velocity_slider.sliderPosition(): self.velocity_slider.setSliderPosition(velocity) self.velocity_spin.setValue(velocity) def get_speed_ramping_async(self, ramp): acc, dec = ramp if not self.acceleration_slider.isSliderDown() and \ not self.deceleration_slider.isSliderDown(): if acc != self.acceleration_slider.sliderPosition(): self.acceleration_slider.setSliderPosition(acc) self.acceleration_spin.setValue(acc) if dec != self.deceleration_slider.sliderPosition(): self.deceleration_slider.setSliderPosition(dec) self.deceleration_spin.setValue(dec) def is_enabled_async(self, enabled): if enabled: if self.enable_checkbox.checkState() != Qt.Checked: self.endis_all(True) self.enable_checkbox.setCheckState(Qt.Checked) else: if self.enable_checkbox.checkState() != Qt.Unchecked: self.endis_all(False) self.enable_checkbox.setCheckState(Qt.Unchecked) def update_start(self): async_call(self.stepper.get_max_velocity, None, self.get_max_velocity_async, self.increase_error_count) async_call(self.stepper.get_speed_ramping, None, self.get_speed_ramping_async, self.increase_error_count) async_call(self.stepper.is_enabled, None, self.is_enabled_async, self.increase_error_count) def update_data(self): async_call(self.stepper.get_remaining_steps, None, self.remaining_steps_update, self.increase_error_count) async_call(self.stepper.get_current_position, None, self.position_update, self.increase_error_count) async_call(self.stepper.get_current_velocity, None, self.speedometer.set_velocity, self.increase_error_count) self.update_counter += 1 if self.update_counter % 10 == 0: async_call(self.stepper.get_motor_current, None, self.maximum_current_update, self.increase_error_count) async_call(self.stepper.get_stack_input_voltage, None, self.stack_input_voltage_update, self.increase_error_count) async_call(self.stepper.get_external_input_voltage, None, self.external_input_voltage_update, self.increase_error_count) async_call(self.stepper.get_minimum_voltage, None, self.minimum_voltage_update, self.increase_error_count) async_call(self.stepper.get_step_mode, None, self.mode_update, self.increase_error_count) def velocity_slider_released(self): value = self.velocity_slider.value() self.velocity_spin.setValue(value) try: self.stepper.set_max_velocity(value) except ip_connection.Error: return def velocity_spin_finished(self): value = self.velocity_spin.value() self.velocity_slider.setValue(value) try: self.stepper.set_max_velocity(value) except ip_connection.Error: return def acceleration_slider_released(self): acc = self.acceleration_slider.value() dec = self.deceleration_slider.value() self.acceleration_spin.setValue(acc) try: self.stepper.set_speed_ramping(acc, dec) except ip_connection.Error: return def acceleration_spin_finished(self): acc = self.acceleration_spin.value() dec = self.deceleration_spin.value() self.acceleration_slider.setValue(acc) try: self.stepper.set_speed_ramping(acc, dec) except ip_connection.Error: return def deceleration_slider_released(self): acc = self.acceleration_slider.value() dec = self.deceleration_slider.value() self.deceleration_spin.setValue(dec) try: self.stepper.set_speed_ramping(acc, dec) except ip_connection.Error: return def deceleration_spin_finished(self): acc = self.acceleration_spin.value() dec = self.deceleration_spin.value() self.deceleration_slider.setValue(dec) try: self.stepper.set_speed_ramping(acc, dec) except ip_connection.Error: return
class ProjectXively(QWidget): qtcb_update_illuminance = pyqtSignal(float) qtcb_update_air_pressure = pyqtSignal(float) qtcb_update_temperature = pyqtSignal(float) qtcb_update_humidity = pyqtSignal(float) qtcb_button_pressed = pyqtSignal(int) lcdwidget = None xively_host = "api.xively.com" xively_agent = "Tinkerforge Starter Kit Weather Station Demo" xively_channel = "Enter Feed ID here" xively_api_key = "Enter API Key here" xively_items = {} xively_headers = None xively_params = "" xively_update_rate = 5 # in minutes text_agent = None text_channel = None text_api_key = None number_update_rate = None save_button = None xively_timer = None error_message = None label_upload_active = None last_upload = None def __init__(self, parent, app): super(QWidget, self).__init__() self.lcdwidget = LCDWidget(self, app) self.lcdwidget.hide() self.text_agent = QLineEdit(self) self.text_agent.setText(self.xively_agent) self.text_channel = QLineEdit(self) self.text_channel.setText(self.xively_channel) self.text_api_key = QLineEdit(self) self.text_api_key.setText(self.xively_api_key) self.number_update_rate = QSpinBox(self) self.number_update_rate.setRange(1, 1440) self.number_update_rate.setSuffix(' min') self.number_update_rate.setValue(self.xively_update_rate) layout1 = QHBoxLayout() layout2 = QVBoxLayout() layout1.addStretch() layout1.addLayout(layout2) layout1.addStretch() layout2.addSpacerItem(QSpacerItem(LCDWidget.FIXED_WIDGTH, 0)) label = QLabel(self) label.setText("Project: <b>Connect to Xively</b>. This project uploads the measured values to Xively. Please find documentation how to configure it and program sources in Python <a href=\"http://www.tinkerforge.com/en/doc/Kits/WeatherStation/WeatherStation.html#connect-to-xively\">here</a>.<br>") label.setTextFormat(Qt.RichText) label.setTextInteractionFlags(Qt.TextBrowserInteraction) label.setOpenExternalLinks(True) label.setWordWrap(True) label.setAlignment(Qt.AlignJustify) layout2.addSpacing(10) layout2.addWidget(label) layout2.addSpacing(10) layout3a = QHBoxLayout() label = QLabel("Agent Description:") label.setMinimumWidth(150) layout3a.addWidget(label) layout3a.addWidget(self.text_agent, 1) layout2.addLayout(layout3a) layout2.addSpacing(10) layout3b = QHBoxLayout() label = QLabel("Feed:") label.setMinimumWidth(150) layout3b.addWidget(label) layout3b.addWidget(self.text_channel, 1) layout2.addLayout(layout3b) layout2.addSpacing(10) layout3c = QHBoxLayout() label = QLabel("API Key:") label.setMinimumWidth(150) layout3c.addWidget(label) layout3c.addWidget(self.text_api_key, 1) layout2.addLayout(layout3c) layout2.addSpacing(10) layout3d = QHBoxLayout() label = QLabel("Update Rate:") label.setMinimumWidth(150) layout3d.addWidget(label) layout3d.addWidget(self.number_update_rate, 1) layout2.addLayout(layout3d) layout2.addSpacing(10) self.label_upload_active = QLabel("Not Active", self) self.label_upload_active.setMinimumWidth(150) font = QFont() font.setPixelSize(20) self.label_upload_active.setFont(font) self.set_active_label(False) self.save_button = QPushButton("Save/Activate") layout4 = QHBoxLayout() layout4.addWidget(self.label_upload_active) layout4.addWidget(self.save_button, 1) layout2.addLayout(layout4) layout2.addStretch() self.setLayout(layout1) self.qtcb_update_illuminance.connect(self.update_illuminance_data_slot) self.qtcb_update_air_pressure.connect(self.update_air_pressure_data_slot) self.qtcb_update_temperature.connect(self.update_temperature_data_slot) self.qtcb_update_humidity.connect(self.update_humidity_data_slot) self.qtcb_button_pressed.connect(self.button_pressed_slot) self.save_button.clicked.connect(self.save_configuration) self.lcdwidget.clear(self) self.error_message = QErrorMessage(self) def set_active_label(self, value): palette = self.label_upload_active.palette() if value: palette.setColor(self.foregroundRole(), Qt.darkGreen) self.label_upload_active.setText("Active") else: palette.setColor(self.foregroundRole(), Qt.red) self.label_upload_active.setText("Not Active") self.label_upload_active.setPalette(palette) def save_configuration(self): try: self.xively_agent = str(self.text_agent.text()).decode('ascii') self.xively_channel = str(self.text_channel.text()).decode('ascii') self.xively_api_key = str(self.text_api_key.text()).decode('ascii') except: self.error_message.showMessage('Agent, Feed and API Key can only contain ASCII characters') return self.xively_update_rate = self.number_update_rate.value() self.xively_headers = { "Content-Type" : "application/x-www-form-urlencoded", "X-ApiKey" : self.xively_api_key, "User-Agent" : self.xively_agent, } self.xively_params = "/v2/feeds/" + self.xively_channel if self.xively_timer is None: self.xively_timer = QTimer(self) self.xively_timer.timeout.connect(self.update_xively) self.xively_timer.start(self.xively_update_rate*60*1000) self.set_active_label(True) self.update_xively() def write_lcd(self): if self.last_upload == None: tmp = "Last: Never" else: tmp = "Last: " + self.last_upload self.lcdwidget.write_line(0, 0, "Xively Upload", self) self.lcdwidget.write_line(2, 0, tmp, self) def update_xively(self): if len(self.xively_items) == 0: return stream_items = [] for identifier, value in self.xively_items.items(): stream_items.append({'id': identifier, 'current_value': value[0], 'min_value': value[1], 'max_value': value[2]}) data = {'version': '1.0.0', 'datastreams': stream_items} self.xively_items = {} body = json.dumps(data) try: http = httplib.HTTPSConnection(self.xively_host) http.request('PUT', self.xively_params, body, self.xively_headers) response = http.getresponse() http.close() if response.status != 200: self.error_message.showMessage('Could not upload to xively -> Response:' + str(response.status) + ': ' + response.reason + '. Check your configuration.') self.xively_timer.stop() self.xively_timer = None self.set_active_label(False) return except Exception as e: self.error_message.showMessage('HTTP error: ' + str(e)) self.xively_timer.stop() self.xively_timer = None self.set_active_label(False) return # set upload time if upload was a success self.last_upload = time.strftime("%H:%M:%S") def put(self, identifier, value): self.write_lcd() try: _, min_value, max_value = self.xively_items[identifier] if value < min_value: min_value = value if value > max_value: max_value = value self.xively_items[identifier] = (value, min_value, max_value) except: self.xively_items[identifier] = (value, value, value) def update_illuminance_data_slot(self, illuminance): self.put('AmbientLight', illuminance/10.0) def update_illuminance(self, illuminance): self.qtcb_update_illuminance.emit(illuminance) def update_humidity_data_slot(self, humidity): self.put('Humidity', humidity/10.0) def update_humidity(self, humidity): self.qtcb_update_humidity.emit(humidity) def update_air_pressure_data_slot(self, air_pressure): self.put('AirPressure', air_pressure/1000.0) def update_air_pressure(self, air_pressure): self.qtcb_update_air_pressure.emit(air_pressure) def update_temperature_data_slot(self, temperature): self.put('Temperature', temperature/100.0) def update_temperature(self, temperature): self.qtcb_update_temperature.emit(temperature) def button_pressed_slot(self, button): pass def button_pressed(self, button): self.qtcb_button_pressed.emit(button)
class Editor(editor_base.EditorBase): """Representa el editor de texto que aparece en el panel derecho. El editor soporta autocompletado de código y resaltado de sintáxis. """ # Señal es emitida cuando el Editor ejecuta codigo signal_ejecutando = QtCore.pyqtSignal() def __init__(self, main, interpreterLocals, consola_lanas, ventana_interprete): super(Editor, self).__init__() self.cantidad_ejecuciones = 0 self.consola_lanas = consola_lanas self.ventana_interprete = ventana_interprete self.ruta_del_archivo_actual = None self.interpreterLocals = interpreterLocals self.setLineWrapMode(QTextEdit.NoWrap) self._cambios_sin_guardar = False self.main = main self.nombre_de_archivo_sugerido = "" self.watcher = pilasengine.watcher.Watcher(None, self.cuando_cambia_archivo_de_forma_externa) def crear_archivo_inicial(self): dirpath = tempfile.mkdtemp() archivo_temporal = os.path.join(dirpath, "mi_juego.py") archivo = codecs.open(archivo_temporal, "w", 'utf-8') archivo.write(CODIGO_INICIAL) archivo.close() #print("Creando el archivo " + str(archivo_temporal)) self.abrir_archivo_del_proyecto(archivo_temporal) def es_archivo_iniciar_sin_guardar(self): return self.nombre_de_archivo_sugerido == "" def crear_y_seleccionar_archivo(self, nombre): # Quita la extension si llega a tenerla. nombre = nombre.replace('.py', '') nombre += ".py" nombre_de_archivo = nombre if self.ruta_del_archivo_actual: base_path = os.path.abspath(os.path.dirname(self.ruta_del_archivo_actual)) ruta = os.path.join(base_path, unicode(nombre_de_archivo)) else: ruta = unicode(nombre_de_archivo) if os.path.exists(ruta): self._tmp_dialog = QErrorMessage(self) self._tmp_dialog.showMessage("Ya existe un archivo con ese nombre") else: self._crear_archivo_nuevo_en(ruta) self.cargar_contenido_desde_archivo(ruta) self.ruta_del_archivo_actual = ruta self.watcher.cambiar_archivo_a_observar(ruta) self.ejecutar() self.main.actualizar_el_listado_de_archivos() def _crear_archivo_nuevo_en(self, ruta): fo = open(ruta, "wb") fo.write("# contenido") fo.close() def obtener_archivos_del_proyecto(self): base_path = os.path.dirname(self.nombre_de_archivo_sugerido) listado = os.listdir(base_path) return [x for x in listado if x.endswith('.py')] def keyPressEvent(self, event): "Atiene el evento de pulsación de tecla." self._cambios_sin_guardar = True # Permite usar tab como seleccionador de la palabra actual # en el popup de autocompletado. if event.key() in [Qt.Key_Tab]: if self.completer and self.completer.popup().isVisible(): event.ignore() nuevo_evento = QKeyEvent(QKeyEvent.KeyPress, Qt.Key_Return, Qt.NoModifier) try: if self.autocomplete(nuevo_evento): return None except UnicodeEncodeError: pass return None if editor_base.EditorBase.keyPressEvent(self, event): return None # Elimina los pares de caracteres especiales si los encuentra if event.key() == Qt.Key_Backspace: self._eliminar_pares_de_caracteres() self._borrar_un_grupo_de_espacios(event) if self.autocomplete(event): return None if event.key() == Qt.Key_Return: cursor = self.textCursor() block = self.document().findBlockByNumber(cursor.blockNumber()) whitespace = re.match(r"(\s*)", unicode(block.text())).group(1) linea_anterior = str(block.text()[:]) cantidad_espacios = linea_anterior.count(' ') / 4 if linea_anterior[-1:] == ':': whitespace = ' ' * (cantidad_espacios + 1) else: whitespace = ' ' * (cantidad_espacios) QTextEdit.keyPressEvent(self, event) return self.insertPlainText(whitespace) return QTextEdit.keyPressEvent(self, event) def _borrar_un_grupo_de_espacios(self, event): cursor = self.textCursor() block = self.document().findBlockByNumber(cursor.blockNumber()) whitespace = re.match(r"(.*)", unicode(block.text())).group(1) if whitespace.endswith(' '): QTextEdit.keyPressEvent(self, event) QTextEdit.keyPressEvent(self, event) QTextEdit.keyPressEvent(self, event) def tiene_cambios_sin_guardar(self): return self._cambios_sin_guardar def _get_current_line(self): "Obtiene la linea en donde se encuentra el cursor." tc = self.textCursor() tc.select(QTextCursor.LineUnderCursor) return tc.selectedText() def _get_position_in_block(self): tc = self.textCursor() position = tc.positionInBlock() - 1 return position def cargar_contenido_desde_archivo(self, ruta): "Carga todo el contenido del archivo indicado por ruta." with codecs.open(unicode(ruta), 'r', 'utf-8') as archivo: contenido = archivo.read() self.setText(contenido) self.nombre_de_archivo_sugerido = ruta self._cambios_sin_guardar = False def abrir_dialogo_cargar_archivo(self): return QFileDialog.getOpenFileName(self, "Abrir Archivo", self.nombre_de_archivo_sugerido, "Archivos python (*.py)", options=QFileDialog.DontUseNativeDialog) def abrir_archivo_del_proyecto(self, nombre_de_archivo): if self.tiene_cambios_sin_guardar(): if self.mensaje_guardar_cambios_abrir(): if not self.guardar_contenido_con_dialogo(): return else: return if self.ruta_del_archivo_actual: base_path = os.path.dirname(self.ruta_del_archivo_actual) ruta = os.path.join(base_path, unicode(nombre_de_archivo)) else: ruta = unicode(nombre_de_archivo) self.cargar_contenido_desde_archivo(ruta) self.ruta_del_archivo_actual = ruta self.watcher.cambiar_archivo_a_observar(ruta) self.ejecutar() self.main.actualizar_el_listado_de_archivos() def abrir_archivo_con_dialogo(self): if self.tiene_cambios_sin_guardar(): if self.mensaje_guardar_cambios_abrir(): if not self.guardar_contenido_con_dialogo(): return else: return ruta = self.abrir_dialogo_cargar_archivo() if ruta: ruta = unicode(ruta) self.cargar_contenido_desde_archivo(ruta) self.ruta_del_archivo_actual = ruta self.watcher.cambiar_archivo_a_observar(ruta) self.ejecutar() self.main.actualizar_el_listado_de_archivos() def cuando_cambia_archivo_de_forma_externa(self): self.recargar_archivo_actual() def recargar_archivo_actual(self): if self.ruta_del_archivo_actual: self.cargar_contenido_desde_archivo(self.ruta_del_archivo_actual) self.ejecutar() def mensaje_guardar_cambios_abrir(self): """Realizar una consulta usando un cuadro de dialogo simple se utiliza cuando hay cambios sin guardar y se desea abrir un archivo. Retorna True si el usuario presiona el boton *Guardar*, Retorna False si el usuario presiona *No*.""" titulo = u"¿Deseas guardar el contenido antes de abrir un archivo?" mensaje = u"El contenido se perdera sino los guardas" mensaje = QMessageBox.question(self, titulo, mensaje, "Guardar", "No") return (not mensaje) def mensaje_guardar_cambios_salir(self): """Realizar una consulta usando un cuadro de dialogo simple se utiliza cuando hay cambios sin guardar y se desa salir del Editor. Retorna 0 si el usuario presiona el boton *Salir sin guardar*, Retorna 1 si el usuario presiona *Guardar* Retorna 2 si presiona *Cancelar*.""" titulo = u"¿Deseas guardar el contenido antes de salir?" mensaje = u"El contenido se perdera sino los guardas" return QMessageBox.question(self, titulo, mensaje, "Salir sin guardar", "Guardar", "Cancelar") def marcar_error_en_la_linea(self, numero, descripcion): hi_selection = QTextEdit.ExtraSelection() hi_selection.format.setBackground(QColor(255, 220, 220)) hi_selection.format.setProperty(QTextFormat.FullWidthSelection, QVariant(True)) hi_selection.cursor = self.textCursor() posicion_linea = self.document().findBlockByLineNumber(numero).position() hi_selection.cursor.setPosition(posicion_linea) hi_selection.cursor.clearSelection() self.setExtraSelections([hi_selection]) def guardar_contenido_con_dialogo(self): ruta = self.abrir_dialogo_guardar_archivo() if not ruta: return False ruta = unicode(ruta) if not ruta.endswith('.py'): ruta += '.py' if ruta: self.guardar_contenido_en_el_archivo(ruta) self._cambios_sin_guardar = False self.ruta_del_archivo_actual = ruta self.nombre_de_archivo_sugerido = ruta self.watcher.cambiar_archivo_a_observar(ruta) self.cargar_contenido_desde_archivo(ruta) self.ejecutar() self.main.actualizar_el_listado_de_archivos() self.main.habilitar_boton_nuevo() return True def guardar_contenido_directamente(self): if self.nombre_de_archivo_sugerido: self.guardar_contenido_en_el_archivo(self.nombre_de_archivo_sugerido) self._cambios_sin_guardar = False self.main.actualizar_el_listado_de_archivos() self.prevenir_live_reload() else: self.guardar_contenido_con_dialogo() def prevenir_live_reload(self): self.watcher.prevenir_reinicio() def salir(self): """Retorna True si puede salir y False si no""" if self.tiene_cambios_sin_guardar(): mensaje = self.mensaje_guardar_cambios_salir() if mensaje == 1: self.guardar_contenido_con_dialogo() elif mensaje == 2: return False return True def obtener_contenido(self): return unicode(self.document().toPlainText()) def ejecutar(self): ruta_personalizada = os.path.dirname(self.ruta_del_archivo_actual) #print "ejecutando texto desde widget editor" texto = self.obtener_contenido() #texto = self.editor.obtener_texto_sanitizado(self) # elimina cabecera de encoding. contenido = re.sub('coding\s*:\s*', '', texto) contenido = contenido.replace('import pilasengine', '') contenido = contenido.replace('pilas = pilasengine.iniciar', 'pilas.reiniciar') for x in contenido.split('\n'): if "__file__" in x: contenido = contenido.replace(x, "# livecoding: " + x + "\n") sys.path.append(ruta_personalizada) self.interpreterLocals['sys'] = sys # Muchos códigos personalizados necesitan cargar imágenes o sonidos # desde el directorio que contiene al archivo. Para hacer esto posible, # se llama a la función "pilas.utils.agregar_ruta_personalizada" con el # path al directorio que representa el script. Así la función "obtener_ruta_al_recurso" # puede evaluar al directorio del script en busca de recursos también. if ruta_personalizada: ruta_personalizada = ruta_personalizada.replace('\\', '/') agregar_ruta_personalizada = 'pilas.utils.agregar_ruta_personalizada("%s")' %(ruta_personalizada) contenido = contenido.replace('pilas.reiniciar(', agregar_ruta_personalizada+'\n'+'pilas.reiniciar(') modulos_a_recargar = [x for x in self.interpreterLocals.values() if inspect.ismodule(x) and x.__name__ not in ['pilasengine', 'inspect'] and 'pilasengine.' not in x.__name__] for m in modulos_a_recargar: reload(m) self.cantidad_ejecuciones += 1 # Limpia la consola a partir de la primer ejecucion luego de iniciar. if self.cantidad_ejecuciones > 1: self.main.limpiar_interprete() try: exec(contenido, self.interpreterLocals) except Exception, e: self.consola_lanas.insertar_error_desde_exception(e) self.ventana_interprete.mostrar_el_interprete() #self.marcar_error_en_la_linea(10, "pepepe") self.signal_ejecutando.emit()
class Blinkenlights(QApplication): HOST = "localhost" PORT = 4223 ipcon = None projects = [] active_project = None error_msg = None def __init__(self, args): super(QApplication, self).__init__(args) self.error_msg = QErrorMessage() self.error_msg.setWindowTitle("Starter Kit: Blinkenlights Demo " + config.DEMO_VERSION) signal.signal(signal.SIGINT, self.exit_demo) signal.signal(signal.SIGTERM, self.exit_demo) self.make_gui() self.connect() def exit_demo(self, signl=None, frme=None): try: self.ipcon.disconnect() self.timer.stop() self.tabs.destroy() except: pass sys.exit() def make_gui(self): self.main = MainWindow(self) self.main.setWindowIcon(QIcon(os.path.join(ProgramPath.program_path(), "demo-icon.png"))) self.tabs = QTabWidget() widget = QWidget() layout = QVBoxLayout() layout.addWidget(self.tabs) widget.setLayout(layout) self.main.setCentralWidget(widget) self.setup = SetupWidget(self.tabs, self) self.tetris = TetrisWidget(self.tabs, self) self.pong = PongWidget(self.tabs, self) self.fire = FireWidget(self.tabs, self) self.text = TextWidget(self.tabs, self) self.images = ImagesWidget(self.tabs, self) self.rainbow = RainbowWidget(self.tabs, self) self.projects.append(self.setup) self.projects.append(self.tetris) self.projects.append(self.pong) self.projects.append(self.fire) self.projects.append(self.text) self.projects.append(self.images) self.projects.append(self.rainbow) self.tabs.addTab(self.setup, "Setup") self.tabs.addTab(self.tetris, "Tetris") self.tabs.addTab(self.pong, "Pong") self.tabs.addTab(self.fire, "Fire") self.tabs.addTab(self.text, "Text") self.tabs.addTab(self.images, "Images") self.tabs.addTab(self.rainbow, "Rainbow") self.active_project = self.projects[0] self.tabs.currentChanged.connect(self.tab_changed_slot) self.main.setWindowTitle("Starter Kit: Blinkenlights Demo " + config.DEMO_VERSION) self.main.show() def connect(self): config.UID_LED_STRIP_BRICKLET = None self.setup.label_led_strip_found.setText('No') self.setup.label_led_strip_uid.setText('None') config.UID_MULTI_TOUCH_BRICKLET = None self.setup.label_multi_touch_found.setText('No') self.setup.label_multi_touch_uid.setText('None') config.UID_DUAL_BUTTON_BRICKLET = (None, None) self.setup.label_dual_button1_found.setText('No') self.setup.label_dual_button1_uid.setText('None') self.setup.label_dual_button2_found.setText('No') self.setup.label_dual_button2_uid.setText('None') config.UID_PIEZO_SPEAKER_BRICKLET = None self.setup.label_piezo_speaker_found.setText('No') self.setup.label_piezo_speaker_uid.setText('None') config.UID_SEGMENT_DISPLAY_4X7_BRICKLET = None self.setup.label_segment_display_found.setText('No') self.setup.label_segment_display_uid.setText('None') if self.ipcon != None: try: self.ipcon.disconnect() except: pass self.ipcon = IPConnection() host = self.setup.edit_host.text() port = self.setup.spinbox_port.value() try: self.ipcon.connect(host, port) except Error as e: self.error_msg.showMessage('Connection Error: ' + str(e.description) + "<br><br>Brickd installed and running?") return except socket.error as e: self.error_msg.showMessage('Socket error: ' + str(e) + "<br><br>Brickd installed and running?") return self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE, self.cb_enumerate) self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED, self.cb_connected) # Wait for a second to give user visual feedback timer = QTimer(self) timer.setSingleShot(True) timer.timeout.connect(self.ipcon.enumerate) timer.start(250) def tab_changed_slot(self, tabIndex): self.active_project.stop() self.active_project = self.projects[tabIndex] self.active_project.start() def cb_enumerate(self, uid, connected_uid, position, hardware_version, firmware_version, device_identifier, enumeration_type): if enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED or \ enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE: if device_identifier == LEDStrip.DEVICE_IDENTIFIER: config.UID_LED_STRIP_BRICKLET = uid self.setup.label_led_strip_found.setText('Yes') self.setup.label_led_strip_uid.setText(uid) elif device_identifier == MultiTouch.DEVICE_IDENTIFIER: config.UID_MULTI_TOUCH_BRICKLET = uid self.setup.label_multi_touch_found.setText('Yes') self.setup.label_multi_touch_uid.setText(uid) elif device_identifier == DualButton.DEVICE_IDENTIFIER: if config.UID_DUAL_BUTTON_BRICKLET[0] == None: config.UID_DUAL_BUTTON_BRICKLET = (uid, None) self.setup.label_dual_button1_found.setText('Yes') self.setup.label_dual_button1_uid.setText(uid) else: config.UID_DUAL_BUTTON_BRICKLET = (config.UID_DUAL_BUTTON_BRICKLET[0], uid) self.setup.label_dual_button2_found.setText('Yes') self.setup.label_dual_button2_uid.setText(uid) elif device_identifier == PiezoSpeaker.DEVICE_IDENTIFIER: config.UID_PIEZO_SPEAKER_BRICKLET = uid self.setup.label_piezo_speaker_found.setText('Yes') self.setup.label_piezo_speaker_uid.setText(uid) elif device_identifier == SegmentDisplay4x7.DEVICE_IDENTIFIER: config.UID_SEGMENT_DISPLAY_4X7_BRICKLET = uid self.setup.label_segment_display_found.setText('Yes') self.setup.label_segment_display_uid.setText(uid) def cb_connected(self, connected_reason): if connected_reason == IPConnection.CONNECT_REASON_AUTO_RECONNECT: while True: try: self.ipcon.enumerate() break except Error as e: self.error_msg.showMessage('Enumerate Error: ' + str(e.description)) time.sleep(1)
except socket.error: # Good si is correct (on UNIX) otherinstance = True else: # On windows only singleinstance can be trusted otherinstance = True if iswindows else False if not otherinstance and not opts.shutdown_running_calibre: return run_gui(opts, args, listener, app, gui_debug=gui_debug) communicate(opts, args) return 0 if __name__ == "__main__": try: sys.exit(main()) except Exception as err: if not iswindows: raise tb = traceback.format_exc() from PyQt4.QtGui import QErrorMessage logfile = os.path.join(os.path.expanduser("~"), "calibre.log") if os.path.exists(logfile): log = open(logfile).read().decode("utf-8", "ignore") d = QErrorMessage() d.showMessage( ("<b>Error:</b>%s<br><b>Traceback:</b><br>" "%s<b>Log:</b><br>%s") % (unicode(err), unicode(tb).replace("\n", "<br>"), log.replace("\n", "<br>")) )
otherinstance = True else: # On windows only singleinstance can be trusted otherinstance = True if iswindows else False if not otherinstance and not opts.shutdown_running_calibre: return run_gui(opts, args, actions, listener, app, gui_debug=gui_debug) communicate(opts, args) return 0 if __name__ == '__main__': try: sys.exit(main()) except Exception as err: if not iswindows: raise tb = traceback.format_exc() from PyQt4.QtGui import QErrorMessage logfile = os.path.join(os.path.expanduser('~'), 'calibre.log') if os.path.exists(logfile): log = open(logfile).read().decode('utf-8', 'ignore') d = QErrorMessage() d.showMessage(('<b>Error:</b>%s<br><b>Traceback:</b><br>' '%s<b>Log:</b><br>%s')%(unicode(err), unicode(tb).replace('\n', '<br>'), log.replace('\n', '<br>')))
class Servo(PluginBase, Ui_Servo): qtcb_under_voltage = pyqtSignal(int) def __init__(self, *args): PluginBase.__init__(self, BrickServo, *args) self.setupUi(self) self.servo = self.device self.position_list = [] self.velocity_list = [] self.acceleration_list = [] self.enable_list = [] self.up_cur = 0 self.up_siv = 0 self.up_eiv = 0 self.up_opv = 0 self.up_mv = 0 self.up_ena = [0] * 7 self.up_pos = [0] * 7 self.up_vel = [0] * 7 self.up_acc = [0] * 7 self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_apply) self.update_timer.setInterval(50) self.alive = True for i in range(1, 8): label = QLabel() label.setText('Off') self.enable_list.append(label) self.status_grid.addWidget(label, i, 1) for i in range(1, 8): pk = PositionKnob() self.position_list.append(pk) self.status_grid.addWidget(pk, i, 2) for i in range(1, 8): cb = ColorBar(Qt.Vertical) self.velocity_list.append(cb) self.status_grid.addWidget(cb, i, 3) for i in range(1, 8): cb = ColorBar(Qt.Vertical) self.acceleration_list.append(cb) self.status_grid.addWidget(cb, i, 4) self.qem = QErrorMessage(self) self.qem.setWindowTitle("Under Voltage") self.test_button.clicked.connect(self.test_button_clicked) self.output_voltage_button.clicked.connect( self.output_voltage_button_clicked) self.servo_dropbox.currentIndexChanged.connect( lambda x: self.update_servo_specific()) self.enable_checkbox.stateChanged.connect(self.enable_state_changed) self.position_syncer = SliderSpinSyncer(self.position_slider, self.position_spin, self.position_changed) self.velocity_syncer = SliderSpinSyncer(self.velocity_slider, self.velocity_spin, self.velocity_changed) self.acceleration_syncer = SliderSpinSyncer(self.acceleration_slider, self.acceleration_spin, self.acceleration_changed) self.period_syncer = SliderSpinSyncer(self.period_slider, self.period_spin, self.period_changed) self.pulse_width_min_spin.editingFinished.connect( self.pulse_width_spin_finished) self.pulse_width_max_spin.editingFinished.connect( self.pulse_width_spin_finished) self.degree_min_spin.editingFinished.connect(self.degree_spin_finished) self.degree_max_spin.editingFinished.connect(self.degree_spin_finished) self.minimum_voltage_button.clicked.connect( self.minimum_voltage_button_clicked) self.qtcb_under_voltage.connect(self.cb_under_voltage) self.servo.register_callback(self.servo.CALLBACK_UNDER_VOLTAGE, self.qtcb_under_voltage.emit) class WorkerThread(QThread): def __init__(self, parent=None, func=None): QThread.__init__(self, parent) self.func = func def run(self): self.func() self.test_event = Event() self.test_thread_object = WorkerThread(self, self.test_thread) self.update_event = Event() self.update_thread_object = WorkerThread(self, self.update_thread) self.update_thread_first_time = False self.update_done_event = Event() self.update_done_event.set() if self.firmware_version >= (2, 3, 1): self.status_led_action = QAction('Status LED', self) self.status_led_action.setCheckable(True) self.status_led_action.toggled.connect( lambda checked: self.servo.enable_status_led() if checked else self.servo.disable_status_led()) self.set_configs([(0, None, [self.status_led_action])]) else: self.status_led_action = None if self.firmware_version >= (1, 1, 3): reset = QAction('Reset', self) reset.triggered.connect(lambda: self.servo.reset()) self.set_actions([(0, None, [reset])]) def start(self): if self.firmware_version >= (2, 3, 1): async_call(self.servo.is_status_led_enabled, None, self.status_led_action.setChecked, self.increase_error_count) self.alive = True self.test_event.clear() self.update_done_event.set() self.update_event.set() if not self.test_thread_object.isRunning(): self.test_thread_object.start() if not self.update_thread_object.isRunning(): self.update_thread_object.start() self.update_servo_specific() self.update_timer.start() def stop(self): if self.test_button.text() == "Stop Test": self.test_button_clicked() self.update_timer.stop() self.update_event.clear() self.alive = False self.update_done_event.wait() def destroy(self): self.test_event.set() self.update_event.set() @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickServo.DEVICE_IDENTIFIER def get_period_async(self, per): self.period_spin.setValue(per) self.period_slider.setValue(per) def is_enabled_async(self, ena): self.enable_checkbox.setChecked(ena) def get_position_async(self, pos): self.position_spin.setValue(pos) self.position_slider.setValue(pos) def get_velocity_async(self, vel): self.velocity_spin.setValue(vel) self.velocity_slider.setValue(vel) def get_acceleration_async(self, acc): self.acceleration_spin.setValue(acc) self.acceleration_slider.setValue(acc) def get_degree_async(self, deg, i): deg_min, deg_max = deg self.degree_min_spin.setValue(deg_min) self.degree_max_spin.setValue(deg_max) self.position_slider.setMinimum(deg_min) self.position_slider.setMaximum(deg_max) self.position_spin.setMinimum(deg_min) self.position_spin.setMaximum(deg_max) self.position_list[i].set_total_angle((deg_max - deg_min) / 100) self.position_list[i].set_range(deg_min / 100, deg_max / 100) def get_pulse_width_async(self, pulse): pulse_min, pulse_max = pulse self.pulse_width_min_spin.setValue(pulse_min) self.pulse_width_max_spin.setValue(pulse_max) def update_servo_specific(self): i = self.selected_servo() if i == 255: self.enable_checkbox.setChecked(False) return async_call(self.servo.get_position, i, self.get_position_async, self.increase_error_count) async_call(self.servo.get_velocity, i, self.get_velocity_async, self.increase_error_count) async_call(self.servo.get_acceleration, i, self.get_acceleration_async, self.increase_error_count) async_call(self.servo.get_period, i, self.get_period_async, self.increase_error_count) async_call(self.servo.is_enabled, i, self.is_enabled_async, self.increase_error_count) def get_lambda_deg(i): return lambda x: self.get_degree_async(x, i) async_call(self.servo.get_degree, i, get_lambda_deg(i), self.increase_error_count) async_call(self.servo.get_pulse_width, i, self.get_pulse_width_async, self.increase_error_count) def error_handler(self, error): pass def servo_current_update(self, value): self.current_label.setText(str(value) + "mA") def stack_input_voltage_update(self, sv): sv_str = "%gV" % round(sv / 1000.0, 1) self.stack_voltage_label.setText(sv_str) def external_input_voltage_update(self, ev): ev_str = "%gV" % round(ev / 1000.0, 1) self.external_voltage_label.setText(ev_str) def output_voltage_update(self, ov): ov_str = "%gV" % round(ov / 1000.0, 1) self.output_voltage_label.setText(ov_str) def minimum_voltage_update(self, mv): mv_str = "%gV" % round(mv / 1000.0, 1) self.minimum_voltage_label.setText(mv_str) def position_update(self, i, pos): self.position_list[i].set_value(pos / 100) def velocity_update(self, i, vel): self.velocity_list[i].set_height(vel * 100 / 0xFFFF) def acceleration_update(self, i, acc): self.acceleration_list[i].set_height(acc * 100 / 0xFFFF) def deactivate_servo(self, i): if self.enable_list[i].text() != 'Off': self.velocity_list[i].grey() self.acceleration_list[i].grey() def activate_servo(self, i): if self.enable_list[i].text() != 'On': self.velocity_list[i].color() self.acceleration_list[i].color() def selected_servo(self): try: return int(self.servo_dropbox.currentText()[-1:]) except: return 255 def enable_state_changed(self, state): s = self.selected_servo() try: if state == Qt.Checked: self.servo.enable(s) elif state == Qt.Unchecked: self.servo.disable(s) except ip_connection.Error: return def update_apply(self): if not self.update_thread_first_time: return self.servo_current_update(self.up_cur) self.stack_input_voltage_update(self.up_siv) self.external_input_voltage_update(self.up_eiv) self.output_voltage_update(self.up_opv) self.minimum_voltage_update(self.up_mv) for i in range(7): if self.up_ena[i]: self.activate_servo(i) self.position_update(i, self.up_pos[i]) self.velocity_update(i, self.up_vel[i]) self.acceleration_update(i, self.up_acc[i]) self.enable_list[i].setText('On') else: self.deactivate_servo(i) self.enable_list[i].setText('Off') def update_thread(self): while self.alive: time.sleep(0.1) try: servo = self.selected_servo() if servo == 255: self.up_cur = self.servo.get_overall_current() else: self.up_cur = self.servo.get_servo_current(servo) self.up_siv = self.servo.get_stack_input_voltage() self.up_eiv = self.servo.get_external_input_voltage() self.up_opv = self.servo.get_output_voltage() self.up_mv = self.servo.get_minimum_voltage() for i in range(7): self.up_ena[i] = self.servo.is_enabled(i) if self.up_ena[i]: self.activate_servo(i) self.up_pos[i] = self.servo.get_current_position(i) self.up_vel[i] = self.servo.get_current_velocity(i) self.up_acc[i] = self.servo.get_acceleration(i) #self.update_apply() self.update_done_event.set() self.update_event.wait() self.update_done_event.clear() except ip_connection.Error: pass self.update_thread_first_time = True self.update_done_event.set() def test_thread(self): def test(num, ena, acc, vel, pos): if not self.alive: return try: if ena: self.servo.enable(num) else: self.servo.disable(num) self.servo.set_acceleration(num, acc) self.servo.set_velocity(num, vel) self.servo.set_position(num, pos) except ip_connection.Error: return def random_test(): for i in range(7): test(i, random.randrange(0, 2), random.randrange(0, 65536), random.randrange(0, 65536), random.randrange(-9000, 9001)) while self.alive: self.test_event.wait() if not self.alive: return # Full Speed left for 2 seconds for i in range(7): test(i, True, 65535, 65535, 9000) time.sleep(2) self.test_event.wait() if not self.alive: return # Full Speed right for 2 seconds for i in range(7): test(i, True, 65535, 65535, -9000) time.sleep(2) self.test_event.wait() if not self.alive: return # Test different speeds for i in range(19): for j in range(7): test(j, True, 65535, 65535 * i / 18, -9000 + i * 1000) time.sleep(0.1) self.test_event.wait() if not self.alive: return time.sleep(1) self.test_event.wait() if not self.alive: return # Test acceleration for i in range(7): test(i, True, 100, 65535, -9000) time.sleep(3) self.test_event.wait() if not self.alive: return # Random for 3 seconds random_test() time.sleep(3) def test_button_clicked(self): if self.test_button.text() == "Start Test": self.test_button.setText("Stop Test") self.test_event.set() else: self.test_button.setText("Start Test") self.test_event.clear() def output_voltage_button_clicked(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(2000) qid.setIntMaximum(9000) qid.setIntStep(100) async_call(self.servo.get_output_voltage, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.output_voltage_selected) qid.setLabelText("Choose Output Voltage in mV.") # "<font color=red>Setting this too high can destroy your servo.</font>") qid.open() def output_voltage_selected(self, value): try: self.servo.set_output_voltage(value) except ip_connection.Error: return def position_changed(self, value): try: self.servo.set_position(self.selected_servo(), value) except ip_connection.Error: return def velocity_changed(self, value): try: self.servo.set_velocity(self.selected_servo(), value) except ip_connection.Error: return def acceleration_changed(self, value): try: self.servo.set_acceleration(self.selected_servo(), value) except ip_connection.Error: return def period_changed(self, value): try: self.servo.set_period(self.selected_servo(), value) except ip_connection.Error: return def pulse_width_spin_finished(self): try: self.servo.set_pulse_width(self.selected_servo(), self.pulse_width_min_spin.value(), self.pulse_width_max_spin.value()) except ip_connection.Error: return def degree_spin_finished(self): min = self.degree_min_spin.value() max = self.degree_max_spin.value() servo = self.selected_servo() self.position_slider.setMinimum(min) self.position_slider.setMaximum(max) self.position_spin.setMinimum(min) self.position_spin.setMaximum(max) if servo == 255: for i in range(7): self.position_list[i].set_total_angle((max - min) / 100) self.position_list[i].set_range(min / 100, max / 100) else: self.position_list[servo].set_total_angle((max - min) / 100) self.position_list[servo].set_range(min / 100, max / 100) try: self.servo.set_degree(servo, min, max) except ip_connection.Error: return def cb_under_voltage(self, ov): mv_str = self.minimum_voltage_label.text() ov_str = "%gV" % round(ov / 1000.0, 1) if not self.qem.isVisible(): self.qem.showMessage( "Under Voltage: Output Voltage of " + ov_str + " is below minimum voltage of " + mv_str, "Servo_UnterVoltage") def minimum_voltage_selected(self, value): try: self.servo.set_minimum_voltage(value) except ip_connection.Error: return def minimum_voltage_button_clicked(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(5000) qid.setIntMaximum(0xFFFF) qid.setIntStep(100) async_call(self.servo.get_minimum_voltage, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.minimum_voltage_selected) qid.setLabelText("Choose minimum servo voltage in mV.") qid.open()
class Editor(editor_base.EditorBase): """Representa el editor de texto que aparece en el panel derecho. El editor soporta autocompletado de código y resaltado de sintáxis. """ # Señal es emitida cuando el Editor ejecuta codigo signal_ejecutando = QtCore.pyqtSignal() def __init__(self, main, interpreterLocals, consola_lanas, ventana_interprete): super(Editor, self).__init__() self.cantidad_ejecuciones = 0 self.consola_lanas = consola_lanas self.ventana_interprete = ventana_interprete self.ruta_del_archivo_actual = None self.interpreterLocals = interpreterLocals self.setLineWrapMode(QTextEdit.NoWrap) self._cambios_sin_guardar = False self.main = main self.nombre_de_archivo_sugerido = "" self.watcher = pilasengine.watcher.Watcher( None, self.cuando_cambia_archivo_de_forma_externa) def crear_archivo_inicial(self): dirpath = tempfile.mkdtemp() archivo_temporal = os.path.join(dirpath, "mi_juego.py") archivo = codecs.open(archivo_temporal, "w", 'utf-8') archivo.write(CODIGO_INICIAL) archivo.close() #print("Creando el archivo " + str(archivo_temporal)) self.abrir_archivo_del_proyecto(archivo_temporal) def es_archivo_iniciar_sin_guardar(self): return self.nombre_de_archivo_sugerido == "" def crear_y_seleccionar_archivo(self, nombre): # Quita la extension si llega a tenerla. nombre = nombre.replace('.py', '') nombre += ".py" nombre_de_archivo = nombre if self.ruta_del_archivo_actual: base_path = os.path.abspath( os.path.dirname(self.ruta_del_archivo_actual)) ruta = os.path.join(base_path, unicode(nombre_de_archivo)) else: ruta = unicode(nombre_de_archivo) if os.path.exists(ruta): self._tmp_dialog = QErrorMessage(self) self._tmp_dialog.showMessage("Ya existe un archivo con ese nombre") else: self._crear_archivo_nuevo_en(ruta) self.cargar_contenido_desde_archivo(ruta) self.ruta_del_archivo_actual = ruta self.watcher.cambiar_archivo_a_observar(ruta) self.ejecutar() self.main.actualizar_el_listado_de_archivos() def _crear_archivo_nuevo_en(self, ruta): fo = open(ruta, "wb") fo.write("# contenido") fo.close() def obtener_archivos_del_proyecto(self): base_path = os.path.dirname(self.nombre_de_archivo_sugerido) listado = os.listdir(base_path) return [x for x in listado if x.endswith('.py')] def keyPressEvent(self, event): "Atiene el evento de pulsación de tecla." self._cambios_sin_guardar = True # Permite usar tab como seleccionador de la palabra actual # en el popup de autocompletado. if event.key() in [Qt.Key_Tab]: if self.completer and self.completer.popup().isVisible(): event.ignore() nuevo_evento = QKeyEvent(QKeyEvent.KeyPress, Qt.Key_Return, Qt.NoModifier) try: if self.autocomplete(nuevo_evento): return None except UnicodeEncodeError: pass return None if editor_base.EditorBase.keyPressEvent(self, event): return None # Elimina los pares de caracteres especiales si los encuentra if event.key() == Qt.Key_Backspace: self._eliminar_pares_de_caracteres() self._borrar_un_grupo_de_espacios(event) if self.autocomplete(event): return None if event.key() == Qt.Key_Return: cursor = self.textCursor() block = self.document().findBlockByNumber(cursor.blockNumber()) whitespace = re.match(r"(\s*)", unicode(block.text())).group(1) linea_anterior = str(block.text()[:]) cantidad_espacios = linea_anterior.count(' ') / 4 if linea_anterior[-1:] == ':': whitespace = ' ' * (cantidad_espacios + 1) else: whitespace = ' ' * (cantidad_espacios) QTextEdit.keyPressEvent(self, event) return self.insertPlainText(whitespace) return QTextEdit.keyPressEvent(self, event) def _borrar_un_grupo_de_espacios(self, event): cursor = self.textCursor() block = self.document().findBlockByNumber(cursor.blockNumber()) whitespace = re.match(r"(.*)", unicode(block.text())).group(1) if whitespace.endswith(' '): QTextEdit.keyPressEvent(self, event) QTextEdit.keyPressEvent(self, event) QTextEdit.keyPressEvent(self, event) def tiene_cambios_sin_guardar(self): return self._cambios_sin_guardar def _get_current_line(self): "Obtiene la linea en donde se encuentra el cursor." tc = self.textCursor() tc.select(QTextCursor.LineUnderCursor) return tc.selectedText() def _get_position_in_block(self): tc = self.textCursor() position = tc.positionInBlock() - 1 return position def cargar_contenido_desde_archivo(self, ruta): "Carga todo el contenido del archivo indicado por ruta." with codecs.open(unicode(ruta), 'r', 'utf-8') as archivo: contenido = archivo.read() self.setText(contenido) self.nombre_de_archivo_sugerido = ruta self._cambios_sin_guardar = False def abrir_dialogo_cargar_archivo(self): return QFileDialog.getOpenFileName( self, "Abrir Archivo", self.nombre_de_archivo_sugerido, "Archivos python (*.py)", options=QFileDialog.DontUseNativeDialog) def abrir_archivo_del_proyecto(self, nombre_de_archivo): if self.tiene_cambios_sin_guardar(): if self.mensaje_guardar_cambios_abrir(): if not self.guardar_contenido_con_dialogo(): return else: return if self.ruta_del_archivo_actual: base_path = os.path.dirname(self.ruta_del_archivo_actual) ruta = os.path.join(base_path, unicode(nombre_de_archivo)) else: ruta = unicode(nombre_de_archivo) self.cargar_contenido_desde_archivo(ruta) self.ruta_del_archivo_actual = ruta self.watcher.cambiar_archivo_a_observar(ruta) self.ejecutar() self.main.actualizar_el_listado_de_archivos() def abrir_archivo_con_dialogo(self): if self.tiene_cambios_sin_guardar(): if self.mensaje_guardar_cambios_abrir(): if not self.guardar_contenido_con_dialogo(): return else: return ruta = self.abrir_dialogo_cargar_archivo() if ruta: ruta = unicode(ruta) self.cargar_contenido_desde_archivo(ruta) self.ruta_del_archivo_actual = ruta self.watcher.cambiar_archivo_a_observar(ruta) self.ejecutar() self.main.actualizar_el_listado_de_archivos() def cuando_cambia_archivo_de_forma_externa(self): self.recargar_archivo_actual() def recargar_archivo_actual(self): if self.ruta_del_archivo_actual: self.cargar_contenido_desde_archivo(self.ruta_del_archivo_actual) self.ejecutar() def mensaje_guardar_cambios_abrir(self): """Realizar una consulta usando un cuadro de dialogo simple se utiliza cuando hay cambios sin guardar y se desea abrir un archivo. Retorna True si el usuario presiona el boton *Guardar*, Retorna False si el usuario presiona *No*.""" titulo = u"¿Deseas guardar el contenido antes de abrir un archivo?" mensaje = u"El contenido se perdera sino los guardas" mensaje = QMessageBox.question(self, titulo, mensaje, "Guardar", "No") return (not mensaje) def mensaje_guardar_cambios_salir(self): """Realizar una consulta usando un cuadro de dialogo simple se utiliza cuando hay cambios sin guardar y se desa salir del Editor. Retorna 0 si el usuario presiona el boton *Salir sin guardar*, Retorna 1 si el usuario presiona *Guardar* Retorna 2 si presiona *Cancelar*.""" titulo = u"¿Deseas guardar el contenido antes de salir?" mensaje = u"El contenido se perdera sino los guardas" return QMessageBox.question(self, titulo, mensaje, "Salir sin guardar", "Guardar", "Cancelar") def marcar_error_en_la_linea(self, numero, descripcion): hi_selection = QTextEdit.ExtraSelection() hi_selection.format.setBackground(QColor(255, 220, 220)) hi_selection.format.setProperty(QTextFormat.FullWidthSelection, QVariant(True)) hi_selection.cursor = self.textCursor() posicion_linea = self.document().findBlockByLineNumber( numero).position() hi_selection.cursor.setPosition(posicion_linea) hi_selection.cursor.clearSelection() self.setExtraSelections([hi_selection]) def guardar_contenido_con_dialogo(self): ruta = self.abrir_dialogo_guardar_archivo() if not ruta: return False ruta = unicode(ruta) if not ruta.endswith('.py'): ruta += '.py' if ruta: self.guardar_contenido_en_el_archivo(ruta) self._cambios_sin_guardar = False self.ruta_del_archivo_actual = ruta self.nombre_de_archivo_sugerido = ruta self.watcher.cambiar_archivo_a_observar(ruta) self.cargar_contenido_desde_archivo(ruta) self.ejecutar() self.main.actualizar_el_listado_de_archivos() self.main.habilitar_boton_nuevo() return True def guardar_contenido_directamente(self): if self.nombre_de_archivo_sugerido: self.guardar_contenido_en_el_archivo( self.nombre_de_archivo_sugerido) self._cambios_sin_guardar = False self.main.actualizar_el_listado_de_archivos() self.prevenir_live_reload() else: self.guardar_contenido_con_dialogo() def prevenir_live_reload(self): self.watcher.prevenir_reinicio() def salir(self): """Retorna True si puede salir y False si no""" if self.tiene_cambios_sin_guardar(): mensaje = self.mensaje_guardar_cambios_salir() if mensaje == 1: self.guardar_contenido_con_dialogo() elif mensaje == 2: return False return True def obtener_contenido(self): return unicode(self.document().toPlainText()) def ejecutar(self): ruta_personalizada = os.path.dirname(self.ruta_del_archivo_actual) #print "ejecutando texto desde widget editor" texto = self.obtener_contenido() #texto = self.editor.obtener_texto_sanitizado(self) # elimina cabecera de encoding. contenido = re.sub('coding\s*:\s*', '', texto) contenido = contenido.replace('import pilasengine', '') contenido = contenido.replace('pilas = pilasengine.iniciar', 'pilas.reiniciar') for x in contenido.split('\n'): if "__file__" in x: contenido = contenido.replace(x, "# livecoding: " + x + "\n") sys.path.append(ruta_personalizada) self.interpreterLocals['sys'] = sys # Muchos códigos personalizados necesitan cargar imágenes o sonidos # desde el directorio que contiene al archivo. Para hacer esto posible, # se llama a la función "pilas.utils.agregar_ruta_personalizada" con el # path al directorio que representa el script. Así la función "obtener_ruta_al_recurso" # puede evaluar al directorio del script en busca de recursos también. if ruta_personalizada: ruta_personalizada = ruta_personalizada.replace('\\', '/') agregar_ruta_personalizada = 'pilas.utils.agregar_ruta_personalizada("%s")' % ( ruta_personalizada) contenido = contenido.replace( 'pilas.reiniciar(', agregar_ruta_personalizada + '\n' + 'pilas.reiniciar(') modulos_a_recargar = [ x for x in self.interpreterLocals.values() if inspect.ismodule(x) and x.__name__ not in ['pilasengine', 'inspect'] and 'pilasengine.' not in x.__name__ ] for m in modulos_a_recargar: reload(m) self.cantidad_ejecuciones += 1 # Limpia la consola a partir de la primer ejecucion luego de iniciar. if self.cantidad_ejecuciones > 1: self.main.limpiar_interprete() try: exec(contenido, self.interpreterLocals) except Exception, e: self.consola_lanas.insertar_error_desde_exception(e) self.ventana_interprete.mostrar_el_interprete() #self.marcar_error_en_la_linea(10, "pepepe") self.signal_ejecutando.emit()
class DC(PluginBase, Ui_DC): qtcb_velocity_reached = pyqtSignal(int) qtcb_under_voltage = pyqtSignal(int) qtcb_emergency_shutdown = pyqtSignal() def __init__(self, *args): PluginBase.__init__(self, BrickDC, *args) self.setupUi(self) self.dc = self.device self.encoder_hide_all() self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_data) self.speedometer = SpeedoMeter() self.vertical_layout_right.insertWidget(4, self.speedometer) self.new_value = 0 self.update_counter = 0 self.full_brake_time = 0 self.velocity_syncer = SliderSpinSyncer(self.velocity_slider, self.velocity_spin, self.velocity_changed) self.acceleration_syncer = SliderSpinSyncer(self.acceleration_slider, self.acceleration_spin, self.acceleration_changed) self.frequency_syncer = SliderSpinSyncer(self.frequency_slider, self.frequency_spin, self.frequency_changed) self.radio_mode_brake.toggled.connect(self.brake_value_changed) self.radio_mode_coast.toggled.connect(self.coast_value_changed) self.minimum_voltage_button.clicked.connect( self.minimum_voltage_button_clicked) self.full_brake_button.clicked.connect(self.full_brake_clicked) self.enable_checkbox.stateChanged.connect(self.enable_state_changed) self.emergency_signal = None self.under_signal = None self.current_velocity_signal = None self.velocity_reached_signal = None self.qem = QErrorMessage(self) self.qtcb_under_voltage.connect(self.cb_under_voltage) self.dc.register_callback(self.dc.CALLBACK_UNDER_VOLTAGE, self.qtcb_under_voltage.emit) self.qtcb_emergency_shutdown.connect(self.cb_emergency_shutdown) self.dc.register_callback(self.dc.CALLBACK_EMERGENCY_SHUTDOWN, self.qtcb_emergency_shutdown.emit) self.qtcb_velocity_reached.connect(self.update_velocity) self.dc.register_callback(self.dc.CALLBACK_VELOCITY_REACHED, self.qtcb_velocity_reached.emit) self.cbe_current_velocity = CallbackEmulator( self.dc.get_current_velocity, self.update_velocity, self.increase_error_count) if self.firmware_version >= (1, 1, 3): reset = QAction('Reset', self) reset.triggered.connect(lambda: self.dc.reset()) self.set_actions(reset) # if self.firmware_version >= (2, 0, 1): # self.enable_encoder_checkbox.stateChanged.connect(self.enable_encoder_state_changed) # self.encoder_show() # else: # self.enable_encoder_checkbox.setText('Enable Encoder (FW Version >= 2.0.1 required)') # self.enable_encoder_checkbox.setEnabled(False) def start(self): self.update_timer.start(1000) self.cbe_current_velocity.set_period(100) self.update_start() self.update_data() def stop(self): self.update_timer.stop() self.cbe_current_velocity.set_period(0) def destroy(self): pass def get_url_part(self): return 'dc' @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickDC.DEVICE_IDENTIFIER def cb_emergency_shutdown(self): if not self.qem.isVisible(): self.qem.setWindowTitle("Emergency Shutdown") self.qem.showMessage( "Emergency Shutdown: Short-Circuit or Over-Temperature") def cb_under_voltage(self, ov): mv_str = self.minimum_voltage_label.text() ov_str = "%gV" % round(ov / 1000.0, 1) if not self.qem.isVisible(): self.qem.setWindowTitle("Under Voltage") self.qem.showMessage( "Under Voltage: Output Voltage of " + ov_str + " is below minimum voltage of " + mv_str, "DC_UnderVoltage") def encoder_hide_all(self): self.enable_encoder_checkbox.hide() self.encoder_hide() def encoder_hide(self): self.p_label.hide() self.p_spinbox.hide() self.i_label.hide() self.i_spinbox.hide() self.d_label.hide() self.d_spinbox.hide() self.st_label.hide() self.st_spinbox.hide() self.cpr_label.hide() self.cpr_spinbox.hide() self.encoder_spacer.hide() def encoder_show(self): self.p_label.show() self.p_spinbox.show() self.i_label.show() self.i_spinbox.show() self.d_label.show() self.d_spinbox.show() self.st_label.show() self.st_spinbox.show() self.cpr_label.show() self.cpr_spinbox.show() self.encoder_spacer.show() def enable_encoder_state_changed(self, state): try: if state == Qt.Checked: self.dc.enable_encoder() self.update_encoder() elif state == Qt.Unchecked: self.dc.disable_encoder() except ip_connection.Error: return def enable_state_changed(self, state): try: if state == Qt.Checked: self.dc.enable() elif state == Qt.Unchecked: self.dc.disable() except ip_connection.Error: return def brake_value_changed(self, checked): if checked: try: self.dc.set_drive_mode(0) except ip_connection.Error: return def coast_value_changed(self, checked): if checked: try: self.dc.set_drive_mode(1) except ip_connection.Error: return def full_brake_clicked(self): try: self.dc.full_brake() except ip_connection.Error: return def minimum_voltage_selected(self, value): try: self.dc.set_minimum_voltage(value) except ip_connection.Error: return def minimum_voltage_button_clicked(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(5000) qid.setIntMaximum(0xFFFF) qid.setIntStep(100) async_call(self.dc.get_minimum_voltage, None, qid.setIntValue, self.increase_error_count) qid.intValueSelected.connect(self.minimum_voltage_selected) qid.setLabelText("Choose minimum motor voltage in mV.") qid.open() def stack_input_voltage_update(self, sv): sv_str = "%gV" % round(sv / 1000.0, 1) self.stack_voltage_label.setText(sv_str) def external_input_voltage_update(self, ev): ev_str = "%gV" % round(ev / 1000.0, 1) self.external_voltage_label.setText(ev_str) def minimum_voltage_update(self, mv): mv_str = "%gV" % round(mv / 1000.0, 1) self.minimum_voltage_label.setText(mv_str) def drive_mode_update(self, dm): if dm == 0: self.radio_mode_brake.setChecked(True) self.radio_mode_coast.setChecked(False) else: self.radio_mode_brake.setChecked(False) self.radio_mode_coast.setChecked(True) def current_consumption_update(self, cc): if cc >= 1000: cc_str = "%gA" % round(cc / 1000.0, 1) else: cc_str = "%gmA" % cc self.current_label.setText(cc_str) def update_velocity(self, value): self.speedometer.set_velocity(value) def get_velocity_async(self, velocity): if not self.velocity_slider.isSliderDown(): if velocity != self.velocity_slider.sliderPosition(): self.velocity_slider.setSliderPosition(velocity) self.velocity_spin.setValue(velocity) self.speedometer.set_velocity(velocity) def get_acceleration_async(self, acceleration): if not self.acceleration_slider.isSliderDown(): if acceleration != self.acceleration_slider.sliderPosition(): self.acceleration_slider.setSliderPosition(acceleration) self.acceleration_spin.setValue(acceleration) def get_pwm_frequency_async(self, frequency): if not self.frequency_slider.isSliderDown(): if frequency != self.frequency_slider.sliderPosition(): self.frequency_slider.setSliderPosition(frequency) self.frequency_spin.setValue(frequency) def is_enabled_async(self, enabled): self.enable_checkbox.setChecked(enabled) def is_encoder_enabled_async(self, enabled): self.enable_encoder_checkbox.setChecked(enabled) def get_encoder_config_async(self, cpr): self.cpr_spinbox.setValue(cpr) def get_encoder_pid_config_async(self, pid_config): self.p_spinbox.setValue(pid_config.p) self.i_spinbox.setValue(pid_config.i) self.d_spinbox.setValue(pid_config.d) self.st_spinbox.setValue(pid_config.sample_time) def update_encoder(self): async_call(self.dc.get_encoder_config, None, self.get_encoder_config_async, self.increase_error_count) async_call(self.dc.get_encoder_pid_config, None, self.get_encoder_pid_config_async, self.increase_error_count) async_call(self.dc.is_encoder_enabled, None, self.is_encoder_enabled_async, self.increase_error_count) def update_start(self): async_call(self.dc.get_drive_mode, None, self.drive_mode_update, self.increase_error_count) async_call(self.dc.get_velocity, None, self.get_velocity_async, self.increase_error_count) async_call(self.dc.get_acceleration, None, self.get_acceleration_async, self.increase_error_count) async_call(self.dc.get_pwm_frequency, None, self.get_pwm_frequency_async, self.increase_error_count) async_call(self.dc.is_enabled, None, self.is_enabled_async, self.increase_error_count) # if self.firmware_version >= (2, 0, 1): # self.update_encoder() def update_data(self): async_call(self.dc.get_stack_input_voltage, None, self.stack_input_voltage_update, self.increase_error_count) async_call(self.dc.get_external_input_voltage, None, self.external_input_voltage_update, self.increase_error_count) async_call(self.dc.get_minimum_voltage, None, self.minimum_voltage_update, self.increase_error_count) async_call(self.dc.get_current_consumption, None, self.current_consumption_update, self.increase_error_count) def acceleration_changed(self, value): try: self.dc.set_acceleration(value) except ip_connection.Error: return def velocity_changed(self, value): try: self.dc.set_velocity(value) except ip_connection.Error: return def frequency_changed(self, value): try: self.dc.set_pwm_frequency(value) except ip_connection.Error: return
class Servo(PluginBase, Ui_Servo): qtcb_under_voltage = pyqtSignal(int) def __init__ (self, ipcon, uid): PluginBase.__init__(self, ipcon, uid) self.setupUi(self) self.servo = brick_servo.Servo(self.uid) self.device = self.servo self.ipcon.add_device(self.servo) self.version = '.'.join(map(str, self.servo.get_version()[1])) self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_apply) self.update_timer.setInterval(0) self.update_timer.setSingleShot(True) layout = QVBoxLayout(self) layout.addWidget(QLabel('Servo')) self.position_list = [] self.velocity_list = [] self.acceleration_list = [] self.enable_list = [] self.up_ena = [0]*7 self.up_pos = [0]*7 self.up_vel = [0]*7 self.up_acc = [0]*7 self.alive = True for i in range(1, 8): label = QLabel() label.setText('Off') self.enable_list.append(label) self.status_grid.addWidget(label, i, 1) for i in range(1, 8): pk = PositionKnob() self.position_list.append(pk) self.status_grid.addWidget(pk, i, 2) for i in range(1, 8): cb = ColorBar(Qt.Vertical) self.velocity_list.append(cb) self.status_grid.addWidget(cb, i, 3) for i in range(1, 8): cb = ColorBar(Qt.Vertical) self.acceleration_list.append(cb) self.status_grid.addWidget(cb, i, 4) self.qem = QErrorMessage(self) self.qem.setWindowTitle("Under Voltage") self.test_button.clicked.connect(self.test_button_clicked) self.output_voltage_button.clicked.connect(self.output_voltage_button_clicked) self.servo_dropbox.currentIndexChanged.connect(lambda x: self.update_servo_specific()) self.enable_checkbox.stateChanged.connect(self.enable_state_changed) self.position_slider.sliderReleased.connect(self.position_slider_released) self.position_slider.valueChanged.connect(self.position_spin.setValue) self.position_spin.editingFinished.connect(self.position_spin_finished) self.velocity_slider.sliderReleased.connect(self.velocity_slider_released) self.velocity_slider.valueChanged.connect(self.velocity_spin.setValue) self.velocity_spin.editingFinished.connect(self.velocity_spin_finished) self.acceleration_slider.sliderReleased.connect(self.acceleration_slider_released) self.acceleration_slider.valueChanged.connect(self.acceleration_spin.setValue) self.acceleration_spin.editingFinished.connect(self.acceleration_spin_finished) self.period_slider.sliderReleased.connect(self.period_slider_released) self.period_slider.valueChanged.connect(self.period_spin.setValue) self.period_spin.editingFinished.connect(self.period_spin_finished) self.pulse_width_min_spin.editingFinished.connect(self.pulse_width_spin_finished) self.pulse_width_max_spin.editingFinished.connect(self.pulse_width_spin_finished) self.degree_min_spin.editingFinished.connect(self.degree_spin_finished) self.degree_max_spin.editingFinished.connect(self.degree_spin_finished) self.minimum_voltage_button.pressed.connect(self.minimum_voltage_button_pressed) self.qtcb_under_voltage.connect(self.cb_under_voltage) self.servo.register_callback(self.servo.CALLBACK_UNDER_VOLTAGE, self.qtcb_under_voltage.emit) class WorkerThread(QThread): def __init__(self, parent = None, func = None): QThread.__init__(self, parent) self.func = func def run(self): self.func() self.test_event = Event() self.test_thread_object = WorkerThread(self, self.test_thread) self.update_event = Event() self.update_thread_object = WorkerThread(self, self.update_thread) self.update_done_event = Event() self.update_done_event.set() def stop(self): if self.test_button.text() == "Stop Test": self.test_button_clicked() self.update_event.clear() self.alive = False self.update_done_event.wait() def start(self): self.alive = True self.test_event.clear() self.update_done_event.set() self.update_event.set() if not self.test_thread_object.isRunning(): self.test_thread_object.start() if not self.update_thread_object.isRunning(): self.update_thread_object.start() self.update_servo_specific() def destroy(self): self.test_event.set() self.update_event.set() @staticmethod def has_name(name): return 'Servo Brick' in name def update_servo_specific(self): i = self.selected_servo() if i == 255: self.enable_checkbox.setCheckState(Qt.Unchecked) return try: pos = self.servo.get_position(i); vel = self.servo.get_velocity(i); acc = self.servo.get_acceleration(i); per = self.servo.get_period(i) ena = self.servo.is_enabled(i) deg_min, deg_max = self.servo.get_degree(i) pulse_min, pulse_max = self.servo.get_pulse_width(i) except ip_connection.Error: return self.position_spin.setValue(pos) self.velocity_spin.setValue(vel) self.acceleration_spin.setValue(acc) self.period_spin.setValue(per) self.position_slider.setValue(pos) self.velocity_slider.setValue(vel) self.acceleration_slider.setValue(acc) self.period_slider.setValue(per) if ena: self.enable_checkbox.setCheckState(Qt.Checked) else: self.enable_checkbox.setCheckState(Qt.Unchecked) self.pulse_width_min_spin.setValue(pulse_min) self.pulse_width_max_spin.setValue(pulse_max) self.degree_min_spin.setValue(deg_min) self.degree_max_spin.setValue(deg_max) self.position_slider.setMinimum(deg_min) self.position_slider.setMaximum(deg_max) self.position_spin.setMinimum(deg_min) self.position_spin.setMaximum(deg_max) self.position_list[i].setTotalAngle((deg_max - deg_min)/100) self.position_list[i].setRange(deg_min/100, deg_max/100) def error_handler(self, error): pass def servo_current_update(self, value): self.current_label.setText(str(value) + "mA") def stack_input_voltage_update(self, sv): sv_str = "%gV" % round(sv/1000.0, 1) self.stack_voltage_label.setText(sv_str) def external_input_voltage_update(self, ev): ev_str = "%gV" % round(ev/1000.0, 1) self.external_voltage_label.setText(ev_str) def output_voltage_update(self, ov): ov_str = "%gV" % round(ov/1000.0, 1) self.output_voltage_label.setText(ov_str) def minimum_voltage_update(self, mv): mv_str = "%gV" % round(mv/1000.0, 1) self.minimum_voltage_label.setText(mv_str) def position_update(self, i, pos): self.position_list[i].setValue(pos/100) def velocity_update(self, i, vel): self.velocity_list[i].set_height(vel*100/0xFFFF) def acceleration_update(self, i, acc): self.acceleration_list[i].set_height(acc*100/0xFFFF) def deactivate_servo(self, i): if self.enable_list[i].text() != 'Off': self.velocity_list[i].grey() self.acceleration_list[i].grey() def activate_servo(self, i): if self.enable_list[i].text() != 'On': self.velocity_list[i].color() self.acceleration_list[i].color() def selected_servo(self): try: return int(self.servo_dropbox.currentText()[-1:]) except: return 255 def enable_state_changed(self, state): s = self.selected_servo() try: if state == Qt.Checked: self.servo.enable(s) elif state == Qt.Unchecked: self.servo.disable(s) except ip_connection.Error: return def update_apply(self): self.servo_current_update(self.up_cur) self.stack_input_voltage_update(self.up_siv) self.external_input_voltage_update(self.up_eiv) self.output_voltage_update(self.up_opv) self.minimum_voltage_update(self.up_mv) for i in range(7): if self.up_ena[i]: self.activate_servo(i) self.position_update(i, self.up_pos[i]) self.velocity_update(i, self.up_vel[i]) self.acceleration_update(i, self.up_acc[i]) self.enable_list[i].setText('On') else: self.deactivate_servo(i) self.enable_list[i].setText('Off') def update_thread(self): while self.alive: time.sleep(0.1) try: servo = self.selected_servo() if servo == 255: self.up_cur = self.servo.get_overall_current() else: self.up_cur = self.servo.get_servo_current(servo) self.up_siv = self.servo.get_stack_input_voltage() self.up_eiv = self.servo.get_external_input_voltage() self.up_opv = self.servo.get_output_voltage() self.up_mv = self.servo.get_minimum_voltage() for i in range(7): self.up_ena[i] = self.servo.is_enabled(i) if self.up_ena[i]: self.activate_servo(i) self.up_pos[i] = self.servo.get_current_position(i) self.up_vel[i] = self.servo.get_current_velocity(i) self.up_acc[i] = self.servo.get_acceleration(i) self.update_timer.start() #self.update_apply() self.update_done_event.set() self.update_event.wait() self.update_done_event.clear() except ip_connection.Error: pass self.update_done_event.set() def test_thread(self): def test(num, ena, acc, vel, pos): if not self.alive: return try: if ena: self.servo.enable(num) else: self.servo.disable(num) self.servo.set_acceleration(num, acc) self.servo.set_velocity(num, vel) self.servo.set_position(num, pos) except ip_connection.Error: return def random_test(): for i in range(7): test(i, random.randrange(0, 2), random.randrange(0, 65536), random.randrange(0, 65536), random.randrange(-9000, 9001)) while self.alive: self.test_event.wait() if not self.alive: return # Full Speed left for 2 seconds for i in range(7): test(i, True, 65535, 65535, 9000) time.sleep(2) self.test_event.wait() if not self.alive: return # Full Speed right for 2 seconds for i in range(7): test(i, True, 65535, 65535, -9000) time.sleep(2) self.test_event.wait() if not self.alive: return # Test different speeds for i in range(19): for j in range(7): test(j, True, 65535, 65535*i/18, -9000+i*1000) time.sleep(0.1) self.test_event.wait() if not self.alive: return time.sleep(1) self.test_event.wait() if not self.alive: return # Test acceleration for i in range(7): test(i, True, 100, 65535, -9000) time.sleep(3) self.test_event.wait() if not self.alive: return # Random for 3 seconds random_test() time.sleep(3) def test_button_clicked(self): if self.test_button.text() == "Start Test": self.test_button.setText("Stop Test") self.test_event.set() else: self.test_button.setText("Start Test") self.test_event.clear() def output_voltage_button_clicked(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(5000) qid.setIntMaximum(27000) qid.setIntStep(100) try: qid.setIntValue(self.servo.get_output_voltage()) except ip_connection.Error: return qid.intValueSelected.connect(self.output_voltage_selected) qid.setLabelText("Choose Output Voltage in mV.") # "<font color=red>Setting this too high can destroy your servo.</font>") qid.open() def output_voltage_selected(self, value): try: self.servo.set_output_voltage(value) except ip_connection.Error: return def position_slider_released(self): value = self.position_slider.value() self.position_spin.setValue(value) try: self.servo.set_position(self.selected_servo(), value) except ip_connection.Error: return def position_spin_finished(self): value = self.position_spin.value() self.position_slider.setValue(value) try: self.servo.set_position(self.selected_servo(), value) except ip_connection.Error: return def velocity_slider_released(self): value = self.velocity_slider.value() self.velocity_spin.setValue(value) try: self.servo.set_velocity(self.selected_servo(), value) except ip_connection.Error: return def velocity_spin_finished(self): value = self.velocity_spin.value() self.velocity_slider.setValue(value) try: self.servo.set_velocity(self.selected_servo(), value) except ip_connection.Error: return def acceleration_slider_released(self): value = self.acceleration_slider.value() self.acceleration_spin.setValue(value) try: self.servo.set_acceleration(self.selected_servo(), value) except ip_connection.Error: return def acceleration_spin_finished(self): value = self.acceleration_spin.value() self.acceleration_slider.setValue(value) try: self.servo.set_acceleration(self.selected_servo(), value) except ip_connection.Error: return def period_slider_released(self): value = self.period_slider.value() self.period_spin.setValue(value) try: self.servo.set_period(self.selected_servo(), value) except ip_connection.Error: return def period_spin_finished(self): value = self.period_spin.value() self.period_slider.setValue(value) try: self.servo.set_period(self.selected_servo(), value) except ip_connection.Error: return def pulse_width_spin_finished(self): try: self.servo.set_pulse_width(self.selected_servo(), self.pulse_width_min_spin.value(), self.pulse_width_max_spin.value()) except ip_connection.Error: return def degree_spin_finished(self): min = self.degree_min_spin.value() max = self.degree_max_spin.value() servo = self.selected_servo() self.position_slider.setMinimum(min) self.position_slider.setMaximum(max) self.position_spin.setMinimum(min) self.position_spin.setMaximum(max) self.position_list[servo].setTotalAngle((max - min)/100) self.position_list[servo].setRange(min/100, max/100) try: self.servo.set_degree(servo, min, max) except ip_connection.Error: return def cb_under_voltage(self, ov): mv_str = self.minimum_voltage_label.text() ov_str = "%gV" % round(ov/1000.0, 1) if not self.qem.isVisible(): self.qem.showMessage("Under Voltage: Output Voltage of " + ov_str + " is below minimum voltage of " + mv_str) def minimum_voltage_selected(self, value): try: self.servo.set_minimum_voltage(value) except ip_connection.Error: return def minimum_voltage_button_pressed(self): qid = QInputDialog(self) qid.setInputMode(QInputDialog.IntInput) qid.setIntMinimum(5000) qid.setIntMaximum(0xFFFF) qid.setIntStep(100) try: qid.setIntValue(self.servo.get_minimum_voltage()) except ip_connection.Error: return qid.intValueSelected.connect(self.minimum_voltage_selected) qid.setLabelText("Choose minimum servo voltage in mV.") qid.open()
def input_device_changed(self, index): self.ui.actionStart.setChecked(False) success, index = self.audiobackend.select_input_device(index) self.settings_dialog.comboBox_inputDevice.setCurrentIndex(index) if not success: # Note: the error message is a child of the settings dialog, so that # that dialog remains on top when the error message is closed error_message = QErrorMessage(self.settings_dialog) error_message.setWindowTitle("Input device error") error_message.showMessage( "Impossible to use the selected input device, reverting to the previous one" ) # reset the channels first_channel = self.audiobackend.get_current_first_channel() self.settings_dialog.comboBox_firstChannel.setCurrentIndex( first_channel) second_channel = self.audiobackend.get_current_second_channel() self.settings_dialog.comboBox_secondChannel.setCurrentIndex( second_channel) self.ui.actionStart.setChecked(True)