Raspberry Pi Pico - Micropython - Get/Set mode of IO-Pin - micropython

Is there a way to get/set the mode of a Pin object in MicroPython on the Raspberry Pi Pico?
The standard library has a Pin.mode() function, but it is not supported on the Pi Pico.
Is there a way to directly change/get the mode of a pin instance?
The only workaround for at least reading the pin mode I came up with is using a regular expression:
import re
from machine import Pin
def is_input(pin: Pin):
"""
Returns True, if the pin object's mode is set as INPUT, else False.
"""
return re.search(r'mode=(\w*)', str(pin)).group(1) == 'IN'
p = Pin(0, Pin.IN)
print(is_input(p)) #True
p = Pin(0, Pin.OUT)
print(is_input(p)) #False

I wrote a wrapper class to around the machine.Pin class which keeps track of the mode and pull setting and allows to change their values by re-initializing the underlying machine.Pin instance.
import machine.Pin
class Pin:
"""
Wrapper around machine.Pin which keeps track of mode and pull settings.
"""
def __init__(self, id, mode=machine.Pin.IN, pull=None, **kwargs):
"""
:param id: GPIO number of the Pin
:param mode: GPIO mode. Either machine.Pin.IN or machine.Pin.OUT; Defaults to machine.Pin.IN
:param pull: GPIO pu/pd. Either machine.Pin.PULL_UP, machine.Pin.PULL_DOWN, None; Default to None
:param kwargs: optional kw-only arguments for machine.Pin constructor
"""
self._mode = mode
self._pull = pull
self._id = id
self._pin = machine.Pin(id, mode=mode, pull=pull, **kwargs)
def __getattr__(self, item):
if item != '_pin':
return getattr(self._pin, item)
def __setattr__(self, key, value):
if not hasattr(self, key) and hasattr(self._pin, key):
setattr(self._pin, key, value)
else:
super().__setattr__(key, value)
def mode(self, mode=None):
"""
Get/set pin mode (input/output) by re-initializing pin.
:param mode: Either machine.Pin.IN or machine.Pin.OUT
:return: returns the current mode (machine.Pin.IN or machine.Pin.OUT) if mode was not provided.
"""
if mode is None:
return self._mode
else:
self._pin = machine.Pin(self._id, mode=mode, pull=self._pull)
self._mode = mode
def pull(self, pull=None):
"""
Get/set pin pull-up/pull-down by re-initializing pin.
:param pull: machine.Pin.PULL_UP, machine.Pin.PULL_DOWN, None
:return: returns the current pull setting (machine.Pin.PULL_UP, machine.Pin.PULL_DOWN, None) if pull was not \
provided.
"""
if pull is None:
return self._pull
else:
self._pin = machine.Pin(self._id, mode=self._mode, pull=pull)
self._pull = pull

Related

uPY uart not communicating correctly with EG25-G

I had a motor controller connected to GP0 and GP1 so I know they work, however I cant seem to get a response from the SIM controller. Without the pico attached to the board, I can get it to work, but when I add the pico it seems like it wont send AT commands or translate received data if the pico is getting any at all. I have tried to run the code line by line in a live session and all I get is a single number that is equal to the number of letters inside the string that I am sending to the sim controller. ie uart.write(bytearray(b'ATE1\r\n')) would return >>> 6 6 being the number of characters in the code after b. I'm ordering a new pico to see if just maybe it was my sub par soldering, but in the mean time I could see if anyone more experienced than I can point out a error.
import machine
import os
import utime
import time
import binascii
from machine import UART
pwr_enable = 22 # EG25_4G Power key connected on GP22
uart_port = 0
uart_baud = 115200
# Initialize UART0
uart = machine.UART(uart_port, uart_baud)
print(os.uname())
def wait_resp_info(timeout=3000):
prvmills = utime.ticks_ms()
info = b""
while (utime.ticks_ms()-prvmills) < timeout:
if uart.any():
info = b"".join([info, uart.read(1)])
print(info.decode())
return info
def Check_and_start(): # Initialize SIM Module
while True:
uart.write(bytearray(b'ATE1\r\n'))
utime.sleep(10)
uart.write(bytearray(b'AT\r\n'))
rec_temp = wait_resp_info()
print(wait_resp_info())
print(rec_temp)
print(rec_temp.decode())
utime.sleep(10)
if 'OK' in rec_temp.decode():
print('OK response from AT command\r\n' + rec_temp.decode())
break
else:
power = machine.Pin(pwr_enable, machine.Pin.OUT)
power.value(1)
utime.sleep(2)
power.value(0)
print('No response, restarting\r\n')
utime.sleep(10)
def Network_check():# Network connectivity check
for i in range(1, 3):
if Send_command("AT+CGREG?", "0,1") == 1:
print('Connected\r\n')
break
else:
print('Device is NOT connected\r\n')
utime.sleep(2)
continue
def Str_to_hex_str(string):
str_bin = string.encode('utf-8')
return binascii.hexlify(str_bin).decode('utf-8')
Check_and_start()
Network_check()
Response is
>>> Check_and_start()
b''
b'\x00\x00'
No response, restarting
New Pico fixed my issue, I believe it to be that my inadequate soldering skills created the issue. Symptoms were, no UART data was being transmitted or received through UART pins 0 and 1. Solution was new Pico board was inserted in place of old one, same code was uploaded and ran successfully first time.

