GithubHelp home page GithubHelp logo

adafruit_circuitpython_magtag's Introduction

Introduction

Documentation Status Discord Build Status Code Style: Black

Helper library for the Adafruit MagTag.

Dependencies

This driver depends on:

Please ensure all dependencies are available on the CircuitPython filesystem. This is easily achieved by downloading the Adafruit library and driver bundle.

Usage Example

# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
import time
import terminalio
from adafruit_magtag.magtag import MagTag

magtag = MagTag()

magtag.add_text(
    text_font=terminalio.FONT,
    text_position=(
        50,
        (magtag.graphics.display.height // 2) - 1,
    ),
    text_scale=3,
)

magtag.set_text("Hello World")

buttons = magtag.peripherals.buttons
button_colors = ((255, 0, 0), (255, 150, 0), (0, 255, 255), (180, 0, 255))
button_tones = (1047, 1318, 1568, 2093)
timestamp = time.monotonic()

while True:
    for i, b in enumerate(buttons):
        if not b.value:
            print("Button %c pressed" % chr((ord("A") + i)))
            magtag.peripherals.neopixel_disable = False
            magtag.peripherals.neopixels.fill(button_colors[i])
            magtag.peripherals.play_tone(button_tones[i], 0.25)
            break
    else:
        magtag.peripherals.neopixel_disable = True
    time.sleep(0.01)

Documentation

API documentation for this library can be found on Read the Docs.

For information on building library documentation, please check out this guide.

Contributing

Contributions are welcome! Please read our Code of Conduct before contributing to help this project stay welcoming.

adafruit_circuitpython_magtag's People

Contributors

anecdata avatar benetherington avatar caternuson avatar dhalbert avatar evaherrada avatar foamyguy avatar kattni avatar ktibow avatar ladyada avatar makermelissa avatar nitz avatar rufusvs avatar slootsky avatar tannewt avatar tekktrik avatar unicycledumptruck avatar vptechops avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

adafruit_circuitpython_magtag's Issues

How to use without requiring Adafruit.io?

I'd like to use the MagTag library without it requiring connecting to Adafruit.io, but it currently seems hard-coded to get time from there, and errors with:

  File "adafruit_magtag/magtag.py", line 288, in get_local_time
  File "adafruit_magtag/network.py", line 173, in get_local_time
KeyError:

Our time service requires a login/password to rate-limit. Please register for a free adafruit.io account and place the user/key in your secrets file under 'aio_username' and 'aio_key'

play_tone function should not raise Value error on frequency of 0

Currently in the library, if a zero frequency is specified to play_tone, a ValueError is thrown. In most other similar implementations, a value of 0 simply represents silence, or rest, for the duration specified. There is no reason for this implementation to be different. Also, this change is not likely to affect any user's existing code.

Current Code:

def play_tone(frequency, duration):
        """..."""
        if frequency <= 0:
            raise ValueError("The frequency has to be greater than 0.")

Suggested change:

def play_tone(frequency, duration):
        """..."""
        if frequency < 0:
            raise ValueError("Negative frequencies are not allowed.")

Peripherals.py line 46 TypeError

Suddenly getting TypeError in Peripherals.py, line 46: 'function missing required positional argument #3' called from a standard example script.
Code_py

2021-07-30_adafruit_magtag_peripherals py_error
neopixel py_init

Library has a hard time handling empty JSON responses

After helping Anne with some code, I noticed that if the json response is [] (which is totally valid json), the library doesn't do a good job with handling this as it handles this as Falsy. Also, it could use better messages when an expected path isn't found.

tweak comments

update description of :param text_wrap and :param text_maxlen

adafruit_portalbase Dependency Error

Context

mag_tag_libs

Expected behavior

  1. MagTag displays quote message
  2. MagTag goes into "deep sleep" for an hour
  3. MagTag wakes up and refreshes quote message

Actual behavior

  1. MagTag displays quote message
  2. MagTag refreshes and display error message
    magtag_error

I believe I'm not missing any libraries and my code is correct, but I could be wrong. Any help would be appreciated.

EPaperDisplay object cannot assign attribute 'rotation'

Using the example code from this repo. I had been working on the weather tutorial on the Adafruit site, but wanted to eliminate potential sources of error.

Following in the lib folder: (from the 20201225 circuit python libraries)

Folders:

  • adafruit_bitmap_font
  • adafrui_display_text
  • adafruit_imageload
  • adafruit_io
  • adafruit_magtag
  • adafruit_portalbase

Files:

  • adafruit_fakerequests
  • adafruit_iniiqr
  • adafruit_requests
  • neopixel
  • simpleio

Whenever the code reloads, I get:
code.py output:
Traceback (most recent call last):
File "code.py", line 5, in
File "adafruit_magtag/magtag.py", line 84, in init
File "adafruit_magtag/graphics.py", line 57, in init
AttributeError: 'EPaperDisplay' object cannot assign attribute 'rotation'

Voltage values seem questionable

The documentation says that I can retrieve the current voltage from the battery with magtag.peripherals.battery. Retrieving that value gives something back that seems non-sensical to me. For example, my magtag currently says that the battery is returning 414729 volts.

Still drawing >50mA during time.sleep()

The plan was to have a new update downloaded every 60s and then put the MagTag to sleep saving battery, but I'm measuring a constant 50-100mA current draw even when doing nothing.

I think the WiFi radio is to blame, but I can't figure out how to turn off the WiFi during sleep. How do I do this?

Unable to play WAV file

Howdy! I am using this library to try to play a WAV file on the MagTag board using CircuitPython 6.1.0. I am trying to figure out what would need to be done to make this work.

The history of commits to peripherals.py has me somewhat confused. Initially there seemed to be a play_wav_file function available in a previous version of the library, which used audioio. However, audioio does not seem to be available for this board. Was this code ever used/tested or was it just wishful thinking on my part that I could use it? :-)

