PyPortal Pynt User Interface example
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- oldblackcrow
- Posts: 221
- Joined: Tue Jun 20, 2017 5:54 pm
Re: PyPortal Pynt User Interface example
Thanks! I'll look through that tomorrow evening. I appreciate your help!
- oldblackcrow
- Posts: 221
- Joined: Tue Jun 20, 2017 5:54 pm
Re: PyPortal Pynt User Interface example
Well, I've temporarily gave up on the AdafruitIO HTTP example to try the MQTT "Make it your own" at the end of PyPortal UI example.
First, I'm not quite sure what the difference is (aside from the coding statements), as there is no good documentation on the Adafruit site to explain.
Second, when I pasted the code from the website (https://learn.adafruit.com/making-a-pyp ... t-your-own), I have to change the "username" and "password" to "aio_username" and "aio_key" respectively. According to other sources, I gather that the broker is one of the following:
1. https://io.adafruit.com/oldblackcrow/feeds/photocell
2. https://io.adafruit.com/oldblackcrow/da ... light-test
3. https://io.adafruit.com/oldblackcrow/feeds/onoff
I've changed the broker to each of these with the *same* following error:
code.py output:
No SD card found: no SD card
Connecting to WiFi...
Connecting to AP Computer
Connected!
Traceback (most recent call last):
File "code.py", line 71, in <module>
File "adafruit_minimqtt/adafruit_minimqtt.py", line 316, in connect
File "adafruit_minimqtt/adafruit_minimqtt.py", line 316, in connect
MMQTTException: ('Invalid broker address defined.', RuntimeError('Failed to request hostname',))
Code done running.
I've read through the pages, but find nothing that addresses this... of course, I may be missing something.
Any ideas? Thanks!
First, I'm not quite sure what the difference is (aside from the coding statements), as there is no good documentation on the Adafruit site to explain.
Second, when I pasted the code from the website (https://learn.adafruit.com/making-a-pyp ... t-your-own), I have to change the "username" and "password" to "aio_username" and "aio_key" respectively. According to other sources, I gather that the broker is one of the following:
1. https://io.adafruit.com/oldblackcrow/feeds/photocell
2. https://io.adafruit.com/oldblackcrow/da ... light-test
3. https://io.adafruit.com/oldblackcrow/feeds/onoff
I've changed the broker to each of these with the *same* following error:
code.py output:
No SD card found: no SD card
Connecting to WiFi...
Connecting to AP Computer
Connected!
Traceback (most recent call last):
File "code.py", line 71, in <module>
File "adafruit_minimqtt/adafruit_minimqtt.py", line 316, in connect
File "adafruit_minimqtt/adafruit_minimqtt.py", line 316, in connect
MMQTTException: ('Invalid broker address defined.', RuntimeError('Failed to request hostname',))
Code done running.
I've read through the pages, but find nothing that addresses this... of course, I may be missing something.
Any ideas? Thanks!
- oldblackcrow
- Posts: 221
- Joined: Tue Jun 20, 2017 5:54 pm
Re: PyPortal Pynt User Interface example
Hey guys, I'm back with this next issue. It took a while to get the PyPortal to connect using MQTT, but y'all finally got me connected (viewtopic.php?f=56&t=177198&start=15). Thank you!
However, now I'm integrating that into the UI example (https://learn.adafruit.com/making-a-pyp ... -full-code)
Here is the MQTT example that @brubell supplied but I just modified to slim it down and only have it pull and print from my feed:
I'm getting the following error:
code.py output:
Connecting to WiFi...
Connected!
Connecting to AIO...
Connected to AIO oldblackcrow/feeds/rx
Traceback (most recent call last):
File "code.py", line 107, in <module>
File "adafruit_pyportal/__init__.py", line 139, in __init__
ValueError: SCK in use
Code done running.
Press any key to enter the REPL. Use CTRL-D to reload.
So, @brubell said, "Could you try this - it doesn't rely on the PyPortal class at all..." with the above code, it's running into that error because line 107 calls for PyPortal. Is there any way around this? I'm soooooo close to finishing this and this is the only thing holding me back. Thanks so much!
However, now I'm integrating that into the UI example (https://learn.adafruit.com/making-a-pyp ... -full-code)
Here is the MQTT example that @brubell supplied but I just modified to slim it down and only have it pull and print from my feed:
Code: Select all
import time
import board
import microcontroller
import displayio
import busio
from digitalio import DigitalInOut
import neopixel
from adafruit_esp32spi import adafruit_esp32spi
from adafruit_esp32spi import adafruit_esp32spi_wifimanager
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
import adafruit_minimqtt.adafruit_minimqtt as MQTT
from analogio import AnalogIn
import neopixel
import adafruit_adt7410
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text.label import Label
from adafruit_button import Button
import adafruit_touchscreen
from adafruit_pyportal import PyPortal
from secrets import secrets
# ------------- Inputs and Outputs Setup ------------- #
try: # attempt to init. the temperature sensor
i2c_bus = busio.I2C(board.SCL, board.SDA)
adt = adafruit_adt7410.ADT7410(i2c_bus, address=0x48)
adt.high_resolution = True
except ValueError:
# Did not find ADT7410. Probably running on Titano or Pynt
adt = None
# WIFI - If you are using a board with pre-defined ESP32 Pins:
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets)
# Setup a feed named 'gas_sensor' for subscribing to changes
gas_sensor = secrets["aio_username"] + "/feeds/rx"
def connected(client, userdata, flags, rc):
# This function will be called when the client is connected successfully to the broker.
print("Connected to AIO %s" % gas_sensor)
# Subscribe to all changes on the gas_sensor.
client.subscribe(gas_sensor)
def disconnected(client, userdata, rc):
# This method is called when the client is disconnected
print("Disconnected from AIO!")
def message(client, topic, message):
# This method is called when a topic the client is subscribed to has a new message.
print("Gas Sensor Readings {0}: {1}".format(topic, message))
# Connect to WiFi
print("Connecting to WiFi...")
wifi.connect()
print("Connected!")
# Initialize MQTT interface with the esp interface
MQTT.set_socket(socket, esp)
# Set up a MiniMQTT Client
mqtt_client = MQTT.MQTT(
broker="io.adafruit.com",
username=secrets["aio_username"],
password=secrets["aio_key"],
)
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = message
# Connect the client to the MQTT broker.
print("Connecting to AIO...")
mqtt_client.connect()
# init. the light sensor
light_sensor = AnalogIn(board.LIGHT)
pixel_pin = board.D3
num_pixels = 1
ORDER = neopixel.RGB
pixels = neopixel.NeoPixel(
pixel_pin, num_pixels, brightness=1.0, auto_write=True, pixel_order=ORDER
)
# ---------- Sound Effects ------------- #
soundDemo = '/sounds/sound.wav'
soundBeep = '/sounds/beep.wav'
soundTab = '/sounds/tab.wav'
# ------------- Other Helper Functions------------- #
# Helper for cycling through a number set of 1 to x.
def numberUP(num, max_val):
num += 1
if num <= max_val:
return num
else:
return 1
# ------------- Screen Setup ------------- #
pyportal = PyPortal()
display = board.DISPLAY
display.rotation = 0
# Backlight function
# Value between 0 and 1 where 0 is OFF, 0.5 is 50% and 1 is 100% brightness.
def set_backlight(val):
val = max(0, min(1.0, val))
board.DISPLAY.auto_brightness = False
board.DISPLAY.brightness = val
# Set the Backlight
set_backlight(0.5)
# Touchscreen setup
# ------Rotate 0:
screen_width = 320
screen_height = 240
ts = adafruit_touchscreen.Touchscreen(board.TOUCH_XL, board.TOUCH_XR,
board.TOUCH_YD, board.TOUCH_YU,
calibration=((5200, 59000), (5800, 57000)),
size=(320, 240))
# ------------- Display Groups ------------- #
splash = displayio.Group(max_size=15) # The Main Display Group
view1 = displayio.Group(max_size=15) # Group for View 1 objects
view2 = displayio.Group(max_size=15) # Group for View 2 objects
view3 = displayio.Group(max_size=15) # Group for View 3 objects
def hideLayer(hide_target):
try:
splash.remove(hide_target)
except ValueError:
pass
def showLayer(show_target):
try:
time.sleep(0.1)
splash.append(show_target)
except ValueError:
pass
# ------------- Setup for Images ------------- #
# Display an image until the loop starts
pyportal.set_background('/images/loading.bmp')
bg_group = displayio.Group(max_size=1)
splash.append(bg_group)
icon_group = displayio.Group(max_size=1)
icon_group.x = 15
icon_group.y = 35
icon_group.scale = 1
view2.append(icon_group)
# This will handel switching Images and Icons
def set_image(group, filename):
"""Set the image file for a given goup for display.
This is most useful for Icons or image slideshows.
:param group: The chosen group
:param filename: The filename of the chosen image
"""
print("Set image to ", filename)
if group:
group.pop()
if not filename:
return # we're done, no icon desired
image_file = open(filename, "rb")
image = displayio.OnDiskBitmap(image_file)
try:
image_sprite = displayio.TileGrid(image, pixel_shader=displayio.ColorConverter())
except TypeError:
image_sprite = displayio.TileGrid(image, pixel_shader=displayio.ColorConverter(),
position=(0, 0))
group.append(image_sprite)
set_image(bg_group, "/images/BGimage.bmp")
# ---------- Text Boxes ------------- #
# Set the font and preload letters
font1 = bitmap_font.load_font("/fonts/Federation-22.bdf")
font = bitmap_font.load_font("/fonts/StarFleet-24.bdf")
font.load_glyphs(b'abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890- ()')
# Default Label styling:
TABS_X = 5
TABS_Y = 50
# Text Label Objects
feed1_label = Label(font1, text="Text Wondow 1", color=0xE39300, max_glyphs=200)
feed1_label.x = TABS_X+20
feed1_label.y = TABS_Y
view1.append(feed1_label)
feed2_label = Label(font1, text="Text Wondow 2", color=0xFFFFFF, max_glyphs=200)
feed2_label.x = TABS_X
feed2_label.y = TABS_Y
#view2.append(feed2_label)
sensors_label = Label(font1, text="Data View", color=0x03AD31, max_glyphs=200)
sensors_label.x = TABS_X+20
sensors_label.y = TABS_Y
view3.append(sensors_label)
sensor_data = Label(font1, text="Data View", color=0x03AD31, max_glyphs=100)
sensor_data.x = TABS_X+15
sensor_data.y = 65
view3.append(sensor_data)
text_hight = Label(font, text="M", color=0x03AD31, max_glyphs=10)
# return a reformatted string with word wrapping using PyPortal.wrap_nicely
def text_box(target, top, string, max_chars):
text = pyportal.wrap_nicely(string, max_chars)
new_text = ""
test = ""
for w in text:
new_text += '\n'+w
test += 'M\n'
text_hight.text = test # Odd things happen without this
glyph_box = text_hight.bounding_box
target.text = "" # Odd things happen without this
target.y = int(glyph_box[3]/2)+top
target.text = new_text
# ---------- Display Buttons ------------- #
# Default button styling:
BUTTON_HEIGHT = 40
BUTTON_WIDTH = 80
# We want three buttons across the top of the screen
TAPS_HEIGHT = 40
TAPS_WIDTH = int(screen_width/3)
TAPS_Y = 0
# We want two big buttons at the bottom of the screen
BIG_BUTTON_HEIGHT = int(screen_height/3.2)
BIG_BUTTON_WIDTH = int(screen_width/2)
BIG_BUTTON_Y = int(screen_height-BIG_BUTTON_HEIGHT)
# This group will make it easy for us to read a button press later.
buttons = []
# Main User Interface Buttons
button_view1 = Button(x=0, y=0,
width=TAPS_WIDTH, height=TAPS_HEIGHT,
label="HANDHELD", label_font=font, label_color=0xff7e00,
fill_color=0x5c5b5c, outline_color=0x767676,
selected_fill=0x1a1a1a, selected_outline=0x2e2e2e,
selected_label=0x525252)
pixels.fill((0, 255, 0))
buttons.append(button_view1) # adding this button to the buttons group
button_view2 = Button(x=TAPS_WIDTH, y=0,
width=TAPS_WIDTH, height=TAPS_HEIGHT,
label="SUBSPACE", label_font=font, label_color=0xff7e00,
fill_color=0x5c5b5c, outline_color=0x767676,
selected_fill=0x1a1a1a, selected_outline=0x2e2e2e,
selected_label=0x525252)
buttons.append(button_view2) # adding this button to the buttons group
button_view3 = Button(x=TAPS_WIDTH*2, y=0,
width=TAPS_WIDTH, height=TAPS_HEIGHT,
label="SENSORS", label_font=font, label_color=0xff7e00,
fill_color=0x5c5b5c, outline_color=0x767676,
selected_fill=0x1a1a1a, selected_outline=0x2e2e2e,
selected_label=0x525252)
buttons.append(button_view3) # adding this button to the buttons group
button_switch = Button(x=0, y=BIG_BUTTON_Y,
width=BIG_BUTTON_WIDTH, height=BIG_BUTTON_HEIGHT,
label="Switch", label_font=font, label_color=0xff7e00,
fill_color=0x5c5b5c, outline_color=0x767676,
selected_fill=0x1a1a1a, selected_outline=0x2e2e2e,
selected_label=0x525252)
#buttons.append(button_switch) # adding this button to the buttons group
button_2 = Button(x=BIG_BUTTON_WIDTH, y=BIG_BUTTON_Y,
width=BIG_BUTTON_WIDTH, height=BIG_BUTTON_HEIGHT,
label="Button", label_font=font, label_color=0xff7e00,
fill_color=0x5c5b5c, outline_color=0x767676,
selected_fill=0x1a1a1a, selected_outline=0x2e2e2e,
selected_label=0x525252)
#buttons.append(button_2) # adding this button to the buttons group
# Add all of the main buttons to the splash Group
for b in buttons:
splash.append(b)
# Make a button to change the icon image on view2
button_icon = Button(x=150, y=60,
width=BUTTON_WIDTH, height=BUTTON_HEIGHT,
label="Icon", label_font=font, label_color=0xffffff,
fill_color=0x8900ff, outline_color=0xbc55fd,
selected_fill=0x5a5a5a, selected_outline=0xff6600,
selected_label=0x525252, style=Button.ROUNDRECT)
#buttons.append(button_icon) # adding this button to the buttons group
# Add this button to view2 Group
#view2.append(button_icon)
# Make a button to play a sound on view2
button_sound = Button(x=150, y=170,
width=BUTTON_WIDTH, height=BUTTON_HEIGHT,
label="Sound", label_font=font, label_color=0xffffff,
fill_color=0x8900ff, outline_color=0xbc55fd,
selected_fill=0x5a5a5a, selected_outline=0xff6600,
selected_label=0x525252, style=Button.ROUNDRECT)
#buttons.append(button_sound) # adding this button to the buttons group
# Add this button to view2 Group
#view3.append(button_sound)
#pylint: disable=global-statement
def switch_view(what_view):
global view_live
if what_view == 1:
hideLayer(view2)
hideLayer(view3)
button_view1.selected = False
button_view2.selected = True
button_view3.selected = True
showLayer(view1)
view_live = 1
print("View1 On")
elif what_view == 2:
# global icon
hideLayer(view1)
hideLayer(view3)
button_view1.selected = True
button_view2.selected = False
button_view3.selected = True
showLayer(view2)
view_live = 2
print("View2 On")
else:
hideLayer(view1)
hideLayer(view2)
button_view1.selected = True
button_view2.selected = True
button_view3.selected = False
showLayer(view3)
view_live = 3
print("View3 On")
#pylint: enable=global-statement
# Set veriables and startup states
button_view1.selected = False
button_view2.selected = True
button_view3.selected = True
showLayer(view1)
hideLayer(view2)
hideLayer(view3)
view_live = 1
icon = 1
icon_name = "Ruby"
button_mode = 1
switch_state = 0
button_switch.label = "OFF"
button_switch.selected = True
# Update out Labels with display text.
text_box(feed1_label, TABS_Y,
"Data provided by AdafuitIO", 30)
text_box(feed1_label, TABS_Y,
'Handheld GAS Sensor Data.'
.format(feed1_label.bounding_box[2], feed1_label.bounding_box[2]*2), 15)
text_box(feed2_label, TABS_Y, 'SubSpace Data', 18)
text_box(sensors_label, TABS_Y-20,
"", 28)
board.DISPLAY.show(splash)
# ------------- Code Loop ------------- #
while True:
mqtt_client.loop()
time.sleep(2)
touch = ts.touch_point
light = light_sensor.value
if adt: # Only if we have the temperature sensor
tempC = adt.temperature
else: # No temperature sensor
tempC = microcontroller.cpu.temperature
tempK = tempC + 273.15
sensor_data.text = 'PHOTONS\n{}\n\nSYSTEM TEMP\n{}°K'.format(light, tempK)
# ------------- Handle Button Press Detection ------------- #
if touch: # Only do this if the screen is touched
# loop with buttons using enumerate() to number each button group as i
for i, b in enumerate(buttons):
if b.contains(touch): # Test each button to see if it was pressed
print('button%d pressed' % i)
if i == 0 and view_live != 1: # only if view1 is visable
pyportal.play_file(soundTab)
switch_view(1)
pixels.fill((0, 255, 0))
while ts.touch_point:
pass
if i == 1 and view_live != 2: # only if view2 is visable
pyportal.play_file(soundTab)
switch_view(2)
set_image(icon_group,"/images/Sensor-graphic-subspace.bmp")
pixels.fill((255, 0, 0))
while ts.touch_point:
pass
if i == 2 and view_live != 3: # only if view3 is visable
pyportal.play_file(soundTab)
switch_view(3)
pixels.fill((0, 0, 255))
while ts.touch_point:
pass
if i == 3:
pyportal.play_file(soundBeep)
# Toggle switch button type
if switch_state == 0:
switch_state = 1
b.label = "ON"
b.selected = False
pixel.fill(BLACK)
print("Swich ON")
else:
switch_state = 0
b.label = "OFF"
b.selected = True
pixel.fill(BLACK)
print("Swich OFF")
# for debounce
while ts.touch_point:
pass
print("Swich Pressed")
if i == 4:
pyportal.play_file(soundBeep)
# Momentary button type
b.selected = True
print('Button Pressed')
button_mode = numberUP(button_mode, 5)
if button_mode == 1:
pixel.fill(RED)
elif button_mode == 2:
pixel.fill(RED)
elif button_mode == 3:
pixel.fill(RED)
elif button_mode == 4:
pixel.fill(BLUE)
elif button_mode == 5:
pixel.fill(PURPLE)
switch_state = 1
button_switch.label = "ON"
button_switch.selected = False
# for debounce
while ts.touch_point:
pass
print("Button released")
b.selected = False
if i == 5 and view_live == 2: # only if view2 is visable
pyportal.play_file(soundBeep)
b.selected = True
while ts.touch_point:
pass
print("Icon Button Pressed")
icon = numberUP(icon, 3)
if icon == 1:
icon_name = "Ruby"
elif icon == 2:
icon_name = "Gus"
elif icon == 3:
icon_name = "Billie"
b.selected = False
text_box(feed2_label, TABS_Y,
"Every time you tap the Icon button the icon image will \
change. Say hi to {}!".format(icon_name), 18)
set_image(icon_group, "/images/"+icon_name+".bmp")
if i == 6 and view_live == 3: # only if view3 is visable
b.selected = True
while ts.touch_point:
pass
print("Sound Button Pressed")
pyportal.play_file(soundDemo)
b.selected = False
code.py output:
Connecting to WiFi...
Connected!
Connecting to AIO...
Connected to AIO oldblackcrow/feeds/rx
Traceback (most recent call last):
File "code.py", line 107, in <module>
File "adafruit_pyportal/__init__.py", line 139, in __init__
ValueError: SCK in use
Code done running.
Press any key to enter the REPL. Use CTRL-D to reload.
So, @brubell said, "Could you try this - it doesn't rely on the PyPortal class at all..." with the above code, it's running into that error because line 107 calls for PyPortal. Is there any way around this? I'm soooooo close to finishing this and this is the only thing holding me back. Thanks so much!
- oldblackcrow
- Posts: 221
- Joined: Tue Jun 20, 2017 5:54 pm
Re: PyPortal Pynt User Interface example
This issue has been solved! Thanks to @Neradoc#2644 on Discord for the following code: https://gist.github.com/Neradoc/0093bac ... 18e4950f1d
The modification is as such:
I'll post the entire UI code with the Garmin LIDAR and this modification tomorrow.
The modification is as such:
Code: Select all
import time
import random
from adafruit_pyportal import PyPortal
pyportal = PyPortal()
pyportal.network.connect()
key = "rx"
latest_id = "rx"
while True:
feed = pyportal.get_io_feed(key)
client = pyportal.network._get_io_client()
last = client.receive_data(key)
the_id = last['id']
if the_id != latest_id:
print("New value:",last['value'])
latest_id = the_id
time.sleep(5)
I'll post the entire UI code with the Garmin LIDAR and this modification tomorrow.
Please be positive and constructive with your questions and comments.