How to save edited webview result?

Situation description:
Python 3.7, GTK 3.0, PyGObjects 3.34.0 Webkit2 4.0
I have a dialog window, with GtkNotebook containing 2 tabs.
1. tab contains editable Webkit webview, the 2. tab contains textview. One of the arguments provided in class consrtructor is valid HTML snippet as string variable
What I would like to get as a result, is that any changes made in any window, are automatically reflected in other.
Current problem:
Using solution provided here, any previous changes that were made in webview are discarded upon switching the notepad tabs. Debugging shows that html obtained with aforementioned call, does not contain changes.
Any ideas what might be missing in the logic or handling itself?
For reference, the code for the dialog is as follows:
# -*- coding: utf-8 -*-
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('WebKit2', '4.0')
from gi.repository import Gtk, WebKit2
class DescriptionDialog:
def __init__(self, *args):
# GTK Builder
self._builder = args[0]
self._builder.add_from_file("UI/GUI/description.glade")
self.dialog = self._builder.get_object("descriptionDialog")
self._textView = self._builder.get_object("textview1")
self.webViewContainer = self._builder.get_object("WebViewContainer")
self.browserHolder = WebKit2.WebView()
self.browserHolder.set_editable(True)
self.webViewContainer.add(self.browserHolder)
self.browserHolder.show()
# valid html snippet, held as string
self.__buffer_orig__ = args[2]
self.buffer = args[2]
self.browserHolder.load_html(self.buffer)
self._builder.connect_signals(
{
"onDialogClose": self.onDialogClose,
"pageChangeNotebook": self.onPageChange
})
self.dialog.set_transient_for(self._builder.get_object("MainWindow"))
self.textBuffer = self._builder.get_object("textbuffer1")
self.textBuffer.set_text(self.buffer)
self.dialog.show()
def onDialogClose(self, handler):
self.dialog.hide()
def onPageChange(self, notebook=None, scrolledWindow=None, pageNumber=0):
if pageNumber == 0:
self.buffer = self.textBuffer.get_text(self.textBuffer.get_start_iter(), self.textBuffer.get_end_iter(), True)
self.browserHolder.load_html(self.buffer)
if pageNumber == 1:
self.browserHolder.get_main_resource().get_data(None, self.getDataFromResource, None)
def getDataFromResource(self, resource, result, userData=None):
# Changed html is not returned here
self.buffer = str(resource.get_data_finish(result).decode("utf-8"))
self.textBuffer.set_text(self.buffer)
For other internet users finding this thread.
Currently, at the given versions, this is the working result that I have come up with.
Main idea with this implementation is following - use the WebView enabled Javascript engine to obtain the contents of a <body> tag. Then, parse the Javascript result to use this value later on.
def onPageChange(self, notebook=None, scrolledWindow=None, pageNumber=0):
if pageNumber == 0:
self.buffer = self.textBuffer.get_text(self.textBuffer.get_start_iter(), self.textBuffer.get_end_iter(), True)
self.browserHolder.load_html(self.buffer)
if pageNumber == 1:
# use JavaScript to get the html contained in rendered body tag
script = "document.body.innerHTML;"
# Execute JavasScript via WebKit2.WebView bindings.
# Result can be obtained asynchronously, via callback method
self.browserHolder.run_javascript(script, None, self.getJSStatus, None)
def getJSStatus(self, resource, result, userData=None):
# Sample adapted and simplified from here:
# https://lazka.github.io/pgi-docs/#WebKit2-4.0/classes/WebView.html#WebKit2.WebView.run_javascript_finish
# Get the JavaScript result
data = self.browserHolder.run_javascript_finish(result)
# Get value from result, and convert it to string
self.buffer = data.get_js_value().to_string()
self.textBuffer.set_text(self.buffer)

