-
Notifications
You must be signed in to change notification settings - Fork 302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Seven segment display #488
Conversation
Current coverage is 79.50% (diff: 98.31%)@@ master #488 diff @@
==========================================
Files 31 31
Lines 7213 7689 +476
Methods 0 0
Messages 0 0
Branches 0 0
==========================================
+ Hits 5645 6113 +468
- Misses 1568 1576 +8
Partials 0 0
|
gpiozero/boards.py
Outdated
for led in range(7): | ||
self[led].value = layout[led] | ||
else: | ||
raise ValueError('There is no layout for character %s') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
%s doesn't get substituted (whoops)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duh
gpiozero/boards.py
Outdated
'L': (False, False, False, True, True, True, False), | ||
'M': (True, False, True, False, True, False, False), | ||
'N': (True, True, True, False, True, True, False), | ||
'O': (True, True, True, True, True, True, False), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has the same representation as '0' - not sure if that's a good idea, but I'm open to arguments either way...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer "O" tiny, but some suggestions found on google images put equal to zero
http://chrispurdie.com/wp-content/uploads/2012/12/7seg1_WEB.jpg
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See, that's what I mean about different people wanting to map different characters to different 7-seg combinations... ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everyone's a critic...
I'll add a method to set_char_layout(char, layout)
gpiozero/boards.py
Outdated
def __init__(self, *pins, **kwargs): | ||
# 7 segment displays must have 7 or 8 pins | ||
if len(pins) < 7 or len(pins) > 8: | ||
raise ValueError('7 segment display must have 7 or 8 pins') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps change 7 segment display
to SevenSegmentDisplay
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep
Ping @SrMouraSilva in case he has any comments. |
assert not isinstance(pin, LEDCollection) | ||
pwm = kwargs.pop('pwm', False) | ||
active_high = kwargs.pop('active_high', True) | ||
if kwargs: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In common with LEDBoard, should we also have a boolean initial_value
property?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep
gpiozero/boards.py
Outdated
if len(self) > 7: | ||
return self[7].value | ||
else: | ||
raise OutputDeviceError('There is no 8th pin for the decimal point') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't decide whether trying to get the decimal point on a 7-pin SevenSegment should just always return False
, rather than raising an exception?
(OTOH, trying to set the dp on a 7-pin SevenSegment probably should still raise an exception?)
gpiozero/boards.py
Outdated
'S': (True, False, True, True, False, True, True), | ||
'T': (False, False, False, True, True, True, True), | ||
'U': (False, True, True, True, True, True, False), | ||
'V': (False, True, True, True, True, True, False), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'U' and 'V' are also indistinguishable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep - made u a 'little u' 'U': (False, False, True, True, True, False, False),
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I add my opinion based in #357 issue
gpiozero/boards.py
Outdated
|
||
def __init__(self, *pins, **kwargs): | ||
# 7 segment displays must have 7 or 8 pins | ||
if len(pins) < 7 or len(pins) > 8: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if 6 < len(a) < 8:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect you might have meant if not 6 < len(pins) < 9:
? IMHO that's less readable though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's true. I'm sorry
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think its more readable as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd use if len(pins) not in (7, 8)
@@ -1185,3 +1185,86 @@ def on(self): | |||
def off(self): | |||
self.value = False | |||
|
|||
class SevenSegmentDisplay(LEDBoard): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignore it
if I want to know if it is on or off, how do?
I suggest a status attribute for it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A custom __repr__
is a good idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if I want to know if it is on or off, how do?
is_active
will tell you if any LEDs are lit https://github.com/RPi-Distro/python-gpiozero/blob/master/gpiozero/devices.py#L357
(unfortunately that's not in the docs yet)
A custom
__repr__
is a good idea
What do you suggest? Is the __repr__
provided by CompositeDevice not good enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you suggest? Is the
__repr__
provided by CompositeDevice not good enough?
I was thinking also display the character represented
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking also display the character represented
If that was to be added, wouldn't that be a better fit for __str__
rather than __repr__
? shrug
gpiozero/boards.py
Outdated
if len(char) > 1: | ||
raise ValueError('Only a single character can be displayed') | ||
if char in SevenSegmentDisplay.layouts: | ||
layout = SevenSegmentDisplay.layouts[char] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer that the denial be up to reduce the complexity idiomatic
if char not in SevenSegmentDisplay.layouts:
raise ValueError('There is no layout for character %s')
layout = SevenSegmentDisplay.layouts[char]
for led in range(7):
self[led].value = layout[led]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, I like that
gpiozero/boards.py
Outdated
@@ -1185,3 +1185,86 @@ def on(self): | |||
def off(self): | |||
self.value = False | |||
|
|||
class SevenSegmentDisplay(LEDBoard): | |||
layouts = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the layout contemplate that both possibilities, I am in favor of a way to get (@property
only) the string representation of what is being displayed: char + dp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...and what should it do if the 7-seg is displaying a combination that doesn't map to a character?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that such a static method that receives a display and displays the character?
Or only raises a Error like if the user call display(notMapedChar).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Being (ultimately) based on CompositeOutputDevice
, the user is free to set the .value
property (tuple of bools) to whatever combination they see fit - we don't restrict what combinations they can use. And as mentioned before, I'm not sure that having a property-getter that throws Exceptions is a good idea :-/
Updated PR based on comments above. |
initial_value = kwargs.pop('initial_value', False) | ||
if kwargs: | ||
raise TypeError('unexpected keyword argument: %s' % kwargs.popitem()[0]) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth adding a code-comment in here that the LED segments in the _layouts
array are listed in the order (a, b, c, d, e, f, g) ?
else: | ||
raise OutputDeviceError('there is no 8th pin for the decimal point') | ||
|
||
def set_char_layout(self, char, layout): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess a docstring explaining the char
and layout
parameters would be really useful? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added docstrings to the class now as we seem to be reaching a concensus.
gpiozero/boards.py
Outdated
raise OutputDeviceError('there is no 8th pin for the decimal point') | ||
|
||
def set_char_layout(self, char, layout): | ||
char = str(char) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this should probably be char = str(char).upper()
to match the display
function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a conscious decision to not upper it, but for the life of me I cant think of my reasoning... I'll upper it!
Yep, looking nice :-) Would it be worth adding an What does @bennuttall think of my suggestion of the decimal_point property-getter always returning False for 7-segments that don't have a decimal point LED? |
raise OutputDeviceError('there is no 8th pin for the decimal point') | ||
|
||
def set_char_layout(self, char, layout): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- A setter method is pythonic?
- For me the
set_char_layout
gives the impression that I can only change an existing layout. - If the layout is attribute (
self._layout
) not a static method, if I change a char layout of a 7seg display, then is desirable that another 7seg haven't this layout?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I purposely made `._layouts' private to the instance rather than static as I felt it might be confusing if a change was reflected across multi instances.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that modifiable attributes should be instance attributes rather than class attributes.
Updated PR based on comments & added docs |
from gpiozero import SevenSegmentDisplay | ||
|
||
seven = SevenSegmentDisplay(1,2,3,4,5,6,7,8,active_high=False) | ||
seven.display("7") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'seven display seven' sounds a bit tautological ;-)
Perhaps seven.display("5")
And GPIO1 is one of the 'reserved' pins, so maybe pins 2-9 would be better? (only a minor point)
@@ -1267,13 +1320,26 @@ def decimal_point(self): | |||
|
|||
@decimal_point.setter | |||
def decimal_point(self, value): | |||
""" | |||
Sets the status of the decimal point led | |||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think property-setters need their own docstring?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There were examples that did so I thought id put them in anyway.
Great docs, thanks :-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some commentaries about "commentaries"
gpiozero/boards.py
Outdated
""" | ||
def __init__(self, *pins, **kwargs): | ||
# 7 segment displays must have 7 or 8 pins | ||
if len(pins) < 7 or len(pins) > 8: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The commentary is redundant (see your documentation and the if len(pins) < 7 or len(pins) > 8:
)
if len(pins) < 7 or len(pins) > 8: | ||
raise ValueError('SevenSegmentDisplay must have 7 or 8 pins') | ||
# Don't allow 7 segments to contain collections | ||
for pin in pins: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me, the commentary is redundant
gpiozero/boards.py
Outdated
Represents the status of the decimal point led | ||
""" | ||
# does the 7seg display have a decimal point (i.e pin 8) | ||
if len(self) > 7: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commentary is necessary?
It is being planned you perform some test? |
multi seven seg display tests
@bennuttall @lurch @waveform80 anyone got any thoughts on why my tests are failing for pypy... I am at a loss. |
Modded multi seven seg tests
Dev - modded multi seven seg tests
Resolved test issues with pypy... Threading - bah. |
Hello. Any news? |
Love the idea, and most of the PR (especially that there's a layouts dict which is exactly what I'd want to see). Needs a little love before merge though, and I need to ponder whether this is an example of a class where it'd be acceptable to have a string-based "value" (esp. for the multi-segment one). Scheduling for 1.5. |
|
||
from gpiozero import MultiSevenSegmentDisplay | ||
|
||
multi_seven = MultiSevenSegmentDisplay((1,2,3,4,5,6,7,8)(9,10,11,12)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems to be a missing comma between the two tuples
parameter can only be specified as a keyword parameter. | ||
|
||
:param bool active_high: | ||
If ``True`` (the default), the :meth:`on` method will set all the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps the documentation here should talk about common-anode and common-cathode, rather than talking about HIGH and LOW?
Right, erm, four years later (sorry!) I've finally gotten around to doing something about this! I rebased the original PR on the current master and had a play around with it, and came back to my original comment:
I was still of the opinion that this is one of those cases where not having a numeric value is justified. After all, composite boards don't have numeric values (okay, they've got a tuple of numeric values, but it's still not strictly a number), and a 1-char value in this case can be seen as a reasonable representation of the device's state (just as the single number in the case of the other LEDCollection derivative, LEDBarGraph, is a reasonable representation of its state). Anyway, as a result I've done quite a bit of re-working on this and it'll need a separate PR for review so I'll close this and anyone interested can go have a look at #930 which is the continuation. |
Bumps [gpiozero](https://github.com/gpiozero/gpiozero) from 1.5.1 to 2.0.1. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/gpiozero/gpiozero/blob/master/docs/changelog.rst">gpiozero's changelog</a>.</em></p> <blockquote> <h1>Release 2.0.1 (2024-02-15)</h1> <ul> <li>Fixed Python 3.12 compatibility, and clarify that 3.9 is the lowest supported version in our CI configuration (<code>[#1113](https://github.com/gpiozero/gpiozero/issues/1113)</code>_)</li> </ul> <p>.. _<a href="https://redirect.github.com/gpiozero/gpiozero/issues/1113">#1113</a>: <a href="https://redirect.github.com/gpiozero/gpiozero/issues/1113">gpiozero/gpiozero#1113</a></p> <h1>Release 2.0 (2023-09-12)</h1> <ul> <li>Removed Python 2.x support; many thanks to Fangchen Li for a substantial amount of work on this! (<code>[#799](https://github.com/gpiozero/gpiozero/issues/799)</code>_ <code>[#896](https://github.com/gpiozero/gpiozero/issues/896)</code>_)</li> <li>Removed RPIO pin implementation</li> <li>Made :class:<code>gpiozero.pins.lgpio.LGPIOFactory</code> the default factory; the former default, :class:<code>gpiozero.pins.rpigpio.RPiGPIOFactory</code>, is now the second place preference</li> <li>Added :doc:<code>compat</code> chapter</li> <li>Added :program:<code>pintest</code> utility</li> <li>Added Raspberry Pi 5 board data</li> </ul> <p>.. _<a href="https://redirect.github.com/gpiozero/gpiozero/issues/799">#799</a>: <a href="https://redirect.github.com/gpiozero/gpiozero/issues/799">gpiozero/gpiozero#799</a> .. _<a href="https://redirect.github.com/gpiozero/gpiozero/issues/896">#896</a>: <a href="https://redirect.github.com/gpiozero/gpiozero/issues/896">gpiozero/gpiozero#896</a></p> <h1>Release 1.6.2 (2021-03-18)</h1> <ul> <li>Correct docs referring to 1.6.0 as the last version supporting Python 2</li> </ul> <p>.. warning::</p> <pre><code>This is the last release to support Python 2 </code></pre> <h1>Release 1.6.1 (2021-03-17)</h1> <ul> <li>Fix missing font files for 7-segment displays</li> </ul> <h1>Release 1.6.0 (2021-03-14)</h1> <ul> <li>Added :class:<code>RotaryEncoder</code> class (thanks to Paulo Mateus) (<code>[#482](https://github.com/gpiozero/gpiozero/issues/482)</code><em>, <code>[#928](https://github.com/gpiozero/gpiozero/issues/928)</code></em>)</li> <li>Added support for multi-segment character displays with :class:<code>LEDCharDisplay</code> and :class:<code>LEDMultiCharDisplay</code> along with "font" support using :class:<code>LEDCharFont</code> (thanks to Martin O'Hanlon) (<code>[#357](https://github.com/gpiozero/gpiozero/issues/357)</code><em>, <code>[#485](https://github.com/gpiozero/gpiozero/issues/485)</code></em>, <code>[#488](https://github.com/gpiozero/gpiozero/issues/488)</code><em>, <code>[#493](https://github.com/gpiozero/gpiozero/issues/493)</code></em>, <code>[#930](https://github.com/gpiozero/gpiozero/issues/930)</code>_)</li> <li>Added :class:<code>Pibrella</code> class (thanks to Carl Monk) (<code>[#773](https://github.com/gpiozero/gpiozero/issues/773)</code><em>, <code>[#798](https://github.com/gpiozero/gpiozero/issues/798)</code></em>)</li> <li>Added :class:<code>TrafficpHat</code> class (thanks to Ryan Walmsley) (<code>[#845](https://github.com/gpiozero/gpiozero/issues/845)</code><em>, <code>[#846](https://github.com/gpiozero/gpiozero/issues/846)</code></em>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/gpiozero/gpiozero/commit/a13848bd9701844c139709750cfa038c59b2ab5f"><code>a13848b</code></a> Run copyrights script for release</li> <li><a href="https://github.com/gpiozero/gpiozero/commit/3ee415cbfd5de07324696ceadd22ded92c48a517"><code>3ee415c</code></a> Bump revision and add changelog for release</li> <li><a href="https://github.com/gpiozero/gpiozero/commit/ebf8874bd71d353ebb5f83dcb1fdbc6be58b454d"><code>ebf8874</code></a> Fix <a href="https://redirect.github.com/gpiozero/gpiozero/issues/1113">#1113</a></li> <li><a href="https://github.com/gpiozero/gpiozero/commit/fa114311048c052ea1b6810c235cc0f858720f36"><code>fa11431</code></a> Set 3.9 as base version, fix 3.12 compatibility</li> <li><a href="https://github.com/gpiozero/gpiozero/commit/981e3f70b00853fd011baf8cd1cb17f241e4ab65"><code>981e3f7</code></a> Merge pull request <a href="https://redirect.github.com/gpiozero/gpiozero/issues/1104">#1104</a> from lurch/patch-2</li> <li><a href="https://github.com/gpiozero/gpiozero/commit/0f09a5a1d0c3b0055cdfe52de3009deea30f8654"><code>0f09a5a</code></a> Small docs typo</li> <li><a href="https://github.com/gpiozero/gpiozero/commit/e59c55c77bdd635a566ff31815e93a51d54907e8"><code>e59c55c</code></a> Workaround rtd's ancient flag</li> <li><a href="https://github.com/gpiozero/gpiozero/commit/025ba5bc2f0b7a0936afc792345a0615586f6b61"><code>025ba5b</code></a> Would help if I specified the right requirement...</li> <li><a href="https://github.com/gpiozero/gpiozero/commit/cba887aa60d3c844ea7e36f8c4d170fd9073d87c"><code>cba887a</code></a> RTD builds "old" projects with sphinx 1.8</li> <li><a href="https://github.com/gpiozero/gpiozero/commit/390caf61ba73af65f39395551c25674631eca7d0"><code>390caf6</code></a> The root doc default changed to 'contents'</li> <li>Additional commits viewable in <a href="https://github.com/gpiozero/gpiozero/compare/v1.5.1...v2.0.1">compare view</a></li> </ul> </details> <br /> [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=gpiozero&package-manager=pip&previous-version=1.5.1&new-version=2.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Initial PR for seven segment display
Related to issue #485