def play_wav_file(self, file_name, wait_to_finish=True):

I am having difficulty understanding what play_tone is actually doing. If I try to call simpleio.tone(board.SPEAKER, 300, 0.2) directly, no sound occurs (but there is no exception). However, once I create my own DigitalInOut for the board.SPEAKER pin and invoke simpleio.tone, I get the dreaded NameError: name 'AudioOut' is not defined error.

>>> from digitalio import DigitalInOut, Direction
>>> speaker = DigitalInOut(board.SPEAKER)
>>> speaker.direction = Direction.OUTPUT
>>> speaker.value = True
>>> simpleio.tone(board.SPEAKER, 300, 0.2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "simpleio.py", line 82, in tone
NameError: name 'AudioOut' is not defined

This is really confusing, since it only seems to occur once I set up DigitalInOut. And tones play fine if I use:

magtag.peripherals.play_tone(300, 0.1)

This suggests that the version of this library I have on my board (which came shipped with ADABOX 017) does not exactly match what I'm seeing in this repo. Any tips or suggestions on how to unlock the FULL AUDIO POTENTIAL of this amazing device? Thank you!

label does not wrap text when set_text rather than fetch()'d

text should be wrapped in this example ๐Ÿ‘

import time
import random
from adafruit_magtag.magtag import MagTag

# Set up where we'll be fetching data from
DATA_SOURCE = "https://www.reddit.com/r/Showerthoughts/top.json?limit=5"

magtag = MagTag()
magtag.network.connect()

# thought in bold text, with text wrapping
magtag.add_text(
    text_font="Arial-Bold-12.bdf",
    text_wrap=33,
    text_maxlen=160,
    text_position=(10, 10),
    text_anchor_point=(0, 0),
    line_spacing=0.75,
)


timestamp = None
while True:
    if not timestamp or (time.monotonic() - timestamp) > 5:  # once every 60 seconds...
        try:
            print("Reading data")
            response = magtag.network.requests.get(DATA_SOURCE)
            value = response.json()
            thoughts = value["data"]["dist"]
            print("Thoughts", thoughts)
            randthought = random.randint(0, thoughts-1)
            thought = value["data"]["children"][randthought]["data"]["title"]
            author = value["data"]["children"][randthought]["data"]["author"]
            print("Random thought from", author, ":", thought)
            magtag.set_text(thought)
        except (ValueError, RuntimeError) as e:
            print("Some error occured, retrying! -", e)
        timestamp = time.monotonic()

MagTag onboard NeoPixel brightness is not working

Attempting to set the brightness of the on-board NeoPixels using the MagTag NeoPixel object does not work. They are max brightness regardless of what the brightness is set to.

Tested setting the NeoPixel brightness using raw CircuitPython and the NeoPixel library, and it was successful (though there is a bug somewhere in which setting brightness = 0 makes them max brightness - looking into where to file that bug as well).

handle rotation in a more elegant way?

for now this works, if you set the rotation thru the magtag.display you need to recreate the magtag object... or maybe this is fine!

import time
import board
import terminalio
from adafruit_magtag.magtag import MagTag

board.DISPLAY.rotation = 270
magtag = MagTag()

magtag.add_text(
    text_font=terminalio.FONT,
    text_position=(
        magtag.graphics.display.width // 2,
        magtag.graphics.display.height // 2,
    ),
    text_anchor_point=(0.5, 0.5),
    text_scale=3,
)

if magtag.display.rotation in (90, 270):
    magtag.set_text("Hello World")
else:
    magtag.set_text("Hello\nWorld")
while True:
    pass

OSError: [Errno 5]

when trying to copy files on the my magtag it is showing as read only drive even after re-flashing the uf2

No way to specify whether a text should be updated by fetch or not

Ok, the issue is that when we add text with add_text, there isn't really a way to tell the fetch function to skip it if it's not meant to be updated with a value. This is kind of an oversight on my part and only occurs if the first label isn't meant to be updated. While this doesn't affect the majority of projects, it is something that should be fixed before too long. This likely affects the MatrixPortal library as well, so it will be better to address sooner than later.

Incorrect import causes MagTag to freeze

Hi, not sure if this is a CircuitPython bug or a library bug, but on my MagTag running CircuitPython 6.1.0beta2 the following line causes the MagTag to stop responding when I have it plugged into the computer.

The issue happens both in the REPL and in code.py. If I connect via minicom, then Ctrl+C to enter the REPL, then type:

from adafruit_magtag.magtag import Graphics

minicom stops responding, and shortly after the CIRCUITPY drive stops responding also. On one or two occasions I noticed that if I wait long enough (longer than half hour) minicom might start responding again, though, freezes instantly once I try to import it. That could only be a coincidence, however, as it usually just freezes and rarely returns unless I turn off the MagTag and turn it on again.

I am using the latest library on circuitpython from today.

how to set tone volume

The MagTag is great but the buzzer sound is very loud.
Is there an option to set the volume directly or make a change to one of the libraries?

Thanks for any advice.

MAGTAG NEOPIXEL fails with 7.0

With the current tip of main I get an error trying to use the magtag library
h was trying to run the "vaccine example" https://learn.adafruit.com/adafruit-magtag-covid-vaccination-percent-tracker/code-the-vaccination-tracker

Press any key to enter the REPL. Use CTRL-D to reload.

Adafruit CircuitPython 7.0.0-alpha.2-736-gb49ee62af on 2021-06-02; Adafruit MagTag with ESP32S2
>>> import vaccine
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "vaccine.py", line 9, in <module>
  File "adafruit_magtag/magtag.py", line 102, in __init__
  File "adafruit_magtag/peripherals.py", line 47, in __init__
ValueError: NEOPIXEL_POWER_INVERTED in use
>>> 

It runs fine on 6.3.0

Received AttributeError on DISPLAY with magtag_simpletest.py

This is the magtag that came with adabox017
It worked when I first plugged it in but I haven't been successful at loading any other program on it.
This is with the latest library:
adafruit-circuitpython-bundle-6.x-mpy-20210101.zip

code.py

SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries

SPDX-License-Identifier: Unlicense

import time
from adafruit_magtag.magtag import MagTag

magtag = MagTag()

magtag.add_text(
text_position=(
50,
(magtag.graphics.display.height // 2) - 1,
),
text_scale=3,
)

magtag.set_text("Hello World")

button_colors = ((255, 0, 0), (255, 150, 0), (0, 255, 255), (180, 0, 255))
button_tones = (1047, 1318, 1568, 2093)

while True:
for i, b in enumerate(magtag.peripherals.buttons):
if not b.value:
print("Button %c pressed" % chr((ord("A") + i)))
magtag.peripherals.neopixel_disable = False
magtag.peripherals.neopixels.fill(button_colors[i])
magtag.peripherals.play_tone(button_tones[i], 0.25)
break
else:
magtag.peripherals.neopixel_disable = True
time.sleep(0.01)

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Traceback (most recent call last):
File "code.py", line 7, in
File "adafruit_magtag/magtag.py", line 84, in init
File "adafruit_magtag/graphics.py", line 56, in init
AttributeError: 'module' object has no attribute 'DISPLAY'

Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 6.0.1 on 2020-12-28; Metro ESP32S2 with ESP32S2

import board
dir(board)
['class', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'D0', 'D1', 'D10', 'D11', 'D12', 'D13', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'DEBUG_RX', 'DEBUG_TX', 'I2C', 'MISO', 'MOSI', 'NEOPIXEL', 'RX', 'SCK', 'SCL', 'SDA', 'SPI', 'TX', 'UART']

Needs override for remove_all_text from parent portal base to avoid a refresh exception

Portalbase has a function to remove all text (remove_all_text) this calls self.set_text to clear the labels.
Since magtag overrides this call to add the option to do a refresh ( auto_refresh: bool = True ) it would be nice to have an override of this function that takes the auto_refresh parameter. If we have more than a couple of labels (text fields) it is likely we will get the Refresh too soon exception.
The code change should be relatively simple (same as parent just passing the extra parameter to set_text). I am unsure if this is part of the scope for this library. I could not find an easy way to remove all objects from the display (maybe I am missing something), but that may be a suitable workaround.
I have been using a work around for my code

def remove_all_text():
    for i in range(count_labels):
        magtag.set_text("", auto_refresh=False, index = i)

where count_labels is a simple counter that increments every time I call add_text. but in this case I don't get the benefit of deleting the _text list ( self._text = [] ).

Missing Type Annotations

There are missing type annotations for some functions in this library.

The typing module does not exist on CircuitPython devices so the import needs to be wrapped in try/except to catch the error for missing import. There is an example of how that is done here:

try:
    from typing import List, Tuple
except ImportError:
    pass

Once imported the typing annotations for the argument type(s), and return type(s) can be added to the function signature. Here is an example of a function that has had this done already:

def wrap_text_to_pixels(
    string: str, max_width: int, font=None, indent0: str = "", indent1: str = ""
) -> List[str]:

If you are new to Git or Github we have a guide about contributing to our projects here: https://learn.adafruit.com/contribute-to-circuitpython-with-git-and-github

There is also a guide that covers our CI utilities and how to run them locally to ensure they will pass in Github Actions here: https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/check-your-code In particular the pages: Sharing docs on ReadTheDocs and Check your code with pre-commit contain the tools to install and commands to run locally to run the checks.

If you are attempting to resolve this issue and need help, you can post a comment on this issue and tag both @FoamyGuy and @kattni or reach out to us on Discord: https://adafru.it/discord in the #circuitpython-dev channel.

The following locations are reported by mypy to be missing type annotations:

  • adafruit_magtag/network.py:50
  • adafruit_magtag/network.py:76
  • adafruit_magtag/magtag.py:64
  • adafruit_magtag/magtag.py:106
  • adafruit_magtag/magtag.py:122
  • adafruit_magtag/magtag.py:146
  • adafruit_magtag/magtag.py:161
  • adafruit_magtag/magtag.py:165
  • adafruit_magtag/peripherals.py:73
  • adafruit_magtag/peripherals.py:119
  • adafruit_magtag/peripherals.py:131
  • adafruit_magtag/graphics.py:52
  • adafruit_magtag/graphics.py:63
  • adafruit_magtag/graphics.py:75

Factor out some layers to separate libraries

As suggested by @tannewt, this will make maintaining PyPortal, MatrixPortal, MagTag, and Blinka_PyPortal libraries easier to maintain.

Notable ones include the FakeRequests, WiFi Module, and possibly Graphics libraries. With this layered approach, we can even do something similar to the PyPortal library.

EPaperDisplay object cannot assign attribute 'rotation'

# MagTag Hello World

import time
from adafruit_magtag.magtag import MagTag

magtag = MagTag()
magtag.add_text(
    text_position=(
        50,
        (magtag.graphics.display.height // 2) - 1,
    ),
    text_scale=3,
)
 
magtag.set_text("Hello World")

This gives me an AttributeError on line 57 in init from adafruit_magtag/graphics.py

Improve docs for using the Alarms when using MagTag library

Setting a PinAlarm does not work when using this MagTag library.

I am using circuitpython v6

This is due to peripherals.py initializing all of the button pins to be used by the *_pressed() methods.

When trying to set a PinAlarm I receive the following error:

Traceback (most recent call last):
  File "code.py", line 265, in <module>
ValueError: BUTTON_A in use

Magtag screen won't update

The magtag is stuck on the Digi-Key screen from the factory. Using the latest: adafruit-circuitpython-adafruit_magtag_2.9_grayscale-en_US-20201216-f2204d7.uf2 from S3, using https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/download/20201216/adafruit-circuitpython-bundle-6.x-mpy-20201216.zip bundle. Used esp-idf to write bootloader: https://learn.adafruit.com/adafruit-magtag/install-uf2-bootloader.

The following code:

import time
import displayio
time.sleep(2)
print('0')
time.sleep(2)
from adafruit_magtag.magtag import MagTag
time.sleep(2)
print("1")
magtag = MagTag()
time.sleep(2)
print("2")
magtag.add_text(
text_position=(
50,
(magtag.graphics.display.height // 2) - 1,
),
text_scale=3,
)
print("3")
try:
magtag.set_text("Hello World")
pass
except:
print("Really bad thing happened.")
print("4")

outputs:
0
1
2
3

It never outputs "4" or "Really bas thing happened."

#76 breaks status_neopixel using board.NEOPIXEL

The change for the neopixel power issue now prevents using board.NEOPIXEL for the network status_neopixel operand. I used the magtag library as magtag = Magtag(status_neopixel = board.NEOPIXEL). This will reproduce the issue.

I found that the initialization of Magtag() now initializes Network() before Peripherals(). When the status_neopixel operand is processed, Network() generates a new neopixel object using board.NEOPIXEL as neopixel.NeoPixel(status_neopixel, 1, brightness=0.2). Then, when Magtag() later initializes Peripherals(), Peripherals() attempts to create its neopixel object, board.NEOPIXEL is now in use.

I verified by creating a work around that moves init of Peripherals() before Network() and passing the self.peripherals.neopixels object to the Network() init. I also changed Network() to accept whatever status_NEOPIXEL parameter object that gets received and just uses that one instead of creating a new object. This works as intended.

url property returns json_path

Probably just a typo?

    @property
    def url(self):
        """
        Get or set the URL of your data source.
        """
        return self._json_path

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.