I use celery beat worker to create new process that use billiard and set daemonic, but daemonic is not working

billiard version 3.5.0.5
celery 4.0.2
Steps to reproduce
I want control long time beat task. like if a task not finish, not run a new process.
def lock_beat_task(gap_time, flush_time):
def decorate(func):
"""
Celery timing task solves the problem that the previous task is executed again when it is not executed.
problem: Celery is similar to crontab, it will be scheduled regularly, regardless of whether the previous task is executed or not.
achieve: With the help of the cache, the key is the class name, and each time the schedule is checked, it is checked whether it is executed before, and the key is deleted after the execution.
:param func:
:return:
"""
#wraps(func)
def wrapper(*args, **kwargs):
key_name = func.__name__
logger.info('++++++++{} enter +++++++.'.format(key_name))
monitor = BeatWokerMonitor(key_name, gap_time, flush_time)
mo_process = monitor.monitor()
if mo_process:
try:
logger.info('++++++++{} is running.++++++++'.format(key_name))
func(*args, **kwargs)
logger.info('{} is graceful end.'.format(key_name))
except KeyboardInterrupt, e:
monitor.logger.info('{} KeyboardInterrupt reset succ'.format(key_name))
finally:
monitor.reset()
# mo_process.join()
else:
logger.info('{} is running or gap time is not over.'.format(key_name))
logger.info('{} is end!---.'.format(key_name))
return wrapper
return decorate
class BeatWokerMonitor(object):
"""
Used to maintain/monitor the health status of the beat workerCall beat_worker_shoud_run.
If there is no key_name in redis, or the time difference between the current time and key_name is
greater than gap_time, create a monitor daemon.
This daemon is responsible for refreshing the time in key_name at a fixed
time.Beat_worker_shoud_run returns true(should run)。 Otherwise return None
"""
def __init__(self, key_name, gap_time, flush_time):
"""
秒级时间
:param key_name:
:param gap_time:
:param flush_time:
"""
self.key_name = key_name
self.gap_time = gap_time
self.flush_time = flush_time
self.db_redis = get_redis_conn(11)
def start_monitor(self):
flush_key_process = Process(target=self.flush_redis_key_gap_time, name='{}_monitor'.format(self.key_name), daemon=True)
flush_key_process.start()
return flush_key_process
def monitor(self):
rd_key_value = self.get_float_rd_key_value()
if not rd_key_value:
v = time.time()
self.db_redis.set(self.key_name, v)
return self.start_monitor()
if time.time() - rd_key_value > self.gap_time:
return self.start_monitor()
def get_float_rd_key_value(self):
value = self.db_redis.get(self.key_name)
if value:
return float(value)
else:
return 0
def flush_redis_key_gap_time(self):
old_time = self.get_float_rd_key_value()
self.logger.info('{} start flush, now is {}'.format(self.key_name, old_time))
while 1:
if time.time() - old_time > self.flush_time:
now = time.time()
self.db_redis.set(self.key_name, now)
old_time = now
self.logger.info('{} monitor flush time {}'.format(self.key_name, now))
else:
self.logger.info('{} not flush {} , {}'.format(self.key_name, time.time() - old_time, self.flush_time))
def reset(self):
self.db_redis.delete(self.key_name)
and task code. you can write some short time task to test .
#app.task
#lock_beat_task(5*60, 10*3)
#send_update_msg("update")
def beat_update_all():
"""
:return:
"""
from crontab.update import EAllTicket
eall = EAllTicket()
send_task_nums = eall.run()
return send_task_nums
Expected behavior
want background run, so can not use multiprocessing to create child process.
use billiard instead
want beat_update_all() finished and monitor process will kill itself.
Actual behavior
beat_update_all() finished and monitor process is still running.

How can I use pyglet batches to draw scenes or levels

