Merge pull request #43 from ian57/master

chore: add french accentuated character
rebase020124
Jürgen Weigert 1 year ago committed by GitHub
commit c3e3132ba2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 45
      README.md
  2. 141
      led-badge-11x44.py
  3. BIN
      photos/accentuated.gif
  4. BIN
      photos/blueBadge.jpg
  5. BIN
      photos/m2ishm.gif

@ -1,7 +1,11 @@
# Led-Badge-44x11
Upload tool for an led name tag with USB-HID interface
![LED Mini Board](photos/green_badge.jpg)
![LED Mini Board](photos/blueBadge.jpg)
Added Accentuated french Characters
![French LED Mini Board](photos/accentuated.gif)
## Hardware
@ -129,6 +133,10 @@ shows a bicycle crossing the display in left-to-right and right-to-left (as a se
shows a simple animation of a slowly beating heart on the first message, and a blinking heart on the second message.
./led-badge-11x44.py -B 50 -m 0 -s 8 "Bonjour à toutes et à tous" "Bienvenu(e)s en Master 2 EEA ISHM" "Ingénierie des systèmes Humains Machines" "Bonne réussite à votre promotion 2023-2024"
![M2 ishm](photos/m2ishm.gif)
python3 ./led-badge-11x44.py --list-names
prints the list of builtin icon names, including :happy: :happy2: :heart: :HEART: :heart2: :HEART2: :fablab: :bicycle: :bicycle_r: :owncloud: ::
@ -138,36 +146,27 @@ prints the list of builtin icon names, including :happy: :happy2: :heart: :HEART
prints some condensed help:
<pre>
usage: led-badge-11x44.py [-h] [-t TYPE] [-s SPEED] [-m MODE] [-b BLINK]
[-a ANTS] [-p FILE] [-l]
MESSAGE [MESSAGE ...]
usage: led-badge-11x44.py [-h] [-t TYPE] [-s SPEED] [-B BRIGHTNESS] [-m MODE] [-b BLINK] [-a ANTS] [-l] MESSAGE [MESSAGE ...]
Upload messages or graphics to a 44x11 led badge via USB HID.
Version 0.6 from https://github.com/jnweiger/led-badge-44x11
Upload messages or graphics to a 11x44 led badge via USB HID.
Version 0.12 from https://github.com/jnweiger/led-name-badge-ls32
-- see there for more examples and for updates.
positional arguments:
MESSAGE Up to 8 message texts with embedded builtin icons or
loaded images within colons(:) -- See -l for a list of
builtins
MESSAGE Up to 8 message texts with embedded builtin icons or loaded images within colons(:) -- See -l for a list of builtins
optional arguments:
options:
-h, --help show this help message and exit
-t TYPE, --type TYPE
Type of display: supported values are 12x48 or
(default) 11x44. Rename the program to led-badge-12x48,
to switch the default.
-t TYPE, --type TYPE Type of display: supported values are 12x48 or (default) 11x44. Rename the program to led-badge-12x48, to switch the default.
-s SPEED, --speed SPEED
Scroll speed (Range 1..8). Up to 8 comma-seperated
values
-m MODE, --mode MODE Up to 8 mode values: Scroll-left(0) -right(1) -up(2)
-down(3); still-centered(4); animation(5); drop-
down(6); curtain(7); laser(8); See '--mode-help' for
more details.
Scroll speed (Range 1..8). Up to 8 comma-separated values
-B BRIGHTNESS, --brightness BRIGHTNESS
Brightness for the display in percent: 25, 50, 75, or 100
-m MODE, --mode MODE Up to 8 mode values: Scroll-left(0) -right(1) -up(2) -down(3); still-centered(4); animation(5); drop-down(6); curtain(7);
laser(8); See '--mode-help' for more details.
-b BLINK, --blink BLINK
1: blinking, 0: normal. Up to 8 comma-seperated values
-a ANTS, --ants ANTS 1: animated border, 0: normal. Up to 8 comma-seperated
values
1: blinking, 0: normal. Up to 8 comma-separated values
-a ANTS, --ants ANTS 1: animated border, 0: normal. Up to 8 comma-separated values
-l, --list-names list named icons to be embedded in messages and exit
Example combining image and text:

@ -52,9 +52,12 @@
import sys, os, re, time, argparse
from datetime import datetime
from array import array
try:
if sys.version_info[0] < 3: raise Exception("prefer usb.core with python-2.x because of https://github.com/jnweiger/led-badge-ls32/issues/9")
if sys.version_info[0] < 3: raise Exception(
"prefer usb.core with python-2.x because of https://github.com/jnweiger/led-badge-ls32/issues/9")
import pyhidapi
pyhidapi.hid_init()
have_pyhidapi = True
except:
@ -80,7 +83,6 @@ or
print("""Please with Linux or MacOS or help us implement support for """ + sys.platform)
sys.exit(1)
__version = "0.12"
font_11x44 = (
@ -201,21 +203,56 @@ font_11x44 = (
0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x00, 0x3c, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x6c, 0x60,
# "àäòöùüèéêëôöûîïÿç"
0x00, 0x60, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x60, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x00, 0x60, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x60, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00,
0x00, 0x18, 0x60, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00,
0x00, 0x10, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00,
0x00, 0x10, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x00, 0x10, 0x6c, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x10, 0x6c, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8,
0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x10, 0x30,
# "ÀÅÄÉÈÊËÖÔÜÛÙŸ"
0x60, 0x18, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
0x10, 0x6c, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
0x6c, 0x6c, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
0x18, 0x60, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00,
0x60, 0x18, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00,
0x10, 0x6c, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00,
0x6c, 0x6c, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00,
0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, # Ö
0x10, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, # Ô
0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, # Ü
0x10, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, # Û
0x60, 0x18, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, # Ù
0x66, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00, # Ÿ
)
charmap = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + \
u'abcdefghijklmnopqrstuvwxyz' + \
u'0987654321^ !"\0$%&/()=?` °\\}][{' + \
u"@ ~ |<>,;.:-_#'+* " + \
u"äöüÄÖÜß"
u"äöüÄÖÜß" + \
u"àäòöùüèéêëôöûîïÿç" + \
u"ÀÅÄÉÈÊËÖÔÜÛÙŸ"
char_offset = {}
for i in range(len(charmap)):
char_offset[charmap[i]] = 11 * i
# print(i, charmap[i], char_offset[charmap[i]])
bitmap_preloaded = [ ([],0) ]
bitmap_preloaded = [([], 0)]
bitmaps_preloaded_unused = False
bitmap_named = {
@ -258,7 +295,7 @@ bitmap_named = {
'bicycle': (array('B', (0x01, 0x02, 0x00, 0x01, 0x07, 0x09, 0x12, 0x12, 0x10, 0x08, 0x07,
0x00, 0x87, 0x81, 0x5f, 0x22, 0x94, 0x49, 0x5f, 0x49, 0x80, 0x00,
0x00, 0x80, 0x00, 0x80, 0x70, 0xc8, 0x24, 0xe4, 0x04, 0x88, 0x70)), 3, '\x16'),
'bicycle_r':(array('B', (0x00, 0x00, 0x00, 0x00, 0x07, 0x09, 0x12, 0x13, 0x10, 0x08, 0x07,
'bicycle_r': (array('B', (0x00, 0x00, 0x00, 0x00, 0x07, 0x09, 0x12, 0x13, 0x10, 0x08, 0x07,
0x00, 0xf0, 0x40, 0xfd, 0x22, 0x94, 0x49, 0xfd, 0x49, 0x80, 0x00,
0x40, 0xa0, 0x80, 0x40, 0x70, 0xc8, 0x24, 0x24, 0x04, 0x88, 0x70)), 3, '\x15'),
'owncloud': (array('B', (0x00, 0x01, 0x02, 0x03, 0x06, 0x0c, 0x1a, 0x13, 0x11, 0x19, 0x0f,
@ -284,7 +321,7 @@ def bitmap_char(ch):
return bitmap_preloaded[ord(ch)]
o = char_offset[ch]
return (font_11x44[o:o+11],1)
return (font_11x44[o:o + 11], 1)
def bitmap_text(text):
@ -296,6 +333,7 @@ def bitmap_text(text):
":heart:" is replaced with a reference to a builtin heart glyph
":gfx/logo.png:" preloads the file gfx/logo.png and is replaced the corresponding control char.
"""
def colonrepl(m):
name = m.group(1)
if name == '':
@ -304,7 +342,7 @@ def bitmap_text(text):
return chr(int(name))
if '.' in name:
bitmap_preloaded.append(bitmap_img(name))
return chr(len(bitmap_preloaded)-1)
return chr(len(bitmap_preloaded) - 1)
b = bitmap_named[name]
return b[2]
@ -312,7 +350,7 @@ def bitmap_text(text):
buf = array('B')
cols = 0
for c in text:
(b,n) = bitmap_char(c)
(b, n) = bitmap_char(c)
buf.extend(b)
cols += n
return (buf, cols)
@ -328,15 +366,15 @@ def bitmap_img(file):
if im.height != 11:
sys.exit("%s: image height must be 11px. Seen %d" % (file, im.height))
buf = array('B')
cols = int((im.width+7)/8)
cols = int((im.width + 7) / 8)
for col in range(cols):
for row in range(11): # [0..10]
byte_val = 0
for bit in range(8): # [0..7]
bit_val = 0
x = 8*col+bit
x = 8 * col + bit
if x < im.width and row < im.height:
pixel_color = im.getpixel( (x, row) )
pixel_color = im.getpixel((x, row))
if isinstance(pixel_color, tuple):
monochrome_color = sum(pixel_color[:3]) / len(pixel_color[:3])
elif isinstance(pixel_color, int):
@ -344,7 +382,7 @@ def bitmap_img(file):
else:
sys.exit("%s: Unknown pixel format detected (%s)!" % (file, pixel_color))
if monochrome_color > 127:
bit_val = 1 << (7-bit)
bit_val = 1 << (7 - bit)
byte_val += bit_val
buf.append(byte_val)
im.close()
@ -374,16 +412,16 @@ def header(lengths, speeds, modes, blink, ants, brightness=100):
Speeds come in as 1..8, but are needed 0..7 here.
"""
a = [int(x) for x in re.split(r'[\s,]+', ants)]
a = a + [a[-1]]*(8-len(a)) # repeat last element
a = a + [a[-1]] * (8 - len(a)) # repeat last element
b = [int(x) for x in re.split(r'[\s,]+', blink)]
b = b + [b[-1]]*(8-len(b)) # repeat last element
b = b + [b[-1]] * (8 - len(b)) # repeat last element
s = [int(x)-1 for x in re.split(r'[\s,]+', speeds)]
s = s + [s[-1]]*(8-len(s)) # repeat last element
s = [int(x) - 1 for x in re.split(r'[\s,]+', speeds)]
s = s + [s[-1]] * (8 - len(s)) # repeat last element
m = [int(x) for x in re.split(r'[\s,]+', modes)]
m = m + [m[-1]]*(8-len(m)) # repeat last element
m = m + [m[-1]] * (8 - len(m)) # repeat last element
h = list(proto_header)
@ -395,38 +433,45 @@ def header(lengths, speeds, modes, blink, ants, brightness=100):
h[5] = 0x10
for i in range(8):
h[6] += b[i]<<i
h[7] += a[i]<<i
h[6] += b[i] << i
h[7] += a[i] << i
for i in range(8):
h[8+i] = 16*s[i] + m[i]
h[8 + i] = 16 * s[i] + m[i]
for i in range(len(lengths)):
h[17+(2*i)-1] = lengths[i] // 256
h[17+(2*i)] = lengths[i] % 256
h[17 + (2 * i) - 1] = lengths[i] // 256
h[17 + (2 * i)] = lengths[i] % 256
cdate = datetime.now()
h[38+0] = cdate.year % 100
h[38+1] = cdate.month
h[38+2] = cdate.day
h[38+3] = cdate.hour
h[38+4] = cdate.minute
h[38+5] = cdate.second
h[38 + 0] = cdate.year % 100
h[38 + 1] = cdate.month
h[38 + 2] = cdate.day
h[38 + 3] = cdate.hour
h[38 + 4] = cdate.minute
h[38 + 5] = cdate.second
return h
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, description='Upload messages or graphics to a 11x44 led badge via USB HID.\nVersion %s from https://github.com/jnweiger/led-badge-ls32\n -- see there for more examples and for updates.' % __version, epilog='Example combining image and text:\n sudo %s "I:HEART2:you"' % sys.argv[0])
parser.add_argument('-t', '--type', default='11x44', help="Type of display: supported values are 12x48 or (default) 11x44. Rename the program to led-badge-12x48, to switch the default.")
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
description='Upload messages or graphics to a 11x44 led badge via USB HID.\nVersion %s from https://github.com/jnweiger/led-badge-ls32\n -- see there for more examples and for updates.' % __version,
epilog='Example combining image and text:\n sudo %s "I:HEART2:you"' % sys.argv[0])
parser.add_argument('-t', '--type', default='11x44',
help="Type of display: supported values are 12x48 or (default) 11x44. Rename the program to led-badge-12x48, to switch the default.")
parser.add_argument('-s', '--speed', default='4', help="Scroll speed (Range 1..8). Up to 8 comma-separated values")
parser.add_argument('-B', '--brightness', default='100', help="Brightness for the display in percent: 25, 50, 75, or 100")
parser.add_argument('-m', '--mode', default='0', help="Up to 8 mode values: Scroll-left(0) -right(1) -up(2) -down(3); still-centered(4); animation(5); drop-down(6); curtain(7); laser(8); See '--mode-help' for more details.")
parser.add_argument('-B', '--brightness', default='100',
help="Brightness for the display in percent: 25, 50, 75, or 100")
parser.add_argument('-m', '--mode', default='0',
help="Up to 8 mode values: Scroll-left(0) -right(1) -up(2) -down(3); still-centered(4); animation(5); drop-down(6); curtain(7); laser(8); See '--mode-help' for more details.")
parser.add_argument('-b', '--blink', default='0', help="1: blinking, 0: normal. Up to 8 comma-separated values")
parser.add_argument('-a', '--ants', default='0', help="1: animated border, 0: normal. Up to 8 comma-separated values")
parser.add_argument('-p', '--preload', metavar='FILE', action='append', help=argparse.SUPPRESS) # "Load bitmap images. Use ^A, ^B, ^C, ... in text messages to make them visible. Deprecated, embed within ':' instead")
parser.add_argument('-l', '--list-names', action='version', help="list named icons to be embedded in messages and exit", version=':'+': :'.join(bitmap_named.keys())+': :: or e.g. :path/to/some_icon.png:')
parser.add_argument('message', metavar='MESSAGE', nargs='+', help="Up to 8 message texts with embedded builtin icons or loaded images within colons(:) -- See -l for a list of builtins")
parser.add_argument('-p', '--preload', metavar='FILE', action='append',
help=argparse.SUPPRESS) # "Load bitmap images. Use ^A, ^B, ^C, ... in text messages to make them visible. Deprecated, embed within ':' instead")
parser.add_argument('-l', '--list-names', action='version', help="list named icons to be embedded in messages and exit",
version=':' + ': :'.join(bitmap_named.keys()) + ': :: or e.g. :path/to/some_icon.png:')
parser.add_argument('message', metavar='MESSAGE', nargs='+',
help="Up to 8 message texts with embedded builtin icons or loaded images within colons(:) -- See -l for a list of builtins")
parser.add_argument('--mode-help', action='version', help=argparse.SUPPRESS, version="""
-m 5 "Animation"
@ -451,14 +496,15 @@ parser.add_argument('--mode-help', action='version', help=argparse.SUPPRESS, ver
args = parser.parse_args()
if have_pyhidapi:
devinfo = pyhidapi.hid_enumerate(0x0416, 0x5020)
#dev = pyhidapi.hid_open(0x0416, 0x5020)
# dev = pyhidapi.hid_open(0x0416, 0x5020)
else:
dev = usb.core.find(idVendor=0x0416, idProduct=0x5020)
if have_pyhidapi:
if devinfo:
dev = pyhidapi.hid_open_path(devinfo[0].path)
print("using [%s %s] int=%d page=%s via pyHIDAPI" % (devinfo[0].manufacturer_string, devinfo[0].product_string, devinfo[0].interface_number, devinfo[0].usage_page))
print("using [%s %s] int=%d page=%s via pyHIDAPI" % (
devinfo[0].manufacturer_string, devinfo[0].product_string, devinfo[0].interface_number, devinfo[0].usage_page))
else:
print("No led tag with vendorID 0x0416 and productID 0x5020 found.")
print("Connect the led tag and run this tool as root.")
@ -487,15 +533,16 @@ for arg in args.message:
msgs.append(bitmap(arg))
if bitmaps_preloaded_unused == True:
print("\nWARNING:\n Your preloaded images are not used.\n Try without '-p' or embed the control character '^A' in your message.\n")
print(
"\nWARNING:\n Your preloaded images are not used.\n Try without '-p' or embed the control character '^A' in your message.\n")
if '12' in args.type or '12' in sys.argv[0]:
print("Type: 12x48")
for msg in msgs:
# trivial hack to support 12x48 badges:
# patch extra empty lines into the message stream.
for o in reversed(range(1, int(len(msg[0])/11)+1)):
msg[0][o*11:o*11] = array('B', [0])
for o in reversed(range(1, int(len(msg[0]) / 11) + 1)):
msg[0][o * 11:o * 11] = array('B', [0])
else:
print("Type: 11x44")
@ -505,22 +552,22 @@ buf.extend(header(list(map(lambda x: x[1], msgs)), args.speed, args.mode, args.b
for msg in msgs:
buf.extend(msg[0])
needpadding = len(buf)%64
needpadding = len(buf) % 64
if needpadding:
buf.extend( (0,) * (64-needpadding) )
buf.extend((0,) * (64 - needpadding))
# print(buf) # array('B', [119, 97, 110, 103, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 126, 255, 255, 255, 255, 126, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
if len(buf) > 8192:
print ("Writing more than 8192 bytes damages the display!")
print("Writing more than 8192 bytes damages the display!")
sys.exit(1)
if have_pyhidapi:
pyhidapi.hid_write(dev, buf)
else:
for i in range(int(len(buf)/64)):
for i in range(int(len(buf) / 64)):
time.sleep(0.1)
dev.write(1, buf[i*64:i*64+64])
dev.write(1, buf[i * 64:i * 64 + 64])
if have_pyhidapi:
pyhidapi.hid_close(dev)

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

Loading…
Cancel
Save