def test_save_prefs(self):
        coolant_range = Range(1, 10, color=[2, 2, 2, 2])
        rpm_range = Range(100, 10000, color=[3, 3, 3, 3])
        self.userprefs.set_range_alert('Coolant', coolant_range)
        self.userprefs.set_range_alert('RPM', rpm_range)

        self.userprefs.save()

        #Did it create the file in the right location?
        self.assertTrue(
            os.path.isfile(self.data_dir + '/' +
                           self.userprefs.prefs_file_name))

        newprefs = UserPrefs(self.data_dir, save_timeout=1000)

        #newprefs should load the prefs file
        new_coolant = newprefs.get_range_alert('Coolant')
        new_rpm = newprefs.get_range_alert('RPM')

        self.assertEquals(coolant_range.min, new_coolant.min,
                          "Range min not saved and loaded from prefs file")
        self.assertEquals(coolant_range.max, new_coolant.max,
                          "Range max not saved and loaded from prefs file")
        self.assertEquals(coolant_range.color, new_coolant.color,
                          "Range color not saved and loaded from prefs file")

        self.assertEquals(rpm_range.min, new_rpm.min,
                          "Range min not saved and loaded from prefs file")
        self.assertEquals(rpm_range.max, new_rpm.max,
                          "Range max not saved and loaded from prefs file")
        self.assertEquals(rpm_range.color, new_rpm.color,
                          "Range color not saved and loaded from prefs file")
Example #2
0
    def init_view(self):
        channel = self.channel
        channelMeta = self.channelMeta
        if channel and channelMeta:
            self.valueFormat = '{0:.' + str(self.channelMeta.precision) + 'f}'

            warnRange = self.settings.userPrefs.get_range_alert(
                self.getWarnPrefsKey(channel),
                Range(min=channelMeta.max,
                      max=channelMeta.max,
                      color=Range.DEFAULT_WARN_COLOR))
            alertRange = self.settings.userPrefs.get_range_alert(
                self.getAlertPrefsKey(channel),
                Range(min=channelMeta.max,
                      max=channelMeta.max,
                      color=Range.DEFAULT_ALERT_COLOR))

            self.setupSlider(self.ids.warnLowSlider, channelMeta,
                             warnRange.min)
            self.setupSlider(self.ids.warnHighSlider, channelMeta,
                             warnRange.max)

            self.setupSlider(self.ids.alertLowSlider, channelMeta,
                             alertRange.min)
            self.setupSlider(self.ids.alertHighSlider, channelMeta,
                             alertRange.max)

            self.ids.selectedWarnColor.color = warnRange.color
            self.ids.selectedAlertColor.color = alertRange.color

            self.alertRange = alertRange
            self.warnRange = warnRange
    def test_range_to_json(self):
        expected = '{"color": [2, 2, 2, 2], "max": 10, "min": 0}'
        min = 0
        max = 10
        color = [2, 2, 2, 2]
        range = Range(min, max, color=color)
        range_json = range.to_json()

        self.assertEquals(expected, range_json, "Range to_json output does not match expected output")
    def test_range_from_dict(self):
        min = 0
        max = 10
        color = [2, 2, 2, 2]
        original_range = Range(min, max, color=color)
        range_dict = original_range.to_dict()

        new_range = Range.from_dict(range_dict)

        self.assertEquals(original_range.max, new_range.max, "New and old range max do not match")
        self.assertEquals(original_range.min, new_range.min, "New and old range min do not match")
        self.assertEquals(original_range.color, new_range.color, "New and old range color does not match")
Example #5
0
    def __init__(self, **kwargs):
        self.settings = None
        self.channel = None
        self.channelMeta = None
        self.warnRange = Range()
        self.alertRange = Range()
        self.valueFormat = '{0:.0f}'

        super(ChannelCustomizationView, self).__init__(**kwargs)
        self.register_event_type('on_channel_customization_close')
        
        self.settings = kwargs.get('settings')
        self.channel = kwargs.get('channel')
        self.channelMeta = self.settings.runtimeChannels.findChannelMeta(self.channel)
        self.init_view()
    def test_set_get_range_alert(self):
        test_range = Range(1, 10)
        self.userprefs.set_range_alert('Coolant', test_range)

        fetched_range = self.userprefs.get_range_alert('Coolant')

        self.assertEquals(test_range.min, fetched_range.min,
                          "Saved range and fetched range do not match")
    def test_range_constructor(self):
        min = 0
        max = 10
        color = [2, 2, 2, 2]
        range = Range(minimum=min, maximum=max, color=color)

        self.assertEquals(min, range.min, msg="Range did not set min property")
        self.assertEquals(max, range.max, msg="Range did not set max property")
        self.assertEquals(color, range.color, msg="Range did not set color property")
    def save_timer(self):
        prefs = UserPrefs(self.data_dir, save_timeout=1)
        rpm_range = Range(1000, 8000)
        prefs.set_range_alert('RPM', rpm_range)

        time.sleep(3)

        new_prefs = UserPrefs(self.data_dir, save_timeout=1000)
        new_rpm_range = new_prefs.get_range_alert('RPM')

        self.assertEquals(rpm_range.min, new_rpm_range.min,
                          "UserPrefs not saved automatically")
    def test_range_is_in_range(self):
        min = 0
        max = 10
        color = [2, 2, 2, 2]
        range = Range(min, max, color=color)

        self.assertTrue(range.is_in_range(0))
        self.assertTrue(range.is_in_range(10))
        self.assertTrue(range.is_in_range(5))
        self.assertFalse(range.is_in_range(-1))
        self.assertFalse(range.is_in_range(11))