So I'm currently learning pyglet for Python 2.7 and I'm trying to make a simple game that has levels. The 1st 'scene' would be the title/intro part, 2nd would be a tutorial of some sort, and the rest are the game levels themselves.
For this, I've created 7 batches(1 intro, 1 tutorial, 5 levels) namely batch, batch1, ... batch6. I've also created 7 classes for each of these batches that represent the scenes/levels. This is what I've done for the intro batch and class:
batch = pyglet.graphics.Batch()
batch1 = pyglet.graphics.Batch()
class StartState:
def __init__(self):
self.welcome = pyglet.text.Label('WELCOME TO', font_name='Arial', font_size=32, color=(200,255,255,255), x=400, y=550, anchor_x='center', anchor_y='center', batch=batch)
self.title = pyglet.text.Label("MY GAME", font_name='Arial', font_size=32, color=(100,200,170,255), x=400, y=450, anchor_x='center', anchor_y='center', batch=batch)
self.press = pyglet.text.Label("press 'SPACE' to continue", font_name='Arial', font_size=32, color=(200,255,150,255), x=400, y=250, anchor_x='center', anchor_y='center', batch=batch)
def update(self, dt):
if keymap[pyglet.window.key.SPACE]:
self.welcome.delete()
self.title.delete()
self.press.delete()
states.pop()
batch1.draw()
The other scenes would also look like that. the states list is a list that I use to store my classes/scenes. states = [Level5(), Level4(), ... , TutorialState(), StartState()]. So every time the condition to advance is fulfilled, which in this class is to press 'SPACE', the window will be 'cleared' i.e. delete the sprites/labels and proceed to the next scene by using states.pop() and batch1.draw().
After I've typed these classes, I added this at the end:
#window.event
def on_draw():
window.clear()
batch.draw()
def update(dt):
if len(states):
states[-1].update(dt)
else:
pyglet.app.exit()
states.append(Level5())
states.append(Level4())
states.append(Level3())
states.append(Level2())
states.append(Level1())
states.append(TutorialState())
states.append(StartState())
pyglet.clock.schedule_interval(update, 1.0/60.0)
window.clear()
window.flip()
window.set_visible(True)
pyglet.app.run()
The problem here is that it only loads the starting batch/scene. Whenever I press 'SPACE' to go to the tutorial scene the labels/sprites of the starting batch disappear but it doesn't draw batch1 or load the the tutorial class/scene. Any suggestions?
After creating a batch for each scene class:
import pyglet
from pyglet.window import key
class SceneTemplate(object):
"""a template with common things used by every scene"""
def __init__(self, text):
self.batch = pyglet.graphics.Batch()
self.label = pyglet.text.Label(
text,
font_name='Arial', font_size=32,
color=(200, 255, 255, 255), x=32, y=704,
batch=self.batch)
# (...)
class MainMenuScene(SceneTemplate):
def __init__(self):
super(MainMenuScene, self).__init__(text='MainMenuScene')
# (...)
class IntroScene(SceneTemplate):
def __init__(self):
super(IntroScene, self).__init__(text='Introduction')
# (...)
class Level1(SceneTemplate):
def __init__(self):
super(Level1, self).__init__(text='Level 1')
# (...)
You can control the state/scene in another class, such as a window class (personally I like to subclass the pyglet window, to keep things organized and some other reasons):
class Window(pyglet.window.Window):
def __init__(self):
super(Window, self).__init__(width=1024, height=768)
self.states = [MainMenuScene(), IntroScene(), Level1()] # and so on...
self.current_state = 0 # later you change it to get the scene you want
self.set_visible()
def on_draw(self):
self.clear()
self.states[self.current_state].batch.draw()
def on_key_press(self, symbol, modifiers):
if symbol == key.SPACE:
new_state = self.current_state + 1
new_state = new_state % len(self.states)
self.current_state = new_state
# if you want each scene to handle input, you could use pyglet's push_handlers(), or even something like:
# self.states[self.current_state].on_key_press(symbol, modifiers)
# giving them access to the window instance might be needed.
if __name__ == '__main__':
window = Window()
pyglet.app.run()

howto get the selectionChanged signal

Hi I am developing a plugin for Qgis in python, I need to connect the sselectionChanged signal emitted when a feature of the layer is selected, I could not find any examples on internet, here is what I have done as far
QObject.connect(self.iface.mapCanvas(),SIGNAL("selectionChanged(QgsMapLayer)"), self.test)
on the log of qgis I get this warning
Warning: Object::connect: (receiver name: 'MainWindow')
What you have to do is to create a signal every time you select a layer:
def initGui(self):
# ... your other code here
self.handler = None
self.selected_layer = None
QObject.connect(self.iface,SIGNAL("currentLayerChanged(QgsMapLayer *)") ,self.layerChanged)
def layerChanged(self, layer):
if self.handler:
QObject.disconnect(self.selected_layer, SIGNAL("selectionChanged()"),self.select_changed)
self.handler = False
self.selected_layer = None
if layer is not None:
if layer.isValid():
QObject.connect(layer,SIGNAL("selectionChanged()"),self.select_changed)
self.selected_layer = layer
def select_changed(self):
# whatever
pass
edit: disconnect(wrong layer) fixed