Example #10
0
class CustomizableGauge(ButtonBehavior, SingleChannelGauge):
    _popup = None
    _customizeGaugeBubble = None
    warning = ObjectProperty(Range())
    alert = ObjectProperty(Range())
    min = NumericProperty(DEFAULT_MIN)
    max = NumericProperty(DEFAULT_MAX)
    _dismiss_customization_popup_trigger = None
    is_removable = BooleanProperty(True)
    is_channel_selectable = BooleanProperty(True)

    def __init__(self, **kwargs):
        super(CustomizableGauge, self).__init__(**kwargs)
        self._dismiss_customization_popup_trigger = Clock.create_trigger(
            self._dismiss_popup, POPUP_DISMISS_TIMEOUT_LONG)

    def _remove_customization_bubble(self, *args):
        try:
            if self._customizeGaugeBubble:
                self._customizeGaugeBubble.dismiss()
                self._customizeGaugeBubble = None
        except:
            pass

    def _get_warn_prefs_key(self, channel):
        return '{}.warn'.format(self.channel)

    def _get_alert_prefs_key(self, channel):
        return '{}.alert'.format(self.channel)

    def _update_channel_ranges(self):
        channel = self.channel
        user_prefs = self.settings.userPrefs
        self.warning = user_prefs.get_range_alert(
            self._get_warn_prefs_key(channel), self.warning)
        self.alert = user_prefs.get_range_alert(
            self._get_alert_prefs_key(channel), self.alert)

    def removeChannel(self):
        self._remove_customization_bubble()
        channel = self.channel
        if channel:
            self.data_bus.removeChannelListener(channel, self.setValue)
        self.channel = None

    def customizeGauge(self, *args):
        self._remove_customization_bubble()
        self.showChannelConfigDialog()

    def selectChannel(self, *args):
        self._remove_customization_bubble()
        self.showChannelSelectDialog()

    def select_alert_color(self):
        value = self.value
        color = self.normal_color
        if self.alert and self.alert.is_in_range(value):
            color = self.alert.color
        elif self.warning and self.warning.is_in_range(value):
            color = self.warning.color
        return color

    def updateColors(self):
        view = self.valueView
        if view:
            view.color = self.select_alert_color()

    def showChannelSelectDialog(self):
        content = ChannelSelectView(settings=self.settings,
                                    channel=self.channel)
        content.bind(on_channel_selected=self.channel_selected)
        content.bind(on_channel_cancel=self._dismiss_popup)

        popup = Popup(title="Select Channel",
                      content=content,
                      size_hint=(0.5, 0.7))
        popup.bind(on_dismiss=self.popup_dismissed)
        popup.open()
        self._popup = popup
        self._dismiss_customization_popup_trigger()

    def on_channel_customization_close(self, instance, warn_range, alert_range,
                                       *args):
        try:
            self.warning = warn_range
            self.alert = alert_range
        except Exception as e:
            Logger.error("Gauge: Error customizing channel: " + str(e))
        self._dismiss_popup()

    def showChannelConfigDialog(self):
        content = ChannelCustomizationView(settings=self.settings,
                                           channel=self.channel)
        content.bind(
            on_channel_customization_close=self.on_channel_customization_close)

        popup = Popup(title='Customize {}'.format(self.channel),
                      content=content,
                      size_hint=(0.6, 0.8))
        popup.bind(on_dismiss=self.popup_dismissed)
        popup.open()
        self._popup = popup
        self._dismiss_customization_popup_trigger()

    def channel_selected(self, instance, value):
        if self.channel:
            self.data_bus.removeChannelListener(self.channel, self.setValue)
        self.value = None
        self.channel = value
        self.settings.userPrefs.set_gauge_config(self.rcid, value)
        self._dismiss_popup()

    def popup_dismissed(self, *args):
        self._popup = None

    def _dismiss_popup(self, *args):
        if self._popup:
            self._popup.dismiss()
            self._popup = None

    def on_release(self):
        if not self.channel:
            self.showChannelSelectDialog()
        else:
            bubble = CustomizeGaugeBubble()
            buttons = []
            if self.is_removable:
                buttons.append(
                    BubbleButton(text='Remove',
                                 on_press=lambda a: self.removeChannel()))
            if self.is_channel_selectable:
                buttons.append(
                    BubbleButton(text='Select Channel',
                                 on_press=lambda a: self.selectChannel()))
            buttons.append(
                BubbleButton(text='Customize',
                             on_press=lambda a: self.customizeGauge()))
            if len(buttons) == 1:
                buttons[0].dispatch('on_press')
            else:
                for b in buttons:
                    bubble.add_widget(b)

                bubble_height = dp(150)
                bubble_width = dp(200)
                bubble.size = (bubble_width, bubble_height)
                bubble.center_on_limited(self)
                bubble.auto_dismiss_timeout(POPUP_DISMISS_TIMEOUT_SHORT)
                self._customizeGaugeBubble = bubble
                self.add_widget(bubble)
Example #11
0
class Gauge(ButtonBehavior, AnchorLayout):
    _customizeGaugeBubble = None
    _valueView = None
    is_removable = BooleanProperty(True)
    is_channel_selectable = BooleanProperty(True)
    settings = ObjectProperty(None)
    value_size = NumericProperty(0)
    title_size = NumericProperty(0)
    channel = StringProperty(None, allownone=True)
    title = StringProperty('')
    value = NumericProperty(None, allownone=True)
    valueFormat = "{:.0f}"
    precision = NumericProperty(DEFAULT_PRECISION)
    warning = ObjectProperty(Range())
    alert = ObjectProperty(Range())
    min = NumericProperty(DEFAULT_MIN)
    max = NumericProperty(DEFAULT_MAX)
    title_color = ObjectProperty(DEFAULT_NORMAL_COLOR)
    normal_color = ObjectProperty(DEFAULT_NORMAL_COLOR)
    pressed = ListProperty([0, 0])
    data_bus = ObjectProperty(None)
    rcid = None
    _popup = None

    _dismiss_customization_popup_trigger = None

    def __init__(self, **kwargs):
        super(Gauge, self).__init__(**kwargs)
        self.rcid = kwargs.get('rcid', self.rcid)
        self.data_bus = kwargs.get('dataBus', self.data_bus)
        self.settings = kwargs.get('settings', self.settings)
        self.channel = kwargs.get('targetchannel', self.channel)
        self._dismiss_customization_popup_trigger = Clock.create_trigger(
            self._dismiss_popup, POPUP_DISMISS_TIMEOUT_LONG)

    def _remove_customization_bubble(self, *args):
        try:
            if self._customizeGaugeBubble:
                self._customizeGaugeBubble.dismiss()
                self._customizeGaugeBubble = None
        except:
            pass

    def _get_warn_prefs_key(self, channel):
        return '{}.warn'.format(self.channel)

    def _get_alert_prefs_key(self, channel):
        return '{}.alert'.format(self.channel)

    def _update_channel_ranges(self):
        channel = self.channel
        user_prefs = self.settings.userPrefs
        self.warning = user_prefs.get_range_alert(
            self._get_warn_prefs_key(channel), self.warning)
        self.alert = user_prefs.get_range_alert(
            self._get_alert_prefs_key(channel), self.alert)

    def removeChannel(self):
        self._remove_customization_bubble()
        channel = self.channel
        if channel:
            self.data_bus.removeChannelListener(channel, self.setValue)
        self.channel = None

    def customizeGauge(self, *args):
        self._remove_customization_bubble()
        self.showChannelConfigDialog()

    def selectChannel(self, *args):
        self._remove_customization_bubble()
        self.showChannelSelectDialog()

    @property
    def valueView(self):
        if not self._valueView:
            self._valueView = kvFind(self, 'rcid', 'value')
        return self._valueView

    @property
    def titleView(self):
        return kvFind(self, 'rcid', 'title')

    def select_alert_color(self):
        value = self.value
        color = self.normal_color
        if self.alert and self.alert.is_in_range(value):
            color = self.alert.color
        elif self.warning and self.warning.is_in_range(value):
            color = self.warning.color
        return color

    def updateColors(self):
        view = self.valueView
        if view: view.color = self.select_alert_color()

    def on_value(self, instance, value):
        view = self.valueView
        if value != None:
            if view:
                view.text = self.valueFormat.format(value)
                self.updateColors()
        else:
            view.text = ''

    def on_title(self, instance, value):
        if not value == None:
            view = kvFind(self, 'rcid', 'title')
            view.text = str(value)

    def on_precision(self, instance, value):
        self.valueFormat = '{:.' + str(value) + 'f}'

    def on_title_color(self, instance, value):
        self.titleView.color = value

    def on_value_size(self, instance, value):
        view = self.valueView
        if view:
            view.font_size = value

    def on_title_size(self, instance, value):
        view = self.titleView
        if view:
            view.font_size = value

    def setValue(self, value):
        self.value = value

    def showChannelSelectDialog(self):
        content = ChannelSelectView(settings=self.settings,
                                    channel=self.channel)
        content.bind(on_channel_selected=self.channel_selected)
        content.bind(on_channel_cancel=self._dismiss_popup)

        popup = Popup(title="Select Channel",
                      content=content,
                      size_hint=(0.5, 0.7))
        popup.bind(on_dismiss=self.popup_dismissed)
        popup.open()
        self._popup = popup
        self._dismiss_customization_popup_trigger()

    def on_channel_customization_close(self, instance, warn_range, alert_range,
                                       *args):
        try:
            self.warning = warn_range
            self.alert = alert_range
        except Exception as e:
            print("Error customizing channel: " + str(e))

        self._dismiss_popup()

    def showChannelConfigDialog(self):
        content = ChannelCustomizationView(settings=self.settings,
                                           channel=self.channel)
        content.bind(
            on_channel_customization_close=self.on_channel_customization_close)

        popup = Popup(title='Customize {}'.format(self.channel),
                      content=content,
                      size_hint=(0.6, 0.7))
        popup.bind(on_dismiss=self.popup_dismissed)
        popup.open()
        self._popup = popup
        self._dismiss_customization_popup_trigger()

    def channel_selected(self, instance, value):
        if self.channel:
            self.data_bus.removeChannelListener(self.channel, self.setValue)
        self.value = None
        self.channel = value
        self.settings.userPrefs.set_gauge_config(self.rcid, value)
        self._dismiss_popup()

    def popup_dismissed(self, *args):
        self._popup = None

    def _dismiss_popup(self, *args):
        if self._popup:
            self._popup.dismiss()
            self._popup = None

    def on_channel(self, instance, value):
        try:
            self._update_display()
            self.update_title()
            self._update_channel_binding()
            self._update_channel_ranges()
        except Exception as e:
            print('Error setting channel {} {}'.format(value, str(e)))

    def on_settings(self, instance, value):
        #Do I have an id so I can track my settings?
        if self.rcid:
            channel = self.settings.userPrefs.get_gauge_config(self.rcid)
            if channel:
                self.channel = channel

    def on_data_bus(self, instance, value):
        self._update_channel_binding()

    def update_title(self):
        try:
            channel = self.channel
            if channel:
                channelMeta = self.settings.systemChannels.channels.get(
                    channel)
                title = channelMeta.name
                if channelMeta.units and len(channelMeta.units):
                    title += '\n({})'.format(channelMeta.units)
                self.title = title
            else:
                self.title = ''
        except Exception as e:
            print('Failed to update gauge title & units ' + str(e))

    def _update_display(self):
        try:
            channelMeta = self.settings.systemChannels.channels.get(
                self.channel)
            if channelMeta:
                self.min = channelMeta.min
                self.max = channelMeta.max
                self.precision = channelMeta.precision
            else:
                self.min = DEFAULT_MIN
                self.max = DEFAULT_MAX
                self.precision = DEFAULT_PRECISION
                self.value = DEFAULT_VALUE
        except Exception as e:
            print('Failed to update gauge min/max ' + str(e))

    def _update_channel_binding(self):
        dataBus = self.data_bus
        channel = self.channel
        if dataBus and channel:
            dataBus.addChannelListener(str(channel), self.setValue)

    def on_release(self):
        if not self.channel:
            self.showChannelSelectDialog()
        else:
            bubble = CustomizeGaugeBubble()
            buttons = []
            if self.is_removable:
                buttons.append(
                    BubbleButton(text='Remove',
                                 on_press=lambda a: self.removeChannel()))
            if self.is_channel_selectable:
                buttons.append(
                    BubbleButton(text='Select Channel',
                                 on_press=lambda a: self.selectChannel()))
            buttons.append(
                BubbleButton(text='Customize',
                             on_press=lambda a: self.customizeGauge()))
            if len(buttons) == 1:
                buttons[0].dispatch('on_press')
            else:
                for b in buttons:
                    bubble.add_widget(b)

                bubble_height = dp(150)
                bubble_width = dp(200)
                bubble.size = (bubble_width, bubble_height)
                bubble.center_on_limited(self)
                bubble.auto_dismiss_timeout(POPUP_DISMISS_TIMEOUT_SHORT)
                self._customizeGaugeBubble = bubble
                self.add_widget(